即使连接不再可用,发送成功?

时间:2022-03-23 05:11:25

What am I missing?

我错过了什么?

I have very simple client and server. The server uses recv with timeout (using select) for 3 seconds. Then it shutdowns and closes the sockets and exits.

我有非常简单的客户端和服务器。服务器使用recv with timeout(使用select)3秒。然后它关闭并关闭插座和退出。

The client connects to the server, sleeps 30 seconds and sends very short message. The sending is about 27seconds after the server has closed the sockets and exited.
And send does not fail..? Why? Why it does not return -1 for error?

客户端连接到服务器,休眠30秒并发送非常短的消息。在服务器关闭套接字并退出后大约27秒发送。并发送不会失败..?为什么?为什么它不返回-1表示错误?


Please note: I cut all checks for return codes and removed all logs, to make this as short as I can. Also, I removed all includes, to make this shorter. But it IS a real code.

请注意:我删除了所有检查返回代码并删除了所有日志,以尽可能缩短。此外,我删除了所有包含,以缩短。但它是一个真正的代码。

client code:

int main( int argc, char* argv[] )
{
    addrinfo hints;
    memset(&hints, 0, sizeof hints); // make sure the struct is empty

    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM; // TCP stream sockets

    addrinfo *res;
    getaddrinfo( "127.0.0.1", "1313", &hints, &res );
    int nSocketFD = socket( res->ai_family, res->ai_socktype, res->ai_protocol );
    assert( -1 != connect( nSocketFD, res->ai_addr, res->ai_addrlen) );
    freeaddrinfo( res ); // free the linked-list, we don't need it anymore

    sleep( 30 );
    if( send( nSocketFD, "bla", 4, 0 ) > 0 )
    {
        printf( "Message successfully sent!\n" );
    }   

    close( nSocketFD );

    return 0;
}

and server:

int main()
{
    addrinfo hints;
    memset(&hints, 0, sizeof hints);
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_flags = AI_PASSIVE;

    addrinfo *res;  // will point to the results
    getaddrinfo( NULL, "1313", &hints, &res );
    int nSocketFD = socket( res->ai_family, res->ai_socktype, res->ai_protocol );
    bind( nSocketFD, res->ai_addr, res->ai_addrlen );
    freeaddrinfo( res ); // free the linked-list
    listen( nSocketFD, 1 );

    sockaddr_storage their_addr;
    socklen_t addr_size = sizeof( sockaddr_storage );
    int nAcceptedSocket = accept( nSocketFD, (sockaddr*)&their_addr, &addr_size );
    assert( -1 != nAcceptedSocket );

    fd_set fds;
    FD_ZERO( &fds );
    FD_SET( nAcceptedSocket, &fds );
    timeval tv; 
    tv.tv_sec = 3;
    tv.tv_usec = 0;

    if( 0 == select( nAcceptedSocket + 1, &fds, NULL, NULL, &tv) )
    {   
        printf( "recv timeout! Exiting..\n" );
        shutdown( nSocketFD, SHUT_RDWR );
        close( nSocketFD );
        shutdown( nAcceptedSocket, SHUT_RDWR );
        close( nAcceptedSocket );
        return 1;
    }   
    assert( false );
    return 0;
}

When I execute it, I see the messages for recv timeout and for successful sent message.

当我执行它时,我看到recv超时和成功发送消息的消息。

Sorry for the long and probably stupid question.

对不起那个漫长且可能很愚蠢的问题。

2 个解决方案

#1


3  

In general you need to read from a socket to get it to notice that the remote end has closed the connection.

通常,您需要从套接字读取以使其注意到远程端已关闭连接。

From the manual page of send (which is just write but with flags):

从send的手册页(只是写但带有标志):

No indication of failure to deliver is implicit in a send().  Locally
detected errors are indicated by a return value of -1.

#2


1  

You didnt not close the socket in your client - so this a valid socket. From send()'s man page

