Reputation: 38173
What am I missing?
I have very simple client and server. The server uses recv
with timeout (using select
) for 3 seconds. Then it shutdown
s and close
s the sockets and exits.
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?
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.
Sorry for the long and probably stupid question.
Upvotes: 3
Views: 1073
Reputation: 23886
You didnt not close the socket in your client - so this a valid socket. From send()'s man page
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.
ADDING: Have a look at socket options (man setsockopt and 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_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.
Upvotes: 1
Reputation: 409404
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):
No indication of failure to deliver is implicit in a send(). Locally
detected errors are indicated by a return value of -1.
Upvotes: 3