1

私はすでにソケット同期に関するこの質問を読んでいますが、まだ理解していません。

最近、TCP ソケットを介して通信が行われる比較的単純なクライアント/サーバー アプリに取り組んでいました。クライアントは C に似た関数 (特にfsockopenおよびfgetc) を使用して PHP で記述され、PHP はソケットと対話するために提供します。サーバーは、Streamデータを出力するために を使用して node.js で記述されます。

プロトコルは非常に単純で、メッセージは 0 バイト文字で終わる単なる文字列です。

基本的には次のように機能します。

SERVER: Message 1
CLIENT: Ack 1

SERVER: Message 2
CLIENT: Ack 2

....

メッセージの終わりを示す 0 バイトが検出されるまで、ソケットから char ごとに char を読み取ることによって、クライアントが一度に 1 つのメッセージを処理したため、これは実際にうまく機能しました。次に、クライアントは、メッセージを正常に受信したことをサーバーに書き戻します (これがそのAck <message id>部分です)。

今、これが起こりました:

SERVER: Message 1
CLIENT: Ack 1

SERVER: Message 2
CLIENT: Ack 2

SERVER: Message 3
        Message 4
        Message 5
        Message 6
CLIENT: <DOH!>
....

stream.write(...)つまり、サーバー上ではすべてのメッセージが単一の操作であるにもかかわらず、サーバーが予期せず 1 つの「バッチ」で複数のメッセージをクライアントに送信したことを意味します。メッセージがどこかにバッファリングされ、すぐにクライアントに送信されたようです。私のクライアントコードは、間に応答がなければソケット内の複数のメッセージを処理できAckなかったため、id 3 の後に残りのメッセージを切り捨てました。

だから私の質問は:

  • ソケットの読み取りと書き込みの同期はどの程度ですか? 上記の質問から、ソケットは基本的に 2 つの単方向パイプであることがわかりました。つまり、それらはまったく同期されていませんか?
  • いくつかのメッセージが単純な「1 つのメッセージに 1 つの ACK」の方法でクライアントに送信された後、突然複数のメッセージがストリームに書き込まれる可能性はありますか?
  • ソケットがブロッキング/ノンブロッキングの方法で開かれた場合、実際に画像が変わりますか?

PHP 5.4とノード0.6.xを使用して、これをUbuntu VMでテストしました(負荷がないか、奇妙な動作を引き起こす可能性があるものはありません)。

4

2 に答える 2

3

TCP は双方向ストリームの抽象化であるため、メッセージの概念がなく、メッセージの境界を保持できません。複数の send() または recv() 呼び出しが TCP パケットにどのようにマップされるかは保証されません。send() を複数回呼び出すことは、すべてのデータを連結して 1 回呼び出すことと同等であるかのように扱う必要があります。さらに重要なことは、受信時に、受信データが個々の recv() 呼び出しでどのように分割されたかに関係なく、コードが受信データをまったく同じように解釈することを確認する必要があることです。

正しく受信するには、不完全なメッセージを保存するバッファを使用できます。ただし、バッファーに不完全なメッセージがある場合は、次の recv() 呼び出しで現在のメッセージが完了し、0 個以上の完全なメッセージが提供され、別の不完全なメッセージの一部が提供される可能性があることに注意してください。

ブロッキング モードまたは非ブロッキング モードは、ここでは何も変更しません。それは、アプリケーションが OS とやり取りする方法だけです。

于 2012-05-19T13:27:56.293 に答える
0

対処する同期の概念が 2 つあります。

  1. send()orの(一般に)同期操作recv()
  2. 一方のプロセスがメッセージを送信する非同期の方法と、もう一方のプロセスがメッセージを処理する方法。

可能であれば、クライアントとサーバーを互いにプロセス同期の「ロック ステップ」に保つ設計を避けるようにしてください。それはトラブルを求めています。プロセスの 1 つが予期せず終了した場合はどうなりますか? recv()他のプロセス/スレッドは、決して来ない上でハングする可能性があります。各メッセージが最終的に確認されることを設計が期待することと、1 つのメッセージしか送信できず、別のメッセージを送信する前に確認する必要があることを設計が期待することは、まったく別のことです。

このことを考慮:

Server: send 1
Client: ack 1
Server: send 2
Server: send 3
Client: ack 2
Server: send 4
Client: ack 3
Client: ack 4

この状況に対応できる設計は、次のことを期待するものよりも優れています。

Server: send 1
Client: ack 1
Server: send 2
Client: ack 2
Server: send 3
Client: ack 3
Server: send 4
Client: ack 4
于 2013-07-09T22:31:09.750 に答える