epoll을 사용하여 모든 클라이언트 이벤트를 모니터하는 TCP 소켓 통신을 구현합니다. 하나의 스레드 만 for 루프의 모든 클라이언트를 처리합니다. 모든 소켓은 비 블로킹입니다.tcp 소켓 recv는 recv buf가 이미 데이터를 가지고있을 때 "리소스를 일시적으로 사용할 수 없음"을 리턴합니다.
지금은 클라이언트가 MTU 이상으로 데이터를 보내면 여러 조각 패킷을 의미하므로 서버는 항상 모든 데이터를 완전히 읽을 수 없습니다. 아래처럼, 나는 머리를 먼저 읽고 머리에서 pdu len을 얻은 다음 pdu 부분을 읽는다.
문제는 내가 머리를 성공적으로 pdu recv()와 밀접하게 읽었지 만 항상 EAGAIN을 여러 번 반환합니다. 재 시도가 중단됩니다. 서버는 수천 개의 클라이언트 이벤트를 처리해야하기 때문에 재 시도를 항상 계속할 수있는 훌륭한 성능을 소비한다고 생각합니다.
모든 패킷이 최대 1448 바이트의 데이터 조각인데 tcpdump를 사용하지만 헤드가 5 바이트 밖에 없으므로 헤드를 읽을 수있는 이유는 무엇입니까? 그러나 다음 데이터 recv() 작업은 EAGAIN을 반환합니까? recv 버퍼에 데이터가 이미 도착했을 때 EAGAIN을 반환 할 수 있습니까? 필자는 처음 5 바이트를 읽을 수 있으므로 recv 버퍼에서 읽을 데이터가 더 있어야합니다.
은 tcp/ip 스택의 어셈블 과정과 관련이 있습니다. 코드는 아래와 같습니다. 모든 pdu recv는 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