0

次のような状況があります。私のサーバーは、リモート サーバー (fd_server) からデータを受信し、それをクライアント (fd_client) に転送します。複数のクライアントと複数のサーバー接続を処理できるように、エッジ トリガーの epoll を使用しています。

手順:

  1. クライアントがサーバーに接続します。
  2. 私のサーバーはリモート サーバーに接続し、データを要求します。
  3. リモートサーバーが応答し、サーバーがデータをクライアントに転送します。

詳細:

サーバーがリモート サーバーに接続した後、fd_server が EPOLLIN フラグを使用して epoll コントロールに追加されます。サーバーはイベントを待機します。

epoll_wait が fd_server を読み取り可能として返すと、次のループに進みます。

いくつかの読み取り/書き込みの後、sctp_sendmsg が EAGAIN を返します。これは、sctp 送信バッファーがいっぱいであることを意味します。fd_server ソケットから既に読み取ったデータを失うことなく、この状況を処理するにはどうすればよいですか?

どのくらいのデータを送信できるかを事前に知る方法があるので、適切な量だけを読み取ることができますか?

while(1){
    N = recv(fd_server,buf, sizeof buf,0);
    if (N == -1){
      /* If errno == EAGAIN, that means we have read all
         data. So go back to the main loop. */
      if (errno != EAGAIN){
          perror ("tcp_recv error");

        }
      break;
    }
    if(N == 0){
      /* End of file. The remote has closed the
         connection. */
         close(fd_server);      
         break;
    }
    pos = 0;
    while(pos < N){
        got = sctp_sendmsg(fd_client, &buf[pos], N-pos, to, tolen, 0, 0, stream, 0, 0);

        if(got<=0){
            if (errno == EAGAIN){
                //what to do?
            }else{
                perror("tcp to sctp send error");
            }
        }
        else{
        pos += got;}
    }
}
4

1 に答える 1

0

いくつかの読み取り/書き込みの後、sctp_sendmsg が EAGAIN を返します。これは、sctp 送信バッファーがいっぱいであることを意味します。fd_server ソケットから既に読み取ったデータを失うことなく、この状況を処理するにはどうすればよいですか?

fd_client ソケットごとに、ある種の「コンテキスト」(データ構造) を保持する必要があります。サーバーに接続される新しいクライアント ソケットごとに、「接続状態」構造体のインスタンスを作成し、それをハッシュ テーブルに格納します。これは次のようになります。

struct ConnectionState
{
    int fd_client; // socket
    uint8_t buffer[MAX_CHUNK_SIZE];  // protocol buffer for this connection
    int buffer_length; // how many bytes received into this buffer
    int pos;           // how many bytes transmitted back out on fd_client from "buffer"
    int has_data;      // boolean to indicate protocol state (1 if there's still data in buffer to send)
};

すべてを一度に送信できない場合は、epoll モードで fd_client ソケットを EPOLLIN から EPOLLOUT に切り替えます。ConnectionState 構造体で「has_data」を true に変更します。次に、ソケット イベントの待機に戻ります。再度送信できるようになったら、そのソケットの ConnectionState 構造体を調べて、引き続き送信する必要があるか、新しいバッファーを受信する必要があるかを判断します。

エッジ トリガー ソケットには注意してください。EPOLLOUT から EPOLLIN に移行する場合は、データを失わないようにするために、先に進んで recv() を再度実行する必要があります。(同様に、送信状態に入るには、最初の送信を試みます)。

于 2013-01-22T10:58:48.997 に答える