Ios tcp连接中的扭曲缓冲区已满

Ios tcp连接中的扭曲缓冲区已满,ios,twisted,Ios,Twisted,我在一个简单的twisted服务器实现中接收长数据(>1024字节)时遇到问题。 从一开始,我就在开发一个ios应用程序,它必须与twisted服务器同步。我准备以JSON格式发送信息。然后我开始在chunck中发送数据(现在命令的chunck为256bytes+4 bytes——是的,我正在实现我自己的协议)。连接正常,我在服务器中接收到这些数据包(在我自己的协议子类的dataReceived函数中)。 ios方法:NSInteger writenbytes=[self.outputStrea

我在一个简单的twisted服务器实现中接收长数据(>1024字节)时遇到问题。 从一开始,我就在开发一个ios应用程序,它必须与twisted服务器同步。我准备以JSON格式发送信息。然后我开始在chunck中发送数据(现在命令的chunck为
256bytes+4 bytes
——是的,我正在实现我自己的协议)。连接正常,我在服务器中接收到这些数据包(在我自己的协议子类的
dataReceived
函数中)。 ios方法:
NSInteger writenbytes=[self.outputStream write:[data bytes]maxLength:[data length]]
将写入的字节返回到流中。对于前4个数据包,返回的值是预期值(260字节)。如果我有更多的可用字节要发送,下次调用该方法时,它将返回0(苹果的文档中说:
“如果接收器是一个固定长度的流,并且已达到其容量,则返回0。”

因此,我推断输入缓冲区已满。我不知道如何释放缓冲区(我不知道如何到达缓冲区)。我不知道缓冲区的极限在哪里(在我看来,这几乎是荒谬的)

这是对服务器的一个基本测试(对于这个问题,使用基于字符串的基本协议是很重要的)

我看到了
LineReceiver
类,但我没有发送线路。传输的数据可能非常大(10Mb-50Mb)。我正在考虑消费者/生产者模型,或者像(AMP或PB)这样的RPC协议作为解决方案,但我想使用我自己的协议。 如果有人知道如何帮助我,我将非常感激。无论如何,谢谢你

连接正常,我在服务器中接收这些数据包(在我自己的协议子类的dataReceived函数中)

可能不会。TCP是一种“面向流”的协议。应用程序对它的使用不是以数据包为单位,而是以字节序列为单位。无法保证将使用传递给
outputStream write
的相同字符串调用
dataReceived
。如果您编写“hello,world”,则可能会用“hello,world”调用收到的数据,也可能会调用两次,先用“hello”,然后用“world”。或者它可以被称为12次:首先是“h”,然后是“e”,然后是“l”,等等

如果您调用
outputStream write
两次,一次调用“hello”,一次调用“world”,那么完全有可能
dataReceived
只调用一次“hello,world”。或者两次,但用“h”和“ello,world”

所以你发明的这个全新的协议(我看到你提到你承认你在做,但你没有解释为什么这是一个好主意或是你应用程序的一个重要部分,而不仅仅是一个潜在错误的巨大来源和对时间的糟糕利用:)必须做一些叫做“框架”的事情以便让您实际解释正在传递的字节序列。这就是为什么会有像AMP这样的协议


为了实际回答您的问题,
outputStream write
返回它实际能够缓冲发送的字节数。您必须始终检查它的返回值,并重新尝试写入它无法发送的任何字节,最好是在等待有更多缓冲区空间的通知之后。缓冲区空间在使用该空间的字节通过网络发送并由接收器确认后变为可用。这需要时间,因为网络不是即时的。关于可用缓冲区空间的通知有多种形式,其中最古老和最广泛的(但不一定是您环境中最好的)是
select(2)
系统调用。

除了Jean-Paul Calderone的回答(确保使用select或thread完全从obj-c端发送数据)之外,对于协议部分,我建议在简单用例中使用长度前缀字符串(AKA Netstring)

这是一个例子。无论何时接收到内容,都需要调用
NSBuffer.write
然后
NSBuffer.extract
以获取可用字符串

from twisted.internet.protocol import Protocol, Factory
from twisted.internet import reactor
class IphoneSync(Protocol):
    def  __init__(self):
        self.__buffer = ""

    def connectionMade(self):
        self.transport.write("0:")
        self.factory.clients.append(self)
        print "clients are ", self.factory.clients

    def connectionLost(self, reason):
        self.factory.clients.remove(self)

    def dataReceived(self, data):

        #print "data is ", data

        a = data.split(':')
        if len(a) > 1:
            command = a[0]
            content = a[1]

            msg = ""
            if command == "iam":
                #user&Pass checking
                msg = "1"


            elif command == "msg":
                self.__buffer += data

                msg = "1: continue"

            elif command == "fin":
                #procesaremos todo
                #Convertir datos en json
                #insertar/actualizar data en sqlite
                #devolver respuesta
                print "buffer is", self.__buffer
                msg = "2: procesing"

            print msg
            self.transport.write(msg)       
            #for c in self.factory.clients:
                #c.message(msg)

    def message(self, message):
        self.transport.write(message)
        #self.transport.write(message + '\n')


factory = Factory()
factory.protocol = IphoneSync
factory.clients = []
dir(factory)

reactor.listenTCP(8000, factory)
print "Iphone Chat server started"
reactor.run()