3

単純なツイスト サーバー実装で長いデータ (>1024 バイト) を受信する際に問題があります。最初から、ねじれたサーバーと同期する必要がある ios アプリを開発しています。送信する情報を JSON 形式で準備します。次に、そのデータをチャンクで送信し始めます (現在256bytes + 4 bytes、コマンドのチャンクで - はい、独自のプロトコルを実装しています)。接続は問題なく、サーバーでこれらのパケットを受信します (dataReceived自分の Protocol サブクラスの機能で)。ios メソッド:NSInteger writtenBytes =[self.outputStream write:[data bytes] maxLength:[data length]]書き込まれたバイトをストリームに返します。最初の 4 パケットの場合、返される値は期待値 (260 バイト) です。送信できるバイト数がさらにある場合は、次にそのメソッドを呼び出したときに 0 が返されます (Apple のドキュメントによると: "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

接続は問題なく、サーバーでこれらのパケットを受信します (独自の Protocol サブクラスの dataReceived 関数で)。

おそらくそうではありません。TCP は「ストリーム指向」のプロトコルです。アプリケーションでの使用は、パケットに関してではなく、一連のバイトに関してです。dataReceivedに渡したのと同じ文字列で が呼び出されるという保証はまったくありませんoutputStream write。"hello, world" と書くdataReceivedと、"hello, world" で呼び出される場合があります。または、最初に "hello" で、次に "world" で 2 回呼び出される場合もあります。または、最初に "h"、次に "e"、次に "l" のように 12 回呼び出すこともできます。

outputStream writeまた、「hello」で 1 回、「world」で 1 回、2 回呼び出した場合、 dataReceived「hello, world」で 1 回だけ呼び出される可能性は十分にあります。または、おそらく 2 回ですが、"h" の後に "ello, world" が続きます。

つまり、あなたが発明しているこの真新しいプロトコル (あなたは自分が行っていることを認識していると言いましたが、潜在的なバグの大きな原因ではなく、なぜこれが良いアイデアなのか、アプリケーションの重要な部分なのかを説明していませんでした。そして、時間の使い方が悪い:)渡されるバイトシーケンスを実際に解釈できるようにするために、「フレーミング」と呼ばれる何かを行う必要があります。これが、AMP のようなプロトコルがある理由です。

実際に質問に答えるためにoutputStream write、送信のために実際にバッファリングできたバイト数を返します。常に戻り値を確認し、送信できなかったバイトを再度書き込む必要があります。できれば、バッファ スペースに余裕があるという通知を待ってから行ってください。バッファ スペースは、そのスペースを使用するバイトがネットワーク経由で送信され、受信者によって確認された後に使用可能になります。ネットワークは瞬間的ではないため、これには時間がかかります。使用可能なバッファ スペースに関する通知にはさまざまな形式がありますが、その中で最も古く、最も広まっているのは (ただし、環境内で必ずしも最適であるとは限りません)、select(2)システム コールです。

于 2012-12-14T16:03:18.463 に答える
0

Jean-Paul Calderone の回答 (select または thread を使用して obj-c 側からデータが完全に送信されるようにする) に加えて、プロトコル部分については、単純なユースケースに長さのプレフィックス付き文字列 (AKA Netstring) を使用することをお勧めします。

これが実装です。何かを受信するたびに、NSBuffer.write次に呼び出しNSBuffer.extractて、利用可能な文字列を取得する必要があります。

于 2013-01-09T02:15:00.740 に答える