ProgramingTip

여러 연결을 만들 때 C에서 소켓 시간 초과를 설정하는 방법은 무엇입니까?

bestdevel 2020. 11. 30. 19:26
반응형

여러 연결을 만들 때 C에서 소켓 시간 초과를 설정하는 방법은 무엇입니까?


상태 확인을 위해 여러 서버에 여러 연결을 만드는 간단한 프로그램을 작성 중입니다. 모든 연결은 주문형으로 구성됩니다. 최대 10 개의 연결을 동시에 만들 수 있습니다. 소켓 당 하나의 아이디어라는 아이디어가 마음에 들지 소켓이 모든 클라이언트 소켓을 비 블로킹으로 만들고 select () 풀에 던졌습니다.

내 클라이언트가 대상가 응답을 멈출 때 오류 보고서를 수신 대기 시간이 너무 길다고 서버 할 때까지 훌륭하게 작동했습니다.

포럼에서 몇 가지 주제를 확인했습니다. 일부는 경보 () 신호를 사용하거나 선택 () 함수 호출에서 시간 제한을 수 제안했습니다. 그러나 나는 하나가 아닌 여러 연결을 다루고 있습니다. 프로세스 전체 시간 초과 신호가 발생하면 다른 모든 연결에서 초과 연결을 구분할 방법이 없습니다.

어쨌든 시스템 기본 시간 초과 기간을 사용합니까?


SO_RCVTIMEO 및 SO_SNDTIMEO 소켓 옵션을 사용하여 다음과 같이 소켓 작업에 대한 시간 제한을 접근 수 있습니다.

    struct timeval timeout;      
    timeout.tv_sec = 10;
    timeout.tv_usec = 0;

    if (setsockopt (sockfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout,
                sizeof(timeout)) < 0)
        error("setsockopt failed\n");

    if (setsockopt (sockfd, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout,
                sizeof(timeout)) < 0)
        error("setsockopt failed\n");

편집 : 로부터 setsockopt man 페이지 :

SO_SNDTIMEO출력 작업에 대한 시간 제한 값을 설정하는 옵션입니다. 출력 작업이 완료 될 때까지 대기하는 시간을 제한하는 데 사용되는 초 및 마이크로 초 수와 함께받는 시간 매개 변수를받습니다. 전송 작업이 시간 동안 차단 된 경우 부분이 또는 전송 된 데이터가 잠금 오류 EWOULDB와 함께 반환됩니다. 현재 구현에서는 추가 데이터가 프로토콜에 전달 될 때 마다이 타이머가 다시 시작됩니다. 이는 출력을 위해 로우 워터 마크에서 하이 워터 마크까지 크기 범위의 출력 부분에 제한이 적용됨을 의미합니다.

SO_RCVTIMEO입력 작업에 대한 시간 제한 값을 설정하는 옵션입니다. 입력 작업이 완료 될 때까지 대기하는 시간을 제한하는 데 사용되는 초 및 마이크로 초 수와 함께받는 시간 매개 변수를받습니다. 현재 구현 에서이 타이머는 프로토콜이 추가 ​​데이터를 수신 할 때마다 다시 시작되는 제한은 사실상 비활성 타이머입니다. 추가 데이터를 수신하지 않고 시간 동안 수신 작업이 차단 된 경우 수신 또는 수신 된 데이터가 있음 EWOULDBLOCK 오류와 함께 반환됩니다. struct timeval 변수는 양의 시간 간격을 둡니다. 개체는 setsockopt ()가 EDOM 오류를 반환합니다.


문제를 완전히 이해했는지 확실하지 않지만 내가 가진 것과 관련이 있다고 생각합니다 .Qt를 TCP 소켓과 사용하고 Windows와 Linux 함께 모두 차단되지 않습니다.

이미 메시지 클라이언트가 실패했거나 사라 졌을 때 빠른 알림을 받고 연결 해제 신호가 보관 될 때 기본 900 초 이상 기다리지 않습니다. 이 작업을 수행하는 트릭은 SOL_TCP 계층의 TCP_USER_TIMEOUT 소켓 옵션을 밀리 초 단위로 지정된 필수 값으로 설정하는 것입니다.

