3

我在一个简单的扭曲服务器实现中接收长数据(> 1024 字节)时遇到问题。从一开始,我正在开发一个必须与扭曲服务器同步的 ios 应用程序。我准备要以 JSON 格式发送的信息。然后我开始以块的形式发送该数据(现在以块的形式发送256bytes + 4 bytes命令 - 是的,我正在实现自己的协议)。连接正常,我在我的服务器中收到了这些数据包(在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)。我正在考虑消费者/生产者模型,或像(AMP 或 PB)这样的 RPC 协议作为解决方案,但我想使用我自己的协议。如果有人知道如何帮助我,我将不胜感激。不管怎么说,还是要谢谢你。

4

2 回答 2

2

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

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

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

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

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

于 2012-12-14T16:03:18.463 回答
0

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

这是一个实现。每当收到某些内容时,您都需要调用NSBuffer.writethenNSBuffer.extract以获取可用的字符串。

于 2013-01-09T02:15:00.740 回答