From: papamms on
On 5月23日, 上午8时29分, David Schwartz <dav...(a)webmaster.com> wrote:
> On May 21, 7:43 pm, papamms <ppmsn2...(a)gmail.com> wrote:
>
> > i run it under linux. from the blog linux actually support these
> > timeouts.
> > maybe my progarm send buff is full? and timeout didn't work?
>
> Why would you expect a perfectly healthy, 100% working connection to
> timeout, regardless of what you set the timeout values to? Again,
> these are *NOT* operation timeouts. They will not time out a perfectly
> good connection on any sane implementation.
>
> DS

you mean these are *NOT* operation timeouts.

so can you tell me what's that?

i had write some test code, and test it in lan. the connection is a
perfectly healthy, 100% working .

server work like this : accept connection and sleep, didn't recv any
data, let tcp's window full

client work like this: connect to server and send data again and
again, print the log

if i had set SO_SNDTIMEO,
client didn't hang on send(), send() will return ;

if i disable set SO_SNDTIMEO, cient will be hanged on send();

client log like this

send time time 1274671226 need send 10000 send 10000 sum send 10000
end time 1274671226 1 usetime 0
send time time 1274671226 need send 10000 send 5976 x <= -1 sum
send 5976 end time 1274671238 0 usetime 12
send time time 1274671238 need send 10000 x <= -1 sum send 0 end
time 1274671244 0 usetime 6
send time time 1274671244 need send 10000 x <= -1 sum send 0 end
time 1274671250 0 usetime 6








server code :


// Module Name: Server.c
//
// Description:
// This example illustrates a simple TCP server that accepts
// incoming client connections. Once a client connection is
// established, a thread is spawned to read data from the
// client and echo it back (if the echo option is not
// disabled).
//
// Compile:
// cl -o Server Server.c ws2_32.lib
//
// Command line options:
// server [-p:x] [-i:IP] [-o]
// -p:x Port number to listen on
// -i:str Interface to listen on
// -o Receive only, don't echo the data back
//
#include <winsock2.h>

#include <stdio.h>
#include <stdlib.h>

#define DEFAULT_PORT 8080
#define DEFAULT_BUFFER 4096

int iPort = DEFAULT_PORT; // Port to listen for clients on
BOOL bInterface = FALSE, // Listen on the specified interface
bRecvOnly = FALSE; // Receive data only; don't echo back
char szAddress[128]; // Interface to listen for clients on



//
// Function: ClientThread
//
// Description:
// This function is called as a thread, and it handles a given
// client connection. The parameter passed in is the socket
// handle returned from an accept() call. This function reads
// data from the client and writes it back.
//
DWORD WINAPI ClientThread(LPVOID lpParam)
{
SOCKET sock=(SOCKET)lpParam;
char szBuff[DEFAULT_BUFFER];
int ret,
nLeft,
idx;

while(1)
{
// Perform a blocking recv() call
//


::Sleep(1000);
continue;


}
return 0;
}

//
// Function: main
//
// Description:
// Main thread of execution. Initialize Winsock, parse the
// command line arguments, create the listening socket, bind
// to the local address, and wait for client connections.
//
int main(int argc, char **argv)
{
WSADATA wsd;
SOCKET sListen,
sClient;
int iAddrSize;
HANDLE hThread;
DWORD dwThreadId;
struct sockaddr_in local,
client;

if (WSAStartup(MAKEWORD(2,2), &wsd) != 0)
{
printf("Failed to load Winsock!\n");
return 1;
}
// Create our listening socket
//
sListen = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
if (sListen == SOCKET_ERROR)
{
printf("socket() failed: %d\n", WSAGetLastError());
return 1;
}
// Select the local interface and bind to it
//
if (bInterface)
{
local.sin_addr.s_addr = inet_addr(szAddress);
if (local.sin_addr.s_addr == INADDR_NONE)
return 0;
}
else
local.sin_addr.s_addr = htonl(INADDR_ANY);
local.sin_family = AF_INET;
local.sin_port = htons(iPort);

if (bind(sListen, (struct sockaddr *)&local,
sizeof(local)) == SOCKET_ERROR)
{
printf("bind() failed: %d\n", WSAGetLastError());
return 1;
}
listen(sListen, 8);
//
// In a continous loop, wait for incoming clients. Once one
// is detected, create a thread and pass the handle off to it.
//
while (1)
{
iAddrSize = sizeof(client);
sClient = accept(sListen, (struct sockaddr *)&client,
&iAddrSize);
if (sClient == INVALID_SOCKET)
{
printf("accept() failed: %d\n", WSAGetLastError());
break;
}
printf("Accepted client: %s:%d\n",
inet_ntoa(client.sin_addr), ntohs(client.sin_port));

hThread = CreateThread(NULL, 0, ClientThread,
(LPVOID)sClient, 0, &dwThreadId);
if (hThread == NULL)
{
printf("CreateThread() failed: %d\n", GetLastError());
break;
}
CloseHandle(hThread);
}
closesocket(sListen);

WSACleanup();
return 0;
}




