여러 연결을 할 때 C에서 소켓타임아웃을 설정하려면 어떻게 해야 합니까?
상태 확인을 위해 여러 서버에 여러 번 연결하는 간단한 프로그램을 작성하고 있습니다.이러한 접속은 모두 온디멘드로 구축됩니다.동시에 최대 10개의 접속을 작성할 수 있습니다.소켓당 1 스레드라는 생각이 마음에 들지 않아서 클라이언트 소켓을 모두 논블로킹으로 만들어 select() 풀에 넣습니다.
타겟 서버가 응답을 정지했을 때, 에러 리포트를 수신할 수 있을 때까지의 대기 시간이 너무 길다고 클라이언트에 항의할 때까지, 이것은 훌륭하게 동작했습니다.
포럼에서 몇 가지 주제를 확인했습니다.일부에서는 select() 함수 호출에서 알람() 신호를 사용하거나 타임아웃을 설정할 수 있다고 제안했습니다.하지만 난 한 개가 아니라 여러 개의 연결을 다루고 있어프로세스 전체의 타임아웃 신호가 발생하면 다른 모든 접속에서 타임아웃 접속을 구별할 방법이 없습니다.
시스템 디폴트타임아웃 기간을 변경할 수 있습니까?
다음과 같이 SO_RCVTIMEO 및 SO_SNDTIMEO 소켓 옵션을 사용하여 모든 소켓 작업에 대해 시간 초과를 설정할 수 있습니다.
struct timeval timeout;
timeout.tv_sec = 10;
timeout.tv_usec = 0;
if (setsockopt (sockfd, SOL_SOCKET, SO_RCVTIMEO, &timeout,
sizeof timeout) < 0)
error("setsockopt failed\n");
if (setsockopt (sockfd, SOL_SOCKET, SO_SNDTIMEO, &timeout,
sizeof timeout) < 0)
error("setsockopt failed\n");
편집: 에서setsockopt
man 페이지:
SO_SNDTIMEO
는 출력 동작의 타임아웃 값을 설정하는 옵션입니다.출력 조작이 완료될 때까지의 대기 시간을 제한하기 위해 사용되는 초수 및 마이크로초 단위의 구조 timeval 파라미터를 받아들입니다.송신 조작이 이 시간 동안 차단되어 있는 경우는, 부분 카운트나 데이터가 송신되지 않은 경우는 EWOLSBLOCK 에러와 함께 반환됩니다.현재의 실장에서는, 이 타이머는, 추가 데이터가 프로토콜에 전달될 때마다 재기동해, 출력용의 로우 워터 마크로부터 하이 워터 마크까지의 사이즈의 출력 부분에 제한이 적용되는 것을 의미한다.
SO_RCVTIMEO
는 입력 조작의 타임 아웃치를 설정하는 옵션입니다.입력 조작이 완료될 때까지의 대기시간을 제한하기 위해 사용되는 초수 및 마이크로초의 구조 timeval 파라미터를 받아들입니다.현재의 실장에서는, 이 타이머는, 프로토콜에 의해서 추가의 데이터가 수신될 때마다 재기동되기 때문에, 그 제한은 사실상 비액티비티 타이머입니다.추가 데이터를 수신하지 않고 이 시간 동안 수신 작업이 차단되면 짧은 카운트로 반환되거나 데이터가 수신되지 않으면 EWDBLOCK 류 lock lock lock lock lock lock lock 。간격을 합니다 않으면 EDMstruct timeval 을 합니다.setsockopt()는 EDM을 사용합니다.
이 문제를 완전히 이해하고 있는지는 모르겠습니다만, 이것은 제가 가지고 있던 것과 관련이 있는 것 같습니다.QT를 TCP 소켓 통신과 함께 사용하고 있는 것, 모든 논블로킹(Windows와 Linux)을 사용하고 있습니다.
는 이미 접속되어 있는 클라이언트에 장애가 발생하거나 완전히 사라졌을 때 빠른 알림을 받고 연결 해제 신호가 발생할 때까지 기본 900초 이상을 기다리지 않았습니다.이 기능을 하기 위한 요령은 SOL_TCP 레이어의 TCP_USER_TIMEOUT 소켓옵션을 밀리초 단위로 필요한 값으로 설정하는 것입니다.
이것은 비교적 새로운 옵션입니다.https://www.rfc-editor.org/rfc/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
접속이 완료될 때까지 타임아웃으로 대기합니다.
이것도 여기서 설명하겠습니다.Operation now in progress error on connect() function 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;
}
}
언급URL : https://stackoverflow.com/questions/4181784/how-to-set-socket-timeout-in-c-when-making-multiple-connections
'programing' 카테고리의 다른 글
C은 무엇인가"정적"기능을 합니까? (0) | 2022.08.16 |
---|---|
정적으로 연결된 라이브러리 간에 심볼 충돌을 처리하는 방법은 무엇입니까? (0) | 2022.08.16 |
GCC를 사용하여 읽을 수 있는 어셈블리를 만들고 있습니까? (0) | 2022.08.09 |
vuejs v2.0에서 컴포넌트로 데이터 전달 (0) | 2022.08.09 |
Requirejs에서 Vue.js를 사용하는 방법 (0) | 2022.08.09 |