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

时间:2012-12-14 11:55:56

标签: ios twisted

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

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

这是服务器的基本测试(这个问题的重要内容是基于字符串协议的基本功能)

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)作为解决方案,但我想使用自己的协议。 如果有人知道如何帮助我,我将非常感激。不管怎样,谢谢。

2 个答案:

答案 0 :(得分:2)

  

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

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

如果你两次打电话给outputStream write,一次打电话给“你好”,一次打电话给“世界”,那么完全有可能dataReceived只用“你好,世界”召唤一次。或者两次,但是“h”然后是“ello,world”。

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

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

答案 1 :(得分:0)

除了Jean-Paul Calderone的回答(确保数据通过使用select或thread完全从obj-c发送),对于协议部分,我建议使用长度前缀字符串(AKA Netstring)以便于使用情况下。

这是一个implementation。收到某些内容后,您需要拨打NSBuffer.write然后NSBuffer.extract来获取可用的字符串。