Programing

소켓 라이브러리에서 recv를 호출 할 때 recv 버퍼의 크기는 얼마입니까?

crosscheck 2020. 7. 7. 07:47
반응형

소켓 라이브러리에서 recv를 호출 할 때 recv 버퍼의 크기는 얼마입니까?


C의 소켓 라이브러리에 대한 몇 가지 질문이 있습니다. 다음은 내 질문에서 참조 할 코드 스 니펫입니다.

char recv_buffer[3000];
recv(socket, recv_buffer, 3000, 0);
  1. recv_buffer를 얼마나 크게 만들 수 있습니까? 3000을 사용하고 있지만 임의적입니다.
  2. recv()버퍼보다 큰 패킷을 받으면 어떻게됩니까 ?
  3. recv를 다시 호출하지 않고 전체 메시지를 받았는지, 수신 할 것이 없을 때 영원히 기다리도록하려면 어떻게해야합니까?
  4. 공간이 부족할 염려없이 버퍼에 계속 추가 할 수 있도록 고정 된 양의 공간이없는 버퍼를 만들 수있는 방법이 있습니까? 아마도 버퍼에 strcat대한 최신 recv()응답 을 연결하는 데 사용 합니까?

한 번에 많은 질문이 있다는 것을 알고 있지만 모든 답변에 크게 감사드립니다.


이러한 질문에 대한 답변은 TCP / IP 내 에서 스트림 소켓 ( SOCK_STREAM) 또는 데이터 그램 소켓 ( SOCK_DGRAM)을 사용하는지에 따라 달라지며 , 전자는 TCP에 해당하고 후자는 UDP에 해당합니다.

버퍼가 얼마나 크게 전달되는지 어떻게 알 수 recv()있습니까?

  • SOCK_STREAM: 너무 중요하지 않습니다. 당신의 프로토콜이 트랜잭션 / 대화 형 프로토콜이라면, 당신이 기대할 수있는 가장 큰 개별 메시지 / 명령을 담을 수있는 크기를 선택하십시오 (3000은 괜찮을 것입니다). 프로토콜이 대량 데이터를 전송하는 경우 더 큰 버퍼가 더 효율적일 수 있습니다. 일반적으로 소켓의 커널 수신 버퍼 크기와 비슷합니다 (종종 256kB 정도).

  • SOCK_DGRAM: 응용 프로그램 레벨 프로토콜이 전송하는 가장 큰 패킷을 보유 할 수있을만큼 큰 버퍼를 사용하십시오. UDP를 사용하는 경우 일반적으로 응용 프로그램 수준 프로토콜은 약 1400 바이트보다 큰 패킷을 보내지 않아야합니다. 패킷은 반드시 조각화하고 다시 어셈블해야하기 때문입니다.

recv버퍼보다 큰 패킷을 가져 오면 어떻게됩니까 ?

  • SOCK_STREAM: 스트림 소켓에는 패킷 개념이 없으므로 연속 바이트 스트림이기 때문에 질문은 실제로 의미가 없습니다. 버퍼에 여유 공간이있는 것보다 읽을 수있는 바이트가 더 많으면 OS에 의해 큐에 대기하고 다음에 호출 할 수 recv있습니다.

  • SOCK_DGRAM: 초과 바이트가 삭제됩니다.

전체 메시지를 받았는지 어떻게 알 수 있습니까?

  • SOCK_STREAM: 애플리케이션 레벨 프로토콜에 메시지 끝을 판별하는 방법을 빌드해야합니다. 일반적으로 길이 접두사 (메시지 길이로 각 메시지를 시작) 또는 메시지 끝 구분 기호 (예 : 텍스트 기반 프로토콜의 줄 바꿈) 일 수 있습니다. 덜 사용되는 세 번째 옵션은 각 메시지에 대해 고정 된 크기를 요구하는 것입니다. 이러한 옵션의 조합도 가능합니다 (예 : 길이 값을 포함하는 고정 크기 헤더).

  • SOCK_DGRAM: 단일 recv호출은 항상 단일 데이터 그램을 반환합니다.

고정 된 공간을 가지지 않고 버퍼를 만들 수있는 방법이 있습니까? 그래서 공간이 부족할 염려없이 계속 추가 할 수 있습니까?

