在tcp连接中完全扭曲的缓冲区

我有一个简单的扭曲的服务器实现中接收长数据(> 1024bytes)的问题。 从一开始,我正在开发一个必须与扭曲的服务器同步的ios应用程序。 我准备的信息以JSON格式发送。 然后我开始发送这些数据块(现在是256bytes + 4 bytes的命令 – 是的,我正在执行我自己的协议)。 连接是好的,我收到我的服务器中的数据dataReceived (在我自己的协议子类的dataReceived函数中)。 ios方法: NSInteger writtenBytes =[self.outputStream write:[data bytes] maxLength:[data length]]将写入的字节返回到stream中。 对于前4个数据包,返回值是预期的(260字节)。 如果我有更多可用的字节发送,下一次我调用该方法,它将返回0(苹果文档说: "If the receiver is a fixed-length stream and has reached its capacity, 0 is returned." )。

所以我推断input缓冲区已满。 我不知道如何释放缓冲区(我不知道如何到达缓冲区)。 我不知道缓冲区的限制在哪里(在我看来,这几乎是荒谬的)。

这是服务器的基本testing(对于基本的string协议,这个问题的重要的东西)

 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() 

我看到了LineReceiver类,但是我没有发送线路。 传输的数据可能非常大(10Mb-50Mb)。 我正在考虑消费者/生产者模型,或RPC协议(AMP或PB)作为解决scheme,但我想用自己的协议工作。 如果有人知道如何帮助我,我会非常感激。 不pipe怎么说,还是要谢谢你。

连接是好的,我收到我的服务器中的数据包(在我自己的协议子类的dataReceived函数中)。

可能不会。 TCP是一个“面向stream”的协议。 您的应用程序使用它不是在数据包方面,而是在一个字节序列方面。 无法保证dataReceived将被传递给outputStream write的相同string调用。 如果你写“你好,世界”, dataReceived可能会被称为“你好,世界” – 或者它可能被称为两次,首先与“你好”,然后与“世界”。 或者它可能被称为12次:首先是“h”,然后是“e”,然后是“l”等。

如果你调用outputStream write两次,一次用“hello”,一次用“world”,那么完全有可能dataReceived只会用“hello,world”调用一次。 或者也许两次,但是用“h”然后“ello,世界”。

因此,这个全新的协议,你发明(我看到你提到你认识到你在做,但你没有解释为什么这是一个好主意或应用程序的重要组成部分,而不是只是一个潜在的错误的大量来源和时间的使用很less:)必须做一些所谓的“成帧”,以便让你真正解释被传递的字节序列。 这就是为什么有像AMP这样的协议。

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

除了Jean-Paul Calderone的答案(确保数据是通过使用select或线程完全从obj-c端发送的),对于协议部分,我build议使用带长度前缀的string(AKA Netstring)作为简单用例。

这是一个实现 。 每当有东西被收到,你需要调用NSBuffer.write然后NSBuffer.extract获得可用的string。

Interesting Posts