programing

소켓 라이브러리에서 recv를 호출할 때 사용하는 recv 버퍼 크기

newsource 2022. 8. 11. 22:58

소켓 라이브러리에서 recv를 호출할 때 사용하는 recv 버퍼 크기

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

char recv_buffer[3000];
recv(socket, recv_buffer, 3000, 0);
  1. recv_buffer 크기를 결정하려면 어떻게 해야 하나요?3000을 사용하고 있지만 임의입니다.
  2. 만약의 경우recv()내 버퍼보다 큰 패킷을 수신할 수 있습니까?
  3. recv에 다시 전화하지 않고 전체 메시지를 받았는지 확인하고 수신할 것이 없을 때 메시지를 영원히 기다려야 하는지 어떻게 알 수 있습니까?
  4. 버퍼에 일정한 공간을 갖지 않고 공간이 부족해질 염려 없이 버퍼를 계속 추가할 수 있는 방법이 있을까요?strcat최신 정보를 연결하다recv()버퍼에 대한 반응?

많은 질문들이 한꺼번에 쏟아지는 건 알지만 어떤 답변이라도 답변해주시면 감사하겠습니다.

이러한 질문에 대한 답변은 스트림소켓 사용 여부에 따라 달라집니다.SOCK_STREAM또는 데이터그램 소켓(SOCK_DGRAM): TCP/IP 에서는, 전자는 TCP 에 대응해, 후자는 UDP 에 대응합니다.

버퍼 크기를 어떻게 알 수 있습니까?recv()?

  • SOCK_STREAM별로 중요하지 않아요.프로토콜이 트랜잭션/인터랙티브 프로토콜인 경우, 합리적으로 예상할 수 있는 가장 큰 개별 메시지/명령어를 저장할 수 있는 크기를 선택하십시오(3000개면 충분합니다).프로토콜이 대량 데이터를 전송하는 경우 더 큰 버퍼가 더 효율적일 수 있습니다. 좋은 경험적 규칙은 소켓의 커널 수신 버퍼 크기(대개 약 256kB)와 비슷합니다.

  • SOCK_DGRAM: 어플리케이션레벨의 프로토콜이 송신한 패킷 중 가장 큰 패킷을 저장할 수 있는 버퍼를 사용합니다.UDP를 사용하는 경우 일반적으로 애플리케이션 수준 프로토콜이 약 1400바이트보다 큰 패킷을 전송해서는 안 됩니다. 이러한 패킷은 조각화하고 재구성해야 하기 때문입니다.

만약의 경우recv버퍼보다 큰 패킷을 얻을 수 있을까요?

  • SOCK_STREAM: 스트림 소켓에는 패킷의 개념이 없기 때문에 이 질문은 사실 이치에 맞지 않습니다.그것은 바이트의 연속적인 스트림일 뿐입니다.읽기 가능한 바이트 수가 버퍼 용량보다 많을 경우 해당 바이트는 OS에 의해 큐잉되어 다음 호출에 사용할 수 있습니다.recv.

  • SOCK_DGRAM: 초과 바이트는 폐기됩니다.

메시지를 다 받았는지 어떻게 알 수 있나요?

  • SOCK_STREAM: 응용 프로그램 수준 프로토콜에 메시지 종료를 결정하는 방법을 구축해야 합니다.일반적으로 이것은 길이 접두사(메시지 길이로 각 메시지를 시작) 또는 메시지 끝 구분자(텍스트 기반 프로토콜의 줄 바꿈일 수 있음) 중 하나입니다.세 번째, 덜 사용되는 옵션은 각 메시지에 고정 크기를 지정하는 것입니다.이러한 옵션의 조합도 가능합니다(예: 길이 값이 포함된 고정 크기 헤더).

  • SOCK_DGRAM: 싱글recvcall은 항상 단일 데이터그램을 반환합니다.

버퍼에 일정한 공간을 확보하지 않고 공간이 부족할 염려 없이 계속 추가할 수 있는 방법이 있습니까?

아니요. 하지만 버퍼 크기를 조정할 수 있습니다.realloc()(처음 할당한 경우)malloc()또는calloc()(즉,)

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

어떤 버퍼보다 더 많은 데이터가 있는 경우 다음 호출을 위해 커널에 저장됩니다.recv.

네, 버퍼를 계속 키울 수 있습니다.오프셋부터 버퍼 중앙으로 recv를 실행할 수 있습니다.idx다음과 같은 작업을 수행합니다.

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

를 가지고 있는 경우SOCK_STREAM소켓,recv는 스트림에서 "최초 3000바이트까지"를 가져옵니다.버퍼의 크기에 대한 명확한 지침은 없습니다. 스트림이 얼마나 큰지 아는 것은 스트림이 모두 완료된 시점뿐입니다.-)

를 가지고 있는 경우SOCK_DGRAM소켓, 데이터그램이 버퍼보다 큽니다.recv버퍼에 데이터그램의 첫 번째 부분을 채우고 -1을 반환하고 EMSGSIZE로 errno를 설정합니다.불행하게도 프로토콜이 UDP이면 나머지 데이터그램이 손실된다는 것을 의미합니다.UDP가 신뢰할 수 없는 프로토콜이라고 불리는 이유의 일부입니다(신뢰할 수 있는 데이터그램 프로토콜이 있지만 그다지 인기가 없습니다.TCP/FAMIP에는 이름을 붙일 수 없습니다.후자를 꽤 잘 알면서도 말이다;-)

버퍼를 동적으로 확장하려면 처음에 버퍼를malloc및 사용realloc필요에 따라서,하지만 그것은 너에게 도움이 되지 않을 거예요recv아아, UDP 소스로부터.

위해서SOCK_STREAM소켓에서는 버퍼 사이즈는 중요하지 않습니다.대기 바이트의 일부를 풀하고 있기 때문에 다음 콜에서 더 많은 바이트를 취득할 수 있기 때문입니다.적당한 크기의 버퍼를 고르세요.

위해서SOCK_DGRAM소켓, 당신은 대기 메시지의 적합한 부분을 얻을 것이고 나머지는 폐기될 것입니다.다음 ioctl을 사용하여 대기 데이터그램 크기를 얻을 수 있습니다.

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

또는 다음 중 하나를 사용할 수 있습니다.MSG_PEEK그리고.MSG_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 ~65,515 바이트입니다따라서 수신 버퍼의 장애 방지 크기는 65507바이트(~64KB)입니다.

다만, 모든 큰 패킷이 네트워크 디바이스에 의해서 적절히 라우팅 되는 것은 아닙니다.자세한 것에 대하여는, 기존의 설명을 참조해 주세요.

최대 스루풋을 실현하기 위한 UDP 패킷의 최적 사이즈는 무엇입니까?
인터넷상의 최대 안전 UDP 패킷사이즈

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

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