그러나 버퍼를 사용하여 버퍼 크기를 조정할 수 있습니다 realloc()(원래 malloc()또는로 할당 된 경우 calloc()).


TCP와 같은 스트리밍 프로토콜의 경우 거의 모든 크기로 버퍼를 설정할 수 있습니다. 즉, 4096 또는 8192와 같이 2의 거듭 제곱 인 공통 값이 권장됩니다.

더 많은 데이터가 있다면 버퍼가 무엇인지, 다음에 호출 할 때 커널에 저장됩니다 recv.

예, 버퍼를 계속 키울 수 있습니다. offset idx에서 시작하여 버퍼 중간에 recv를 수행 할 수 있습니다 .

recv(socket, recv_buffer + idx, recv_buffer_size - idx, 0);

SOCK_STREAM소켓 이 있으면 recv스트림에서 "처음 3000 바이트까지"를 가져옵니다. 얼마나 큰 버퍼를 만드는지에 대한 명확한 지침은 없습니다.

당신이있는 경우 SOCK_DGRAM소켓을, 그리고 데이터 그램 버퍼보다 큰 경우, recv데이터 그램의 첫 부분, -1을 반환로 버퍼를 채우고 세트 EMSGSIZE에 errno를. 불행히도, 프로토콜이 UDP 인 경우, 이는 UDP가 신뢰할 수없는 프로토콜 이라고 불리는 이유 중 일부인 데이터 그램이 손실됨을 의미합니다. 후자를 잘 알고 있음에도 불구하고 TCP / IP 제품군에서 이름을 하나 ;-).

버퍼를 동적으로 늘리려면 처음에 버퍼를 할당하고 필요에 따라 malloc사용하십시오 realloc. 그러나 그것은 recvUDP 소스에서 도움이되지 않습니다 .


들어 SOCK_STREAM그냥 기다리고 바이트의 일부를 당기는 당신은 다음의 호출에 더 검색 할 수 있기 때문에 소켓 버퍼 크기는별로 중요하지 않습니다. 당신이 감당할 수있는 버퍼 크기를 선택하십시오.

들어 SOCK_DGRAM소켓, 당신은 대기 메시지의 피팅 부분을 얻을 것이다 나머지는 삭제됩니다. 다음 ioctl을 사용하여 대기 데이터 그램 크기를 얻을 수 있습니다.

#include <sys/ioctl.h>
int size;
ioctl(sockfd, FIONREAD, &size);

또는 호출 MSG_PEEKMSG_TRUNC플래그 recv()를 사용하여 대기 데이터 그램 크기를 얻을 수 있습니다.

ssize_t size = recv(sockfd, buf, len, MSG_PEEK | MSG_TRUNC);

MSG_PEEK대기 메시지를 엿볼 필요 가 있습니다.-recv는 잘리지 않은 실제 크기를 반환합니다. MSG_TRUNC현재 버퍼를 오버플로하지 않아도 됩니다.

그런 다음 malloc(size)실제 버퍼와 recv()데이터 그램 만 가능합니다.


기술은 항상 구현에 따라 달라지기 때문에 귀하의 질문에 대한 절대 대답은 없습니다. 들어오는 버퍼 크기가 TCP 통신에 문제를 일으키지 않기 때문에 UDP로 통신한다고 가정합니다.

RFC 768 에 따르면 UDP의 패킷 크기 (헤더 포함)는 8 ~ 65515 바이트 범위 일 수 있습니다. 따라서 수신 버퍼의 내결함성 크기는 65507 바이트 (~ 64KB)입니다.

그러나 네트워크 장치가 모든 대형 패킷을 올바르게 라우팅 할 수있는 것은 아닙니다. 자세한 내용은 기존 설명을 참조하십시오.

최대 처리량을위한 최적의 UDP 패킷 크기는 얼마입니까?
인터넷에서 가장 큰 안전한 UDP 패킷 크기는 무엇입니까


16kb는 옳습니다. 기가비트 이더넷을 사용하는 경우 각 패킷의 크기는 9kb 일 수 있습니다.

참고 : https://stackoverflow.com/questions/2862071/how-large-should-my-recv-buffer-be-when-calling-recv-in-the-socket-library

반응형