client code like this:



#ifndef WIN32
# include <sys/epoll.h>
# include <sys/types.h>
# include <sys/socket.h>
# include <arpa/inet.h>
# include <netdb.h>
# include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <time.h>

#define SOCKET int
#define UINT32 unsigned int
#endif
#include <string>


bool WriteHttpRequest( SOCKET &sClient, const std::string &request);

bool SetSocket(SOCKET & sClient, UINT32 urecvout, UINT32 usendout);



bool WriteHttpRequest( SOCKET &sClient, const std::string &request)
{

int needsend = request.length();
int sended = 0;
int x;

printf(" need send %d ", needsend);

while (1)
{
x = send(sClient, request.c_str() + sended, needsend - sended ,
0);
if (x > 0)
{
printf(" send %d ", x);
fflush(stdout);
sended += x;
if (sended >= needsend)
{
printf(" sum send %d", sended);
return true;
}
}
else if (x <=0) {
printf(" x <= %d sum send %d ", x, sended);
fflush(stdout);
return false;
}
}
return false;// end while
}

bool SetSocket(SOCKET & sClient, UINT32 urecvout, UINT32 usendout)
{
int x;
UINT32 recvout = urecvout; //
UINT32 sndout = usendout; //
int len = recvout;



#ifndef WIN32
struct timeval tv;
tv.tv_usec = 0;
tv.tv_sec = urecvout /1000 +1;
x = setsockopt( sClient, SOL_SOCKET, SO_SNDTIMEO, &tv,
sizeof(tv));
printf( "setsockopt SO_RCVTIMEO %d\n",x);

tv.tv_sec = usendout /1000 +1;
x = setsockopt( sClient,SOL_SOCKET, SO_RCVTIMEO, &tv,
sizeof(tv));
printf( "setsockopt SO_SNDTIMEO %d\n",x);


#endif

return true;
}


int main()
{

int sClient;
int ports = 8080;
sClient = socket(AF_INET, SOCK_STREAM, 0);

struct sockaddr_in clientadd ={0};

memset(&clientadd, 0 , sizeof(clientadd));

clientadd.sin_addr.s_addr = inet_addr("192.168.1.1");
clientadd.sin_family = AF_INET;
clientadd.sin_port = htons(ports);

if (connect(sClient, (struct sockaddr *)&clientadd,
sizeof(clientadd)) == -1)

{
printf("connect fail");
return 0;
}
SetSocket(sClient, 5000, 25000);
std::string request(10000, 'a');
while (1)
{
int lasttime = time(NULL);
printf ("send time time %d ", lasttime);
bool result = WriteHttpRequest( sClient, request);
int timenow = time(NULL);

printf (" end time %d %d usetime %d\n", timenow, result, timenow -
lasttime);

}

return 0;
}












From: David Schwartz on
On May 23, 8:32 pm, papamms <ppmsn2...(a)gmail.com> wrote:

> you mean these are *NOT* operation timeouts.

Correct. They are *connection* timeouts. They timeout the connection
itself, not the particular operation on it.

> server work like this :  accept connection and sleep, didn't recv any
> data, let tcp's window full
>
> client work like this: connect to server and send data again and
> again,  print the log
>
> if  i had set SO_SNDTIMEO,
> client didn't hang on send(),  send() will return ;
>
> if i disable set SO_SNDTIMEO, cient will be hanged on send();

As a consequence of the connection itself timing out, the operation
timed out (since the operation is now impossible). However, since you
cannot rely on the connection timing out, you cannot rely on the
operation timing out as a consequence of it. In this case, what it
just happens to do is what you just happen to want. But you want to
time out the operation, not the connection. To get reliable behavior,
you need to use an operation timeout.

DS

From: David Schwartz on
On May 24, 10:14 pm, David Schwartz <dav...(a)webmaster.com> wrote:

> As a consequence of the connection itself timing out, the operation
> timed out (since the operation is now impossible). However, since you
> cannot rely on the connection timing out, you cannot rely on the
> operation timing out as a consequence of it. In this case, what it
> just happens to do is what you just happen to want. But you want to
> time out the operation, not the connection. To get reliable behavior,
> you need to use an operation timeout.

For example, see this link:
http://msdn.microsoft.com/en-us/library/ms740476%28VS.85%29.aspx

Note that it says: "If a send or receive operation times out on a
socket, the socket state is indeterminate, and should not be used; TCP
sockets in this state have a potential for data loss, since the
operation could be canceled at the same moment the operation was to be
completed."

That is, once a send or receive times out, the *CONNECTION* is dead. I
don't recommend using these "timeouts" because they are sort of
operation timeouts and sort of connection timeouts.

DS