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
...
}
...
いくつかの助けを借りてこの問題を解決してください! – jackxie
あなたのソケットはノンブロッキングモードですか?もしそうであれば、EAGAINは受信バッファに残っているデータがなくなるたびに取得されるべきである。複数のソケットのノンブロッキングI/Oを同時に処理するには、パーシャルレスポンスを受信した後に通常のpoll()コールに戻るようにステートマシンを実装する必要があります。それからpoll()があなたのソケットで読むデータがもっとあることを示したら、ソケットから追加のデータを戻してrecv()し、以前ソケットから取得したデータに追加しますあなたはPDU全体を持っています。 –
'recv bufに既にデータがある場合、tcp socket recvは "リソースを一時的に利用できません"を返しますか?いいえ。 – EJP