您没有关闭客户端中的套接字 - 所以这是一个有效的套接字。来自send()的手册页

No indication of failure to deliver is implicit in a send().  Locally detected errors are indicated by a return value of -1.

We have this issue with some of our software - if network hardware fails somewhere along the line and it is brought back up again - then either end still thinks the socket is valid - and without keepalives probes - it will stay this way.

我们的一些软件遇到了这个问题 - 如果网络硬件在某个地方出现故障并再次恢复 - 那么任何一端仍然认为套接字是有效的 - 并且没有Keepalive探测器 - 它将保持这种状态。

ADDING: Have a look at socket options (man setsockopt and man tcp) SO_KEEPALIVE

添加:看看socket选项(man setsockopt和man tcp)SO_KEEPALIVE

From TCP man page tcp_keepalive_intvl (integer; default: 75; since Linux 2.4) The number of seconds between TCP keep-alive probes.

从TCP手册页tcp_keepalive_intvl(整数;默认值:75;自Linux 2.4开始)TCP保持活动探测之间的秒数。

   tcp_keepalive_probes (integer; default: 9; since Linux 2.2)
          The  maximum  number  of  TCP  keep-alive  probes  to  send before giving up and killing the connection if no response is obtained from the other end.

   tcp_keepalive_time (integer; default: 7200; since Linux 2.2)
          The number of seconds a connection needs to be idle before TCP begins sending out  keep-alive  probes.   Keep-alives  are only  sent when the SO_KEEPALIVE socket option is enabled.  The default value is 7200 seconds (2 hours).  An idle connection is terminated after approximately an additional 11 minutes (9 probes an interval of 75  seconds  apart)  when  keep-alive is enabled.

          Note that underlying connection tracking mechanisms and application timeouts may be much shorter.

#1


3  

In general you need to read from a socket to get it to notice that the remote end has closed the connection.

通常,您需要从套接字读取以使其注意到远程端已关闭连接。

From the manual page of send (which is just write but with flags):

从send的手册页(只是写但带有标志):

No indication of failure to deliver is implicit in a send().  Locally
detected errors are indicated by a return value of -1.

#2


1  

You didnt not close the socket in your client - so this a valid socket. From send()'s man page

您没有关闭客户端中的套接字 - 所以这是一个有效的套接字。来自send()的手册页

No indication of failure to deliver is implicit in a send().  Locally detected errors are indicated by a return value of -1.

We have this issue with some of our software - if network hardware fails somewhere along the line and it is brought back up again - then either end still thinks the socket is valid - and without keepalives probes - it will stay this way.

我们的一些软件遇到了这个问题 - 如果网络硬件在某个地方出现故障并再次恢复 - 那么任何一端仍然认为套接字是有效的 - 并且没有Keepalive探测器 - 它将保持这种状态。

ADDING: Have a look at socket options (man setsockopt and man tcp) SO_KEEPALIVE

添加:看看socket选项(man setsockopt和man tcp)SO_KEEPALIVE

From TCP man page tcp_keepalive_intvl (integer; default: 75; since Linux 2.4) The number of seconds between TCP keep-alive probes.

从TCP手册页tcp_keepalive_intvl(整数;默认值:75;自Linux 2.4开始)TCP保持活动探测之间的秒数。

   tcp_keepalive_probes (integer; default: 9; since Linux 2.2)
          The  maximum  number  of  TCP  keep-alive  probes  to  send before giving up and killing the connection if no response is obtained from the other end.

   tcp_keepalive_time (integer; default: 7200; since Linux 2.2)
          The number of seconds a connection needs to be idle before TCP begins sending out  keep-alive  probes.   Keep-alives  are only  sent when the SO_KEEPALIVE socket option is enabled.  The default value is 7200 seconds (2 hours).  An idle connection is terminated after approximately an additional 11 minutes (9 probes an interval of 75  seconds  apart)  when  keep-alive is enabled.

          Note that underlying connection tracking mechanisms and application timeouts may be much shorter.