Inconsistency in TCP sockets behavior between Windows and Linux
- From: "Rafi" <Rafi@xxxxxxxxxxxxxxxxxxxxxxxxx>
- Date: Mon, 20 Feb 2006 03:12:27 -0800
Hi,
There is an inconsistency in TCP sockets behavior between Windows and Linux,
and I think that Linux behavior is more reasonable.
There are client and server applications.
Server creates a listening socket and waits for incoming TCP connection.
Client connects to the server, sends some amount of data (say 100 bytes) and
then abortively closes the connection. This is done by setting linger (ON,
delay 0) option on client side socket.
Server accepts the connection but 'recv' fails with 10054 (CONNRESET)
although network sniffer (ethereal) shows the data has successfully arrived
at the server side and TCP ACK was sent (from Server to Client).
If Client would delay a bit (say Sleep for a second) it works fine, the
'recv' succeeds to receive the sent buffer. On Linux the same program works
fine; that is the sent buffer can be read regardless the reset connection.
I think it is unreasonable that 'recv' operation works in different way
depending on the time when it was called, before or after TCP RST has
arrived.
The programs demonstrating this behavior follows. The same program works as
client and server. Server binds to port 23456 and should be called without
arguments. In order to run the program as a client, run it with the following
arguments: -c -d server_ip_address.
This program should compile on windows and Linux.
#ifndef _WIN32
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <errno.h>
#else
#include "windows.h"
#include "winsock.h"
#endif
#include <string.h>
#include <stdio.h>
int isServ = 1;
char *destIp = "";
unsigned short port = 23456;
/*
* usage
* to run as server: -s
* to run as client: -c -d server_ip_address
*/
#ifndef _WIN32
#define closesocket close
#define Sleep(n) usleep(n*1000)
#endif
int main(int argc, char** argv)
{
struct sockaddr_in sa;
int s;
int cnt, ret, addrLen;
char buff[100];
#if _WIN32
{
WORD wVersionRequested;
WSADATA wsaData;
wVersionRequested = 0x0101;
WSAStartup(wVersionRequested, &wsaData);
}
#endif
for (cnt = 1; cnt < argc; cnt++)
{
if (!strcmp(argv[cnt],"-s"))
isServ = 1;
else if (!strcmp(argv[cnt],"-c"))
isServ = 0;
else if (!strcmp(argv[cnt],"-d"))
destIp = argv[++cnt];
else
printf("wrong usage\n");
}
memset(&sa,0,sizeof(sa));
sa.sin_family = AF_INET;
sa.sin_port = htons(port);
if (isServ)
sa.sin_addr.s_addr = INADDR_ANY;
else
sa.sin_addr.s_addr = inet_addr(destIp);
addrLen = sizeof(sa);
s = socket(AF_INET,SOCK_STREAM,0);
if (s < 0)
{
printf("failed to create socket \n");
exit(0);
}
if (isServ)
{
int ns,err;
struct sockaddr_in nsa;
printf("running as server\n");
if (bind(s,(struct sockaddr*)&sa, addrLen) < 0)
{
printf("failed to bind the socket\n");
exit(0);
}
if (listen(s,10) < 0)
{
printf("failed to listen on the socket\n");
exit(0);
}
addrLen = sizeof(nsa);
ns = accept(s,(struct sockaddr*)&nsa, &addrLen);
if (ns < 0)
{
printf("failed to accept\n");
exit(0);
}
printf("accepted client connection from %s:%d\n",
inet_ntoa(nsa.sin_addr),ntohs(nsa.sin_port));
/* sleep for a while; lets other side to reset the connection */
printf("going to sleep for a while ...\n");
Sleep(1000);
printf("awake, try to read from the socket ...\n");
ret = recv(ns,buff,sizeof(buff),0);
#ifdef _WIN32
err = WSAGetLastError();
#else
err = errno;
#endif
printf("Recv returns with %d, error %d\n",ret,err);
closesocket(ns);
closesocket(s);
}
else
{
struct linger l;
/* set the linger, for abortive close */
l.l_onoff = 1;
l.l_linger = 0;
if (setsockopt(s,SOL_SOCKET,SO_LINGER,(char*)&l,sizeof(l)) < 0)
{
printf("failed to to set linger\n");
exit(0);
}
if (connect(s,(struct sockaddr*)&sa, addrLen) < 0)
{
printf("failed to to connect\n");
exit(0);
}
ret = send(s,buff,50,0);
if (ret != 50)
{
printf("failed to send\n");
exit(0);
}
/* if client Sleep, server running on Windows works fine, otherwise
server 'recv' fails */
/*Sleep(3000);*/
closesocket(s);
printf("connected, sent and closed the socket\n");
}
return 0;
}
.
- Follow-Ups:
- Prev by Date: Re: Making sure you receive it all
- Next by Date: Re: Inconsistency in TCP sockets behavior between Windows and Linux
- Previous by thread: Time out delays
- Next by thread: Re: Inconsistency in TCP sockets behavior between Windows and Linux
- Index(es):
Relevant Pages
|