I have tried to use the SOAP_IO_KEEPALIVE flag to send
up to 1000000 char values from a client to a server.
The behaviour is strange. Some times the client gets a
"broken pipe" and often the soap client error is
"TCP socket failed in tcp_connect()".
It Seems from the code that the "soap__ns_send...()"
calls the tcp_connect many times when accordig to the
the keep alive
flag it should call it once.
Here are the client and server interesting pieces code
(you can use it for testing pourposes), also with the
test.h header.
Client :
--------------------------------------------------------------------------------------------------
soap_init2(&soap, SOAP_IO_KEEPALIVE, SOAP_IO_KEEPALIVE);
for(int i=0; i<1000000; i++) {
char c='\0';
if (!res = soap_send_ns__sendChar(&soap, server,
NULL, c)) {
soap_print_fault(&soap, stdout);
exit(1);
}
if(res!=SOAP_OK) {
soap_print_fault(&soap, stdout);
exit(1);
}
if (soap.error) soap_print_fault(&soap, stdout);
}
--------------------------------------------------------------------------------------------------
Server:
--------------------------------------------------------------------------------------------------
soap_init2(&soap, SOAP_IO_CHUNK|SOAP_IO_KEEPALIVE,
SOAP_IO_CHUNK|SOAP_IO_KEEPALIVE);
soap.accept_timeout = TIMEOUT;
soap.bind_flags |= SO_REUSEADDR;
m = soap_bind(&soap, NULL, port, BACKLOG);
if (m < 0) {
soap_print_fault(&soap, stderr);
exit(1);
}
for (;;) {
soap_accept(&soap);
cerr << ":DONE" << endl;
for (int i=0, times=0; i<atoi(argv[2]); i++, times++){
res = soap_recv_ns__sendChar(&soap, &c);
if (res == SOAP_OK) {
cerr << "Received message " << times << endl ;
} else {
soap_print_fault(&soap, stderr);
exit(1);
}
}
cerr << "exiting" << endl;
}
--------------------------------------------------------------------------------------------------
test.h :
--------------------------------------------------------------------------------------------------
//gsoap ns service name: test
//gsoap ns service style: rpc
//gsoap ns service encoding: encoded
//gsoap ns service location: http://c6:18000
//gsoap ns schema namespace: urn:test
int ns__sendChar(assist_char c, void);
--------------------------------------------------------------------------------------------------
Thanks for interest.
Logged In: YES
user_id=1063105
To my mind, you have exactelly the same problem that i
described in the case 972535.
You can try my patch :
-) create a the following soap_poll2 fonction in stdsoap2.c[pp]:
#ifndef MAC_CARBON
#ifndef PALM_1
SOAP_FMAC1
int
SOAP_FMAC2
soap_poll2(struct soap * soap)
{
#ifndef WITH_LEAN
struct timeval timeout;
fd_set sfd,rfd;
int r;
timeout.tv_sec = 0;
timeout.tv_usec = 0;
FD_ZERO(&rfd);
FD_ZERO(&sfd);
if (soap->socket >= 0)
{ FD_SET(soap->socket, &rfd);
FD_SET(soap->socket, &sfd);
r = select(soap->socket + 1, &rfd, &sfd, NULL, &timeout);
}
else if (soap->master >= 0)
{ FD_SET(soap->master, &rfd);
r = select(soap->master + 1, &rfd, &sfd, NULL, &timeout);
}
else
{ FD_SET(soap->sendfd, &sfd);
FD_SET(soap->recvfd, &rfd);
r = select((soap->sendfd > soap->recvfd ? soap->sendfd :
soap->recvfd) + 1, &rfd, &sfd, NULL, &timeout);
}
if (r > 0)
{
#ifdef WITH_OPENSSL
if (soap->ssl)
{ if ((soap->socket >= 0) && FD_ISSET(soap->socket, &rfd))
{ char buf = '\0';
if (SSL_peek(soap->ssl, &buf, 1) <= 0)
return SOAP_EOF;
}
}
#endif
if ((soap->socket >= 0 && FD_ISSET(soap->socket, &rfd))
|| (soap->recvfd >= 0 && FD_ISSET(soap->recvfd, &rfd)) ) {
// On ne devrait rien avoir a lire , si c'est le cas
il s'agit d'un EOF
// Il faut alors se reconnecter
return SOAP_EOF;
}
return SOAP_OK;
}
if (r < 0 && (soap_valid_socket(soap->master) ||
soap_valid_socket(soap->socket)) && soap_socket_errno !=
SOAP_EINTR)
{ soap->errnum = soap_socket_errno;
soap_set_receiver_error(soap, tcp_error(soap), "select
failed in soap_poll()", SOAP_TCP_ERROR);
return soap->error = SOAP_TCP_ERROR;
}
else
soap->errnum = soap_errno;
return SOAP_EOF;
#else
return SOAP_OK;
#endif
}
#endif
#endif
-) modify the soap_connect_command() function to call
soap_poll2 and
to have keepalive again for the new connection :
if (*soap->host)
{ soap->status = http_command;
if (!soap_valid_socket(soap->socket) ||
strcmp(soap->host, host) || soap->port != port)
{ soap->keep_alive = 0; /* force close */
soap_closesock(soap);
DBGLOG(TEST,SOAP_MESSAGE(fdebug, "Connect to
host='%s' path='%s' port=%d\n", soap->host, soap->path,
soap->port));
soap->socket = soap->fopen(soap,
endpoint,soap->host, soap->port);
if (soap->error)
return soap->error;
soap->keep_alive = ((soap->omode &
SOAP_IO_KEEPALIVE) != 0);
}
// call soap_poll2 instead of soap_poll
else if (!soap->keep_alive || soap_poll2(soap))
{ soap->keep_alive = 0; /* force close */
soap_closesock(soap);
DBGLOG(TEST,SOAP_MESSAGE(fdebug, "Reconnect to
host='%s' path='%s' port=%d\n", soap->host, soap->path,
soap->port));
soap->socket = soap->fopen(soap, endpoint,
soap->host, soap->port);
if (soap->error)
return soap->error;
// Set keepalive again
soap->keep_alive = ((soap->omode &
SOAP_IO_KEEPALIVE) != 0);
}
}
Logged In: YES
user_id=1063105
May i have your feedback ?
Thanks.
Logged In: NO
Sorry for answering so late.
Your patch seems to work but i had to write a different
server code that
calls the "accept" more times. infact sfter some packets the
server seems to get a "connection timesd out".
The problem still remains in the client that instead of
opening only one socket (as the IO_KEEP_ALIVE should do)
it opens many sockets. (if i send 10000000 packets i get a
socket connect refused because all ports are in use).
Here is the interesting part of the Server code :
for (;;) {
done = 0;
soap_accept(&soap);
fprintf(stderr, "Connect :: Again\n %d", soap.recvfd);
while(!done) {
struct ns__sendChar msg;
res = soap_recv_ns__sendChar(&soap, &msg);
if (res == SOAP_OK) {
fprintf(stderr, "Received message %d : %d\n", msg.c.item,
msg.c.data);
if (msg.c.item == (streamlen-1)) {
done=1;
}
} else {
soap_print_fault(&soap, stderr);
break;
}
}
}
Yhe client still remain the same.
Than you for you time.
Logged In: YES
user_id=918756
Sorry for answering so late.
Your patch seems to work but i had to write a different
server code that
calls the "accept" more times. infact sfter some packets the
server seems to get a "connection timesd out".
The problem still remains in the client that instead of
opening only one socket (as the IO_KEEP_ALIVE should do)
it opens many sockets. (if i send 10000000 packets i get a
socket connect refused because all ports are in use).
Here is the interesting part of the Server code :
for (;;) {
done = 0;
soap_accept(&soap);
fprintf(stderr, "Connect :: Again\n %d", soap.recvfd);
while(!done) {
struct ns__sendChar msg;
res = soap_recv_ns__sendChar(&soap, &msg);
if (res == SOAP_OK) {
fprintf(stderr, "Received message %d : %d\n", msg.c.item,
msg.c.data);
if (msg.c.item == (streamlen-1)) {
done=1;
}
} else {
soap_print_fault(&soap, stderr);
break;
}
}
}
Yhe client still remain the same.
Than you for you time.
Logged In: YES
user_id=1063105
Hi
I have tested my patch only for the client side (I am using
a GLUE server).
In my case, the client build with GSOAP 2.6 uses only 1
socket until the server shutdown the connection.
In that case, my patch makes that the client reconnects
automatically instead of failing in the first request that
follows.
So I am wondering that your client uses hundred's of socket.
Did you select http version 1.1 ?
With your test program, how many times did you have a
"Connect :: Again" messages ?
If you have the strace (Linux) or truss (Solaris, ...)
command could you have a look on your client and server
process to see who close the socket ?
Note : In my client, i use a connect, send and recv timeout
different than 0 (the default is 0 which means no timeout)
Logged In: NO
Hi again.
Peraphs we have found the issue.
We achieved to have working client and server without
applying your patch.
The point is that in the soap_poll() function the select
goes in timeout.
We just raised the time out value (for example 2 seconds)
and all things
began to work.
Let me know if this work also for your problem.
Regards.
Logged In: YES
user_id=1063105
Just one thing on my patch. It is tested only for the client
(because i don't use the server) and it may have side effect
on the server.
However, if you now run again your test as follow :
send 10 request, sleep enough time to have your server that
shutdown the socket (or stop/start the server) send 2 more
request.
If you do that, you may see (i have that on my computer)
that the first request after the stop/start fails.
Then, if you apply my patch ONLY for the client and do again
the same test, everything will be OK.
Logged In: YES
user_id=354274
The gSOAP server implements a fairness policy that limits the length of
the keep-alive session to 100 calls, thereby forcing clients to reconnect.
The soap->max_keep_alive value can be changed after soap_init().
The fairness policy forbids clients to gain exclusive access to the server.
Note that all web servers limit the keep alive session's length.
Setting soap->max_keep_alive resolves this issue.
In addition, the soap_poll() algorithm will be modified for gSOAP 2.7.1.
I'd be happy to receive comments when you have a chance to look at
gSOAP 2.7.1 to be released by the end of March 2005.