이것은 새로운 옵션입니다. pls는 http://tools.ietf.org/html/rfc5482를 참조하십시오 . 그러나 분명히 잘 작동하고 있고 WinXP, Win7 / x64 및 Kubuntu 12.04 / x64에서 시도해 @하는 10 초를 선택했습니다. 조금 더 길지만 이전에 시도한 다른 것보다 훨씬 낫습니다 ;-)

내가 만난 유일한 문제는 적절한 포함을 찾는 것이 었습니다. 명백하게 표준 소켓에 추가적으로 (아직 ..) 마침내 다음과 같이 직접 정의했습니다.

#ifdef WIN32
    #include <winsock2.h>
#else
    #include <sys/socket.h>
#endif

#ifndef SOL_TCP
    #define SOL_TCP 6  // socket options TCP level
#endif
#ifndef TCP_USER_TIMEOUT
    #define TCP_USER_TIMEOUT 18  // how long for loss retry before timeout [ms]
#endif

이 소켓 옵션을 사용하는 것은 클라이언트가 이미 사용 설정에만 작동하며 코드 줄은 다음과 사용할 수 있습니다.

int timeout = 10000;  // user timeout in milliseconds [ms]
setsockopt (fd, SOL_TCP, TCP_USER_TIMEOUT, (char*) &timeout, sizeof (timeout));

초기 연결의 실패는 connect ()를 호출 할 때 시작된 타이머에 의해 실행됩니다. 이에 대한 Qt 신호가 없기 때문에 연결 신호가 발생하지 않고 연결이 끊어집니다. 아직 연결되지 않았 음 때문에 제기되지 않았 음 ..


자신만의 타임 아웃 시스템을 구현할 수 없습니까?

시간 초과 이벤트의 정렬 된 목록 또는 Heath가 제안한대로 우선 순위 힙을 유지하십시오. 선택 또는 폴링 호출에서 제한 시간 목록 상단의 제한 시간 값을 사용하십시오. 해당 시간 초과가 도달하면 해당 작업을 수행하십시오.

이 작업은 아직 연결되지 않은 소켓을 연결할 수 있습니다.


connect제한 시간은 비 블로킹 소켓을 (GNU의 libc으로 취급하는 문서connect). 당신은 도착 connect즉시 반환하고 사용하는 select전체에 대한 연결을위한 타임 아웃 기다릴.

여기에도 설명되어 있습니다. connect (함수) error에 대한 작업 진행 중 오류입니다 .

int wait_on_sock(int sock, long timeout, int r, int w)
{
    struct timeval tv = {0,0};
    fd_set fdset;
    fd_set *rfds, *wfds;
    int n, so_error;
    unsigned so_len;

    FD_ZERO (&fdset);
    FD_SET  (sock, &fdset);
    tv.tv_sec = timeout;
    tv.tv_usec = 0;

    TRACES ("wait in progress tv={%ld,%ld} ...\n",
            tv.tv_sec, tv.tv_usec);

    if (r) rfds = &fdset; else rfds = NULL;
    if (w) wfds = &fdset; else wfds = NULL;

    TEMP_FAILURE_RETRY (n = select (sock+1, rfds, wfds, NULL, &tv));
    switch (n) {
    case 0:
        ERROR ("wait timed out\n");
        return -errno;
    case -1:
        ERROR_SYS ("error during wait\n");
        return -errno;
    default:
        // select tell us that sock is ready, test it
        so_len = sizeof(so_error);
        so_error = 0;
        getsockopt (sock, SOL_SOCKET, SO_ERROR, &so_error, &so_len);
        if (so_error == 0)
            return 0;
        errno = so_error;
        ERROR_SYS ("wait failed\n");
        return -errno;
    }
}

물론 첫 번째 대답은 가장 좋은 대답입니다. 추가 할 수 있습니까?

...

2 setsockopt 후 클라이언트가 시간 초과 테스트를 통과했는지 아니면 다음과 같이 실패했는지 제어 할 수 있습니다.

n = readline(sockd, recvline, MAXLINE);

삽입해야 해

if (n <= 0){
    if(write(sockd,"ERROR. Timeout di 5sec scaduto, sii piu' veloce\n",MAXLINE)<0)
        err_sys("errore nella write");
    close(sockd);
    sockd = 0;
    break;
}

참고 URL : https://stackoverflow.com/questions/4181784/how-to-set-socket-timeout-in-c-when-making-multiple-connections

반응형