Development Tip

sock send () 명령에서 "일시적으로 리소스를 사용할 수 없음"이 발생하는 원인

yourdevel 2020. 10. 29. 20:09
반응형

sock send () 명령에서 "일시적으로 리소스를 사용할 수 없음"이 발생하는 원인


Resource temporarily unavailable소켓 send()명령 에 오류 가 발생할 수있는 것은 무엇입니까 ? 소켓은 AF_UNIX, SOCK_STREAM. 대부분의 경우 작동하지만 때때로이 오류가 발생합니다. 소켓의받는 쪽이 제대로 작동하는 것 같습니다.

나는 이것이 그다지 상세하지 않다는 것을 알고 있지만 일반적인 아이디어를 찾고 있습니다. 감사!


"Resource temporarily unavailable"에 해당하는 오류 메시지 EAGAIN입니다. 이는 작업이 차단되었지만 비 차단 작업이 요청되었음을 의미합니다. 의 경우 다음 send()중 하나 때문일 수 있습니다.

  • 파일 설명자를 비 차단으로 명시 적으로 표시합니다 fcntl(). 또는
  • 통과 MSG_DONTWAIT플래그를합니다 send(); 또는
  • SO_SNDTIMEO소켓 옵션 으로 전송 시간 제한을 설정합니다 .

non-blocking소켓을 사용하고 있고 출력 버퍼가 가득 차 있기 때문 입니다.

로부터 send()man 페이지

   When the message does not fit into  the  send  buffer  of  the  socket,
   send() normally blocks, unless the socket has been placed in non-block-
   ing I/O mode.  In non-blocking mode it  would  return  EAGAIN  in  this
   case.  

EAGAIN"일시적으로 사용할 수없는 리소스" 와 관련된 오류 코드입니다.

select()이 동작을 더 잘 제어하려면 사용 고려하십시오.


예를 들어 보겠습니다.

  1. 클라이언트는 서버에 연결하고 1 초마다 1MB의 데이터를 서버에 보냅니다.

  2. 서버 측은 연결을 수락 한 다음 tcp send buffer클라이언트 의 recv msg없이 20 초 동안 잠자기 때문에 클라이언트 측은 가득 찰 것입니다.

클라이언트 측 코드 :

#include <arpa/inet.h>
#include <sys/socket.h>
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#define exit_if(r, ...)                                                                          \
    if (r) {                                                                                     \
        printf(__VA_ARGS__);                                                                     \
        printf("%s:%d error no: %d error msg %s\n", __FILE__, __LINE__, errno, strerror(errno)); \
        exit(1);                                                                                 \
    }

void setNonBlock(int fd) {
    int flags = fcntl(fd, F_GETFL, 0);
    exit_if(flags < 0, "fcntl failed");
    int r = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
    exit_if(r < 0, "fcntl failed");
}

void test_full_sock_buf_1(){
    short port = 8000;
    struct sockaddr_in addr;
    memset(&addr, 0, sizeof addr);
    addr.sin_family = AF_INET;
    addr.sin_port = htons(port);
    addr.sin_addr.s_addr = INADDR_ANY;


    int fd = socket(AF_INET, SOCK_STREAM, 0);
    exit_if(fd<0, "create socket error");

    int ret = connect(fd, (struct sockaddr *) &addr, sizeof(struct sockaddr));
    exit_if(ret<0, "connect to server error");
    setNonBlock(fd);

    printf("connect to server success");

    const int LEN = 1024 * 1000;
    char msg[LEN];  // 1MB data
    memset(msg, 'a', LEN);

    for (int i = 0; i < 1000; ++i) {
        int len = send(fd, msg, LEN, 0);
        printf("send: %d, erron: %d, %s \n", len, errno, strerror(errno));
        sleep(1);
    }

}

int main(){
    test_full_sock_buf_1();

    return 0;
}

서버 측 코드 :

    #include <arpa/inet.h>
    #include <sys/socket.h>
    #include <stdio.h>
    #include <errno.h>
    #include <fcntl.h>
    #include <stdlib.h>
    #include <string.h>
    #define exit_if(r, ...)                                                                          \
        if (r) {                                                                                     \
            printf(__VA_ARGS__);                                                                     \
            printf("%s:%d error no: %d error msg %s\n", __FILE__, __LINE__, errno, strerror(errno)); \
            exit(1);                                                                                 \
        }
void test_full_sock_buf_1(){

    int listenfd = socket(AF_INET, SOCK_STREAM, 0);
    exit_if(listenfd<0, "create socket error");

    short port = 8000;
    struct sockaddr_in addr;
    memset(&addr, 0, sizeof addr);
    addr.sin_family = AF_INET;
    addr.sin_port = htons(port);
    addr.sin_addr.s_addr = INADDR_ANY;

    int r = ::bind(listenfd, (struct sockaddr *) &addr, sizeof(struct sockaddr));
    exit_if(r<0, "bind socket error");

    r = listen(listenfd, 100);
    exit_if(r<0, "listen socket error");

    struct sockaddr_in raddr;
    socklen_t rsz = sizeof(raddr);
    int cfd = accept(listenfd, (struct sockaddr *) &raddr, &rsz);
    exit_if(cfd<0, "accept socket error");

    sockaddr_in peer;
    socklen_t alen = sizeof(peer);
    getpeername(cfd, (sockaddr *) &peer, &alen);

    printf("accept a connection from %s:%d\n", inet_ntoa(peer.sin_addr), ntohs(peer.sin_port));

    printf("but now I will sleep 15 second, then exit");
    sleep(15);
}

서버 측을 시작한 다음 클라이언트 측을 시작하십시오.

서버 측은 다음을 출력 할 수 있습니다.

accept a connection from 127.0.0.1:35764
but now I will sleep 15 second, then exit
Process finished with exit code 0

enter image description here

클라이언트 측은 다음을 출력 할 수 있습니다.

connect to server successsend: 1024000, erron: 0, Success 
send: 1024000, erron: 0, Success 
send: 1024000, erron: 0, Success 
send: 552190, erron: 0, Success 
send: -1, erron: 11, Resource temporarily unavailable 
send: -1, erron: 11, Resource temporarily unavailable 
send: -1, erron: 11, Resource temporarily unavailable 
send: -1, erron: 11, Resource temporarily unavailable 
send: -1, erron: 11, Resource temporarily unavailable 
send: -1, erron: 11, Resource temporarily unavailable 
send: -1, erron: 11, Resource temporarily unavailable 
send: -1, erron: 11, Resource temporarily unavailable 
send: -1, erron: 11, Resource temporarily unavailable 
send: -1, erron: 11, Resource temporarily unavailable 
send: -1, erron: 11, Resource temporarily unavailable 
send: -1, erron: 104, Connection reset by peer 
send: -1, erron: 32, Broken pipe 
send: -1, erron: 32, Broken pipe 
send: -1, erron: 32, Broken pipe 
send: -1, erron: 32, Broken pipe 
send: -1, erron: 32, Broken pipe 

enter image description here

You can see, as the server side doesn't recv the data from client, so when the client side tcp buffer get full, but you still send data, so you may get Resource temporarily unavailable error.

참고URL : https://stackoverflow.com/questions/14370489/what-can-cause-a-resource-temporarily-unavailable-on-sock-send-command

반응형