2017-09-07 81 views
0

epollを使ってすべてのクライアントイベントを監視するTCPソケット通信を実装します。すべてのソケットは非ブロッキングです。recv bufがすでにデータを持っているときに、tcp socket recvは "resource temporarily unavailable"を返します。

私はちょうどクライアントがMTU以上のデータを送信すると、いくつかのフラグメントパケットを意味し、サーバは常にすべてのデータを完全に読み取ることができません。 以下のように、私は頭を先に読んで、頭から頭を出してから頭を読んだ後、頭を読む。

問題は、pdu recv()と密接に従っていますが、常にEAGAINを数回返します。私の再試行は中断します。 サーバは何千ものクライアントイベントを処理する必要があるので、リトライを常に続行させることは許容されていません。

私はtcpdumpを使用してクライアントからのパケットをキャプチャしますが、すべてのパケットは最大1448バイトのデータですが、ヘッドは5バイトしかないので、ヘッドを正常に読み取ることができますが、次のデータrecv()可能なrecv EAGAINは、データがすでにrecvバッファに到着したときに返すことができますか?私の意見では、最初の5バイトを読み取ることができるので、recvバッファで読み取るデータが増える必要があります。

は、おそらくtcp/ipスタックのアセンブルプロセスに関連しています。 コードは以下の通りです。すべてのrecduは、10回以上再試行する必要があります。 recvできれば

... 
#define HDR_LEN 5 
n = epoll(epfd, events, 1000, -1) 
for(i =0; i < n; i++) 
{ 
    uint8 pHdr[HDR_LEN] = {0}; 
    uint16 pdulen = 0, offset =0; 
    infd = events[i].fd; 
    nRead = recv(infd, pHdr, HDR_LEN); // read the data head first 
    pdulen = ntohs(*(uint16 *)(pHdr+2)); // get the pdu len from the head 
    uint8 *pbuf = malloc(pdulen+HDR_LEN); 

    memcpy(pbuf, pHdr, HDR_LEN);   // move the head to buf 
    while(offset != pdulen)     // then read the pdu data 
    { 
     nRead = recv(infd, pbuf+HDR_LEN+offset, pdulen-offset); 
     if (nRead <=0) 
     { 
      if (nRead == -1 && errno == EAGAIN) // resource temporarily unavailable 
      { 
       if (retry < 5) 
       { 
        usleep(500); 
        retry++; 
        continue; 
       } 
       else 
        break; // already try 5 times, should always continue? 
      } 
      else 
       break; 
     } 
     else 
     { 
      offset += nRead; 
      retry = 0; 
     } 
    } 
    if (offset == pdulen) 
     process(pbuf, pdulen+HDR_LEN); // process the complete data 
    ... 
} 
... 
+0

いくつかの助けを借りてこの問題を解決してください! – jackxie

+1

あなたのソケットはノンブロッキングモードですか?もしそうであれば、EAGAINは受信バッファに残っているデータがなくなるたびに取得されるべきである。複数のソケットのノンブロッキングI/Oを同時に処理するには、パーシャルレスポンスを受信した後に通常のpoll()コールに戻るようにステートマシンを実装する必要があります。それからpoll()があなたのソケットで読むデータがもっとあることを示したら、ソケットから追加のデータを戻してrecv()し、以前ソケットから取得したデータに追加しますあなたはPDU全体を持っています。 –

+0

'recv bufに既にデータがある場合、tcp socket recvは "リソースを一時的に利用できません"を返しますか?いいえ。 – EJP

答えて

0

epollはかつて、ブロックせずにあなたを教えてくれます。 recvがソケットからすべてのデータを消費する場合、次のrecvはデータがなくなるまでブロックし、EAGAIN(ノンブロッキングソケットの場合)を返します。ソケットが読み取ることができたときに検出する

  1. 使用select/poll/epoll

    共通パターンがにあります。

  2. 準備完了ソケットでrecvを1回呼び出し、受信したデータをバッファに追加します。
  3. バッファに処理のための十分なデータが含まれているかどうかを確認します。はいの場合は、処理してください。そうでなければ、select/poll/epollにもっと読むことができるように指示してください。
関連する問題