programing

C에서 소켓 연결 상태를 찾는 방법은 무엇입니까?

skycolor 2023. 8. 5. 10:02
반응형

C에서 소켓 연결 상태를 찾는 방법은 무엇입니까?

TCP 연결이 되어 있습니다.서버는 클라이언트에서 데이터를 읽기만 합니다.이제 연결이 끊기면 클라이언트가 파이프에 데이터를 쓰는 동안 오류가 발생하지만(파손된 파이프) 서버는 여전히 해당 파이프에서 수신합니다.연결 상태가 UP인지 아닌지 알 수 있는 방법이 있습니까?

다음과 같이 getsockopt를 호출할 수 있습니다.

int error = 0;
socklen_t len = sizeof (error);
int retval = getsockopt (socket_fd, SOL_SOCKET, SO_ERROR, &error, &len);

소켓이 작동하는지 테스트하려면:

if (retval != 0) {
    /* there was a problem getting the error code */
    fprintf(stderr, "error getting socket error code: %s\n", strerror(retval));
    return;
}

if (error != 0) {
    /* socket has a non zero error status */
    fprintf(stderr, "socket error: %s\n", strerror(error));
}

소켓이 여전히 연결되어 있는지 여부를 안정적으로 감지하는 유일한 방법은 정기적으로 데이터를 전송하는 것입니다.일반적으로 클라이언트가 무시하는 애플리케이션 수준 'ping' 패킷을 정의하는 것이 더 편리하지만, 이러한 기능 없이 프로토콜이 이미 지정된 경우에는 SO_KEEPALIVE 소켓 옵션을 설정하여 이를 수행하도록 tcp 소켓을 구성할 수 있어야 합니다.winsock 설명서에 링크를 연결했지만 모든 BSD와 같은 소켓 스택에서 동일한 기능을 사용할 수 있어야 합니다.

TCP 킵얼라이브 소켓 옵션(SO_KEEPALIVE)은 이 시나리오에서 도움이 되며 연결이 끊길 경우 서버 소켓을 닫습니다.

recv에 나온 것처럼 매우 간단합니다.

소켓에서 다음을 사용하여 1바이트를 읽는지 확인합니다.MSG_PEEK그리고.MSG_DONT_WAIT이렇게 하면 데이터가 대기열에서 해제되지 않습니다(PEEK) 및 작업이 비차단(DONT_WAIT)

while (recv(client->socket,NULL,1, MSG_PEEK | MSG_DONTWAIT) != 0) {
    sleep(rand() % 2); // Sleep for a bit to avoid spam
    fflush(stdin);
    printf("I am alive: %d\n", socket);
}

// When the client has disconnected, this line will execute
printf("Client %d went away :(\n", client->socket);

여기서 예제를 찾았습니다.

다음을 통해 소켓 연결 상태를 쉽게 확인할 수 있는 방법이 있습니다.poll콜. 먼저, 소켓에 대한 폴링이 필요합니다.POLLIN사건의

  1. 소켓이 닫혀 있지 않고 읽을 데이터가 있는 경우read0보다 많이 반환됩니다.
  2. 소켓에 대한 새로운 데이터가 없다면,POLLIN의 경우 0으로 설정됩니다.revents
  3. 소켓이 닫혀 있는 경우POLLIN플래그가 1로 설정되고 읽기가 0을 반환합니다.

다음은 작은 코드 조각입니다.

int client_socket_1, client_socket_2;
if ((client_socket_1 = accept(listen_socket, NULL, NULL)) < 0)
{
    perror("Unable to accept s1");
    abort();
}
if ((client_socket_2 = accept(listen_socket, NULL, NULL)) < 0)
{
    perror("Unable to accept s2");
    abort();
}
pollfd pfd[]={{client_socket_1,POLLIN,0},{client_socket_2,POLLIN,0}};
char sock_buf[1024]; 
while (true)
{
    poll(pfd,2,5);
    if (pfd[0].revents & POLLIN)
    {
        int sock_readden = read(client_socket_1, sock_buf, sizeof(sock_buf));
        if (sock_readden == 0)
            break;
        if (sock_readden > 0)
            write(client_socket_2, sock_buf, sock_readden);
    }
    if (pfd[1].revents & POLLIN)
    {
        int sock_readden = read(client_socket_2, sock_buf, sizeof(sock_buf));
        if (sock_readden == 0)
            break;
        if (sock_readden > 0)
            write(client_socket_1, sock_buf, sock_readden);
    }
}

