0

フォワードプロキシを書きました。WindowsとLinuxの両方に使用します。OSごとに変更が必要です。ただし、いくつかの昇給条件が見られます。ほとんどの場合、最後のパケット (FIN 信号) を推測する際の私の誤解によるものだと思います。現在、ソケットのセットを選択しています。どちらのソケットが通知されても、read() を実行します。read が 0 を返す場合、それは FIN パケットであると想定し、そのソケットを閉じます。私の read() がゼロ以外の値を与えることはありえますか。しかし、そのパケットにはFINが含まれています(発生する可能性があると思います)。そのため、いくつかのソケットは閉じられていますが、閉じません。プロキシがどのソケットが閉じられたかを検出する方法がわかりません。または、確立された接続の最後のパケットです。

私のコードは次のようになります。

クライアントから受け入れた 100 個の fds があります。それらを配列に保存しますsock_array[total_size]

select(copy_of_sock_array,timeout)                                                          
for(int cnt=0;cnt<total_size;cnt++)                                                          
{                                                                                            
   if(FD_ISSET(sock_array[cnt],sock_array))                                                  
   {
            ret = recv(sock_array[cnt],buffer,len);                                          
            if(ret<=0){                                                                      
                /*This must be a FIN packet */                                               
                /* Close corresponding socket which is opened with outer world */            
                close(/*corresponding socket*/);                                                                      
            }                                                                                  
   }                                                                                          
}                                                                                                

これは大丈夫に見えますか?

ありがとう

4

2 に答える 2

1

非ブロッキング読み取りを実行し、読み取りを停止する必要があることを示す戻り値を取得するまで、ソケットからの読み取りを続ける必要があります。

ssize_t r = 0;
for (;;) {
    r = recv(sock, buf, bufsz, MSG_DONTWAIT);
    if (r <= 0) {
        if (r < 0 && errno == EINTR) {
            continue;
        }
        break;
    }
    /* ... handle data in buf .. */
}
if (r < 0) {
    if (errno == EAGAIN) {
        /* ... wait in select again ... */
    } else {
        /* ... handle error ... */
    }
} else {
    /* got FIN */
}

FIN を受信したからといって、必ずしも接続を閉じる必要があるわけではないことに注意してください。FIN は、これ以上データが送信されないことを示しているだけですが、ピアはまだデータを受け入れようとしている可能性があります。これは、クライアントが単一の応答のみを必要とする HTTP で発生する可能性があるため、要求の後に FIN を配信します。ただし、それでも応答を受信することを期待しています。

プロキシには、sock1 と sock2 などの 2 つのソケットがある可能性があります。したがって、sock1 での FIN の受信は、sock2 でキューに入れられたデータが配信された後に、この指示が sock2 に転送されることを意味する必要があります (ミラーも同様です)。を使用して FIN を転送できますshutdown

shutdown(sock2, SHUT_WR);

sock1 と sock2 の両方から FIN を受信した場合はclose、両方のソケットで呼び出すことができます。

だからあなたの質問に対処します。

私の read() がゼロ以外の値を与えることはありえますか。しかし、そのパケットにはFINが含まれています(発生する可能性があると思います)。

はい、これは起こるかもしれません。これが、停止の指示が出るまで読み続ける理由です。技術的には、そうする必要はありません。接続ごとの公平性の問題がある場合は、他の接続を処理するまで延期できます。ただし、選択待機に入る前に、戻って読み終え​​る必要があります。

そのため、いくつかのソケットは閉じられていますが、閉じません。プロキシがどのソケットが閉じられたかを検出する方法がわかりません。または、確立された接続の最後のパケットです。

説明したように、(透過的な) プロキシとして、ソケットに FIN を転送し、FIN を受信すると、ソケットを安全に閉じることができます。透過的なプロキシでない場合は、別のルール セットでプレイします。その場合、実際にはクライアントのサーバーになるからです。したがって、実装しているアプリケーション プロトコルで許可されている場合はいつでも、ソケットを閉じることができます。

于 2012-08-10T21:45:42.237 に答える
0

ソケットの動作は明確に定義されています。データを受信し、その後接続が閉じられた場合は、2つのread()が必要になります。1つ目はデータを返し、2つ目は0を返し、接続の終了を通知します。

syscallが0を返すまで、常に読む必要があります。

そして、これを検出するためにノンブロッキング読み取りは必要ありません!

于 2012-08-10T22:30:53.567 に答える