|
Home > Archive > Unix Programming > May 2007 > Problems with network sockets
You are viewing an archived Text-only version of the thread.
To view this thread in it's original format and/or if you want to reply to
this thread please [click here]
| Author |
Problems with network sockets
|
|
| Andrew Falanga 2007-05-23, 7:20 pm |
| Hi,
I have a program that is going to be sending log information and
program state information to a remote host. The manner for
communication is TCP and I'm opening different sockets for the log
information and program state information.
In the case of the program state information, the process is that the
program will make a connection to the remote host, send a string "STF-
SEND" indicating to the remote host that contents of a state file are
about to be transferred, and it then waits for the response from the
remote host in the form of another string "STF-READY."
Using telnet I've verified that the remote host does, indeed, send the
response string in its entirety, i.e. "STF-READY"; however, on the
local side, using my program instead of telnet, all I get is "STF-".
A skeleton version of what I'm doing is this (I'm using C++):
// all preparation has been completed, structures filled and the
connection made
// a socket has been opened and its descriptor is in the variable "sd"
send( sd, "STF-SEND", 8, 0 );
fd_set fds;
struct timeval to;
char msg[256];
char pPart = msg;
int bytesRead = 0;
FS_SET( sd, &fds );
to.tv_sec = 10;
to.tv_usec = 0;
while( 1 ) {
switch( select( sd, &fds, NULL, NULL, &to ) ) {
case -1:
throw Fail( "error occurred in select" );
case 0:
throw Fail( "timeout occurred" );
}
bytesRead += recv( sd, pPart, 256, 0 );
if( bytesRead < strlen( "STF-READY" ) ) {
#ifdef DEBUG
std::cout << "Received a partial message" << std::endl;
std::cout << "Contents of buffer:" << std::endl;
for( int i=0; i < strlen( "STF-READY" ); i++ )
std::cout << msg[i];
std::cout << std::endl;
#endif
pPart += bytesRead;
FD_ZERO( &fds );
FD_SET( sd, &fds );
continue;
}
}
Using this code, I read in the "STF-" part of the "STF-READY" response
string. However, I continually timeout waiting for more data to
become available. What would I want to look at for reasons why?
I'm not reconfiguring the socket in any way using fcntl. Should I,
perhaps, make the socket non-blocking? I'm just completely drawing a
blank as to why I'm not reading the entire string "STF-READY"
Thanks for any help,
Andy
| |
| Eric Sosman 2007-05-23, 7:20 pm |
| Andrew Falanga wrote On 05/23/07 17:22,:
> Hi,
>
> I have a program that is going to be sending log information and
> program state information to a remote host. The manner for
> communication is TCP and I'm opening different sockets for the log
> information and program state information.
>
> In the case of the program state information, the process is that the
> program will make a connection to the remote host, send a string "STF-
> SEND" indicating to the remote host that contents of a state file are
> about to be transferred, and it then waits for the response from the
> remote host in the form of another string "STF-READY."
>
> Using telnet I've verified that the remote host does, indeed, send the
> response string in its entirety, i.e. "STF-READY"; however, on the
> local side, using my program instead of telnet, all I get is "STF-".
>
> A skeleton version of what I'm doing is this (I'm using C++):
>
> // all preparation has been completed, structures filled and the
> connection made
> // a socket has been opened and its descriptor is in the variable "sd"
>
> send( sd, "STF-SEND", 8, 0 );
>
> fd_set fds;
> struct timeval to;
> char msg[256];
> char pPart = msg;
> int bytesRead = 0;
>
> FS_SET( sd, &fds );
> to.tv_sec = 10;
> to.tv_usec = 0;
>
> while( 1 ) {
> switch( select( sd, &fds, NULL, NULL, &to ) ) {
> case -1:
> throw Fail( "error occurred in select" );
>
> case 0:
> throw Fail( "timeout occurred" );
> }
>
> bytesRead += recv( sd, pPart, 256, 0 );
> if( bytesRead < strlen( "STF-READY" ) ) {
> #ifdef DEBUG
> std::cout << "Received a partial message" << std::endl;
> std::cout << "Contents of buffer:" << std::endl;
> for( int i=0; i < strlen( "STF-READY" ); i++ )
> std::cout << msg[i];
> std::cout << std::endl;
> #endif
> pPart += bytesRead;
> FD_ZERO( &fds );
> FD_SET( sd, &fds );
>
> continue;
> }
> }
>
> Using this code, I read in the "STF-" part of the "STF-READY" response
> string. However, I continually timeout waiting for more data to
> become available. What would I want to look at for reasons why?
>
> I'm not reconfiguring the socket in any way using fcntl. Should I,
> perhaps, make the socket non-blocking? I'm just completely drawing a
> blank as to why I'm not reading the entire string "STF-READY"
Not certain, but two things to look at:
- Shouldn't the first argument to select() be sd+1
instead of plain sd? You may be timing out because
you're ignoring the very socket you care about ...
- The buffer length in recv() is wrong after a partial
read. Once you've received twenty bytes, you no
longer have 256 empty spaces in the buffer ...
--
Eric.Sosman@sun.com
| |
| Karl Malbrain 2007-05-23, 7:20 pm |
| "Eric Sosman" <Eric.Sosman@sun.com> wrote in message
news:1179956724.292850@news1nwk...
> Andrew Falanga wrote On 05/23/07 17:22,:
>
> Not certain, but two things to look at:
>
> - Shouldn't the first argument to select() be sd+1
> instead of plain sd? You may be timing out because
> you're ignoring the very socket you care about ...
>
> - The buffer length in recv() is wrong after a partial
> read. Once you've received twenty bytes, you no
> longer have 256 empty spaces in the buffer ...
Also you have two usages of your bytesRead variable -- one is cumulative the
other is the transactional.
karl m
| |
| Rainer Weikusat 2007-05-24, 7:20 am |
| Andrew Falanga <af300wsm@gmail.com> writes:
[...]
> fd_set fds;
> struct timeval to;
> char msg[256];
> char pPart = msg;
> int bytesRead = 0;
>
> FS_SET( sd, &fds );
> to.tv_sec = 10;
> to.tv_usec = 0;
In 9.5 out of 10[*] cases, using arbitrary timeouts for TCP-communication
will have no effect except causing spurious communication failures.
[*] The remaining 0.5 case is if it is possible that
internet-visible source address of the TCP-connection can
change suddenly and the device directly connected to the
internet is using Linux (or another kernel with similar
behaviour). The kernel will completely ignored this and the
TCP-connection will 'hang' for a long time. The (IMO) correct
way for the kernel to handle this would be to kill
locally-originated TCP connections immediatly and to RST
others upon attempt of sending something. I once implemented
this for 2.2 and have halfway implemented this for 2.4 (w/o
the 'terminate LAB originated'-part). The System and Software
Theft Company used to have a fairly brain-damaged kernel patch
doing something similar with the nice property of addtionally
killing totally internal connections every once in a while, in
the great tradition of "their fine engineering" ... (yes, this
is useless. Users love brand names and want to be screwed
by overgraduates).
> while( 1 ) {
> switch( select( sd, &fds, NULL, NULL, &to ) ) {
This should be sd + 1
> case -1:
> throw Fail( "error occurred in select" );
>
> case 0:
> throw Fail( "timeout occurred" );
> }
>
> bytesRead += recv( sd, pPart, 256, 0 );
In case of an error, this will decrement bytesRead by one.
> if( bytesRead < strlen( "STF-READY" ) ) {
The result of 'strlen("STF-READY")' is the same as the compile time
constant 'sizeof("STF-READY") - 1'. The compiler you are using may or
may not replace the subroutine call with this expression.
> #ifdef DEBUG
> std::cout << "Received a partial message" << std::endl;
> std::cout << "Contents of buffer:" << std::endl;
> for( int i=0; i < strlen( "STF-READY" ); i++ )
This should probably be 'bytesRead'. A much simpler way:
msg[byteRead] = 0;
cout << msg << std::endl;
> std::cout << msg[i];
> std::cout << std::endl;
> #endif
> pPart += bytesRead;
> FD_ZERO( &fds );
> FD_SET( sd, &fds );
> continue;
> }
If you ever arrive here, 'bytesRead' should likely be set to zero.
|
|
|
|
|