2016-03-21 16 views
0

geventを使用して着信接続を受け付け、接続ごとのグリーンレットを使用してデータを返す小さなHTTPサーバーがあります。 (ローカル)クライアントは、サーバー側がクライアントに書き込み死ぬとソケットがCLOSE_WAIT状態にあるにもかかわらず、成功する:今すぐgevent tcpソケットは切断されていますが、データを送信することができます

$ ls -l /proc/21860/fd |grep 22 
lrwx------. 1 mathieu mathieu 64 Mar 21 19:55 22 -> socket:[187093] 
$ lsof |grep 187093 
python 21860  mathieu 22u  IPv4    187093  0t0  TCP localhost.localdomain:36072->localhost.localdomain:48908 (CLOSE_WAIT) 

、私はgevent.socket.socketで作成したソケットのsendメソッドを期待します例外と一緒に失敗するが、私は誰も得られない!

def send(socket, data): 
    sent = socket.send(data) 
    while sent != len(data): 
     data = data[sent:] 
     sent = socket.send(data) 

私の期待は間違っていますか?そうでない場合は、ここで何がうまくいかないでしょうか?

答えて

0

少しのデバッグの後、ソケットAPIがTCPの上でどのように動作するかについての私の期待は間違っていました。潜在的な読者は、奪うように慎重にTCP option SO_LINGER (zero) - when it's required

物事を参照することもできます()

  1. クライアント側近くには大体「私はあなたにデータを送信し終わっています」という意味のサーバにFINを送信します。これは、サーバーが引き続きデータを返送できる可能性があることを意味します。
  2. サーバーがクライアント側のクローズ後に書き込みを試みると、書き込みは成功し(ユーザー領域からカーネル空間にコピーされたバイト数が返されます)、データはクライアントに送信され、クライアントはそのソケットまだTIMEWAIT状態になっています(SO_LINGERゼロでこれを無効にしない限り、SO_LINGERをゼロに設定したくないのでなければ)、サーバソケットの状態はCLOSEDに更新されます。
  3. クライアントからRSTを受信した後にサーバーが2回目の書き込みを試みると、書き込みは失敗します。
  4. クライアント側クローズ後にサーバーがrecvを試行する場合、recvはストリームの終わりを示すためにゼロを返します。

これを要約すると、私のサーバーは、クライアントが接続を閉じてそれに応じて動作することを示す記号としてrecv()== 0として返されたストリーム終了通知を使用する必要があることを意味します。関連するソケットを閉じます)。

関連する問題