저도 비슷한 문제가 있었습니다.서버가 클라이언트에 연결되어 있는지, 클라이언트가 서버에 연결되어 있는지 알고 싶습니다.이러한 상황에서 recv 함수의 반환 값은 유용할 수 있습니다.소켓이 연결되어 있지 않으면 0바이트를 반환합니다.따라서 저는 이것을 사용하여 루프를 끊었고 추가적인 함수 스레드를 사용할 필요가 없었습니다.전문가들이 올바른 방법이라고 생각하는 경우에도 이 방법을 사용할 수 있습니다.

get sock opt는 다소 유용할 수 있지만, 다른 방법은 SIGPIPE에 대한 신호 처리기를 설치하는 것입니다. 기본적으로 소켓 연결이 끊어질 때마다 커널은 SIGPIPE 신호를 프로세스로 보내고 필요한 작업을 수행할 수 있습니다.그러나 연결 상태를 알 수 있는 솔루션은 여전히 제공되지 않습니다.이게 도움이 되길 바랍니다.

getpeername 함수를 사용해야 합니다.

이제 연결이 끊어지면 errno: ENOTCONN - 소켓이 연결되지 않았습니다.그 말은 'DOWN'을 의미합니다.

그렇지 않으면(다른 오류가 없는 경우) 반환 코드는 0 --> UP을 의미합니다.

리소스: man 페이지: http://man7.org/linux/man-pages/man2/getpeername.2.html

Windows에서는 다음을 사용하여 네트워크 어댑터에 있는 모든 포트의 정확한 상태를 쿼리할 수 있습니다.확장 TCP 테이블 가져오기

프로세스 등과 관련된 항목으로만 필터링하고 필요에 따라 주기적으로 모니터링할 수 있습니다.이것은 "대안적인" 접근법입니다.

또한 소켓 핸들을 복제하고 소켓에 IOCP/O 겹침 i/o 대기를 설정하고 이러한 방식으로 모니터링할 수도 있습니다.

#include <sys/socket.h>
#include <poll.h>
...

int client = accept(sock_fd, (struct sockaddr*)&address, (socklen_t*)&addrlen);
pollfd pfd = {client, POLLERR, 0}; // monitor errors occurring on client fd
...
while(true)
{
   ...
   if(not check_connection(pfd, 5))
   {
        close(client);
        close(sock[1]);
        if(reconnect(HOST, PORT, reconnect_function))
            printf("Reconnected.\n");
        pfd = {client, POLLERR, 0};
   }
   ...
}
...
bool check_connection(pollfd &pfd, int poll_timeout)
{
    poll(&pfd, 1, poll_timeout);
    return not (pfd.revents & POLLERR);
}

사용할 수 있습니다.SS_ISCONNECTED의 거시적인.getsockopt()기능.SS_ISCONNECTED에 정의되어 있습니다.socketvar.h.

BSD 소켓의 경우 Bej의 가이드를 확인할 수 있습니다.recv가 0을 반환하면 다른 쪽이 연결이 끊어진 것을 알 수 있습니다.

이제 여러분은 실제로 다른 쪽의 연결이 끊기는 것을 감지하는 가장 쉬운 방법이 무엇인지 물으실 수 있습니다.한 가지 방법은 스레드가 항상 recv를 수행하도록 하는 것입니다.이 스레드는 클라이언트의 연결이 끊어질 때 즉시 알 수 있습니다.

언급URL : https://stackoverflow.com/questions/4142012/how-to-find-the-socket-connection-state-in-c

반응형