LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   send() recv() used multiple times fail (https://www.linuxquestions.org/questions/programming-9/send-recv-used-multiple-times-fail-703705/)

Jane2008 02-10-2009 03:24 PM

send() recv() used multiple times fail
 
The send() and recv() are used multiple times to communicate two machines. But it only works for the first time. After that the data returned from recv() remains the same.
Here are parts of the codes.

sd = socket( PF_INET, SOCK_STREAM, protocol->p_proto );
if ( sd == -1 )
{
perror( "socket()" );
return (errno);
}
memset( &socketaddr, 0, sizeof(socketaddr) );
socketaddr.sin_family = AF_INET;
socketaddr.sin_port = htons( port );

memcpy( &socketaddr.sin_addr, hostaddr->h_addr, hostaddr->h_length );
rval = connect( sd, (struct sockaddr *) &socketaddr, sizeof(socketaddr) );
if ( rval == -1 )
{
perror( "connect()" );
return (errno);
}

scanf("%d", &choice);
while(choice)
{
rval = send(sd, commands[choice], strlen(commands[choice], 0);
...
rval = recv( sd, buffer, sizeof(buffer), 0 );
if ( rval == -1 )
{
perror( "recv()" );
}
else
{ printf("%s\n", buffer); }
scanf("%d", &choice);
}
close( sd );
return (0);

j-osh 02-10-2009 07:37 PM

Could be multiple things...I usually start by printing out the buffers right before I send it and right after I receive it to make sure they are the same. Print out the length of the buffer to make sure it is the same value you are passing send.

how do you define commands[] or rather what type is it?

ta0kira 02-10-2009 08:13 PM

Try shutdown(sd, SHUT_RDWR); instead of close(sd); and see what happens. Also, it could be in the server code.
ta0kira

PS If the server reads until EOF, it might be blocking waiting for the socket to be shut down (close doesn't actually destroy the connection); therefore it might not actually get back to the accept call.

ta0kira 02-10-2009 08:13 PM

(it posted twice)

j-osh 02-11-2009 12:37 AM

Sorry I am not sure the shutdown command is needed here...I have never closed a socket any other way than close(socket_fd).

Since the full code isn't given it is hard to say but maybe the loop isn't incrementing the pointer/variable. Maybe the memory in the buffers aren't being handled correctly. But since you say that at least the first command transfers correctly that your sockets might not be the problem. For debugging just put in a lot of printf statement or use gdb to debug. If you feel the issues are with socket programming either google "Beej's guide to network programming" or check out a copy of the steven's unix network programming book from the library. If you think the network or sockets are not actually sending the packets then wireshark could be your best friend for debugging such an issues.

dwhitney67 02-11-2009 06:40 AM

I agree with j-osh. Without seeing the full code, it is hard to determine where the problem lies.

@ Jane2008 -

How have you declared 'buffer'? Are you initializing it with nulls before using it?

With respect to your socket, is it setup as non-blocking?

Be aware that when a message is sent via a TCP socket, it is possible that the message may not arrive in one packet; it may be provided in multiple packets, depending on the size of the message.

How do you determine that you have received a complete message? Are the messages newline-terminated, or does it consist of a fixed-length of data? If you are expecting lots of individual messages, you may need to perform I/O buffering of the data that is received, and then pluck out individual messages, when say, a newline is detected.

Consider the following (which I have not tested):
PHP Code:

...

// send data...

// receive response
fd_set savefds;
FD_ZERO(&savefds);
FD_SET(sd, &savefds);

char buffer[1024] = {0};
int bytesRcvd 0;

while (
bytesRcvd sizeof(buffer) - 1)
{
  
fd_set readfds savefds;
  
struct timeval timeout = {10};  // one second (arbitrarily chosen)

  // don't attempt to read unless there is data present on the socket
  
if (select(sd 1, &readfds00, &timeout) <= 0)
  {
    break;
  }

  
// ok, data detected; let's read
  
int rdStat read(sdbuffer bytesRcvdsizeof(buffer) - bytesRcvd 10);

  if (
rdStat 0)  bytesRcvd += rdStat;
}

if (
bytesRcvd 0)
{
  
printf("%s"buffer);
}

... 


wje_lq 02-11-2009 08:04 AM

Quote:

Are you initializing [the buffer] with nulls before using it?
Generally it serves no purpose to do this.

dwhitney67 02-11-2009 08:14 AM

Quote:

Originally Posted by wje_lq (Post 3439638)
Generally it serves no purpose to do this.

You are right, except of course when the data expected is a string. It's nice to have a null terminated buffer. Of course one can manually add a null to terminate the buffer after the data has been received.

Initializing the buffer to all nulls, as I have shown in my example, was not a big effort. In fact, it is wise to always initialize variables (when they are declared).

Jane2008 02-11-2009 09:09 AM

Thanks. Here are the full codes.
#include <errno.h>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

extern int errno;
extern int h_errno;

int main(int argc, char **argv)
{
int port = 8080;
struct protoent *protocol;
int rval;
int sd;
struct sockaddr_in socketaddr;
char *ptr ="192.168.0.100";
char *message = "$U";
char *commands[]={"\0", "$U", "$T", "%U", "%T", "#U", "#T", "#F","#D", "#S"};
// Initialize the buffer but seems no use, the data in buffer remains same
char response[1024]={0};
int choice;

/* Choose what protocol is used */
protocol = getprotobyname( "tcp" );
if ( !protocol )
{
perror( "getprotobyname()" );
return (errno);
}
printf("TCP is supportable!\n");

/* Create socket */
sd = socket( PF_INET, SOCK_STREAM, protocol->p_proto );
if ( sd == -1 )
{
perror( "socket()" );
return (errno);
}
printf("The socket is created successfully.\n");

/* Setup info about the remote host*/
memset( &socketaddr, 0, sizeof(socketaddr) );

socketaddr.sin_family = AF_INET;
socketaddr.sin_port = htons(port);
socketaddr.sin_addr.s_addr = inet_addr(ptr);

/* Connect to the host*/
rval = connect( sd, (struct sockaddr *) &socketaddr, sizeof(socketaddr) );
if ( rval == -1 )
{
perror( "connect()" );
return (errno);
}
printf("Connect successfully!\n");

/* Now that we're connected, we can send and receive all we want.
* I've decided to use this example as a means of simply grabbing
* whatever banner the server sends us and sending it to stdout.
*/
printf("Please choose the operation:\n");
printf("1. Read voltage configuration\n");
printf("2. Read temperature & fan configuration\n");
printf("3. Write voltage configuration\n");
printf("4. Write temperature & fan configuration\n");
printf("5. Read voltage data\n");
printf("6. Read temperature data\n");
printf("7. Read fan revolution data\n");
printf("8. Read switch status\n");
printf("9. Read system monitor status\n");
printf("0. Exit\n");

scanf("%d", &choice);

while(choice !=0 && choice>=0 && choice<=9)
{
printf("%s\n", commands[choice]);
rval = send(sd, commands[choice], strlen(commands[choice]), 0);
if( rval == -1)
{
perror("send()");
return(errno);

}

rval = recv( sd, response, sizeof(response), 0 );
if ( rval == -1 )
{
perror( "recv()" );
return(errno);
}
else
{
printf("The temperature is: %s\n", response);
}
scanf("%d", &choice);
}

close( sd );
shutdown(sd, SHUT_RDWR);
return (0);
}

Jane2008 02-11-2009 09:25 AM

The printf sentence indicated that the command is changed with the option I choosed. But the data returned by recv() still remains the same.

dwhitney67 02-11-2009 10:09 AM

I tested your client application with my server application. The only modifications I did to your app was to change the port number, the IP address, and I inserted a '\n' character at the end of each of the command strings. The latter modification was to satisfy my server's message protocol requirements.

Anyhow, your application worked, albeit my server was sending back a small message (the number of characters received).

Because you have stated that your client application is not working as expected, I would recommend that you look into two areas:

1. Ensure that your client app has the correct message protocol to talk to the server (i.e. check your command strings).

2. Check that the server is receiving your client's messages correctly, and is responding correctly.

P.S. Your client application outputs the same string ("The temperature is: ...", regardless of the choice selected. For example:
Code:

...

7. Read fan revolution data
8. Read switch status
9. Read system monitor status
0. Exit
1
$U

The temperature is: Msg of 3 bytes received.

2
$T

The temperature is: Msg of 3 bytes received.

3
%U

The temperature is: Msg of 3 bytes received.

4
%T

The temperature is: Msg of 3 bytes received.

5
#U

The temperature is: Msg of 3 bytes received.

6
#T

The temperature is: Msg of 3 bytes received.

7
#F

The temperature is: Msg of 3 bytes received.

8
#D

The temperature is: Msg of 3 bytes received.

9
#S

The temperature is: Msg of 3 bytes received.


Jane2008 02-11-2009 10:33 AM

Thanks. The protocol is OK otherwise I will not receive data from it and the server can receive client's messages correctly. If 1 is entered first, the volt data is received. If 2 is entered first, the corresponding data is received. ...
But the problem is when entered 2(or other) after 1, the returned data is volt data.
Do you noticed that whatever option you entered, the buffer returns the same message "Msg of 3 bytes received". I think the data in your buffer is still same.

Because you have stated that your client application is not working as expected, I would recommend that you look into two areas:

1. Ensure that your client app has the correct message protocol to talk to the server (i.e. check your command strings).

2. Check that the server is receiving your client's messages correctly, and is responding correctly.

P.S. Your client application outputs the same string ("The temperature is: ...", regardless of the choice selected. For example:
Code:

...

1
$U

The temperature is: Msg of 3 bytes received.

2
$T

The temperature is: Msg of 3 bytes received.

3
%U

The temperature is: Msg of 3 bytes received.

4
%T

The temperature is: Msg of 3 bytes received.

5
#U

The temperature is: Msg of 3 bytes received.

6
#T

The temperature is: Msg of 3 bytes received.

7
#F

The temperature is: Msg of 3 bytes received.

8
#D

The temperature is: Msg of 3 bytes received.

9
#S

The temperature is: Msg of 3 bytes received.

[/QUOTE]

Jane2008 02-11-2009 10:34 AM

Thanks. The protocol is OK otherwise I will not receive data from it and the server can receive client's messages correctly. If 1 is entered first, the volt data is received. If 2 is entered first, the corresponding data is received. ...
But the problem is when entered 2(or other) after 1, the returned data is volt data.
Do you noticed that whatever option you entered, the buffer returns the same message "Msg of 3 bytes received". I think the data in your buffer is still same.
Quote:

Originally Posted by Jane2008 (Post 3439780)
Because you have stated that your client application is not working as expected, I would recommend that you look into two areas:

1. Ensure that your client app has the correct message protocol to talk to the server (i.e. check your command strings).

2. Check that the server is receiving your client's messages correctly, and is responding correctly.

P.S. Your client application outputs the same string ("The temperature is: ...", regardless of the choice selected. For example:
Code:

...

1
$U

The temperature is: Msg of 3 bytes received.

2
$T

The temperature is: Msg of 3 bytes received.

3
%U

The temperature is: Msg of 3 bytes received.

4
%T

The temperature is: Msg of 3 bytes received.

5
#U

The temperature is: Msg of 3 bytes received.

6
#T

The temperature is: Msg of 3 bytes received.

7
#F

The temperature is: Msg of 3 bytes received.

8
#D

The temperature is: Msg of 3 bytes received.

9
#S

The temperature is: Msg of 3 bytes received.


[/QUOTE]

dwhitney67 02-11-2009 12:51 PM

Pay no attention to the output I provided earlier; my server responds back with the same response everytime and includes the number of bytes received, which was 3 (e.g. "#U\n");

Here's the output when I modified my server to echo the string that was sent to it. Note that I removed the '\n' characters from the printf() statements from your client application so that I would not output two newlines.
Code:

$ ./a.out
TCP is supportable!
The socket is created successfully.
Connect successfully!
Please choose the operation:
1. Read voltage configuration
2. Read temperature & fan configuration
3. Write voltage configuration
4. Write temperature & fan configuration
5. Read voltage data
6. Read temperature data
7. Read fan revolution data
8. Read switch status
9. Read system monitor status
0. Exit
1
$U
The temperature is: Server received: $U
2
$T
The temperature is: Server received: $T
3
%U
The temperature is: Server received: %U
4
%T
The temperature is: Server received: %T
5
#U
The temperature is: Server received: #U
6
#T
The temperature is: Server received: #T
7
#F
The temperature is: Server received: #F
8
#D
The temperature is: Server received: #D
9
#S
The temperature is: Server received: #S
10
$

Anyhow, I'm certain the problematic issues with your client application are because of one or more of the following:

1) The client application is not following the correct messaging protocol, or
2) The server is not handling the incoming messages as expected, or
3) The server is not responding properly.

Please examine each of the possibilities above before you think of anything else!

Jane2008 02-13-2009 08:49 AM

Thanks.
I found that the client application only supports one time communication. That is, once connected, only one send and recv can be used to get the message. After that, you have to connect again.
I modified the codes as follows. First choose the option, then connect, send, recv, close finally. But the close() and shutdown() doesn't work.

char* io_operation(char* commands)
{
int rval;
int sd;
struct sockaddr_in socketaddr;
struct protoent *protocol;
int port = 8080;
char *ptr ="192.168.0.100";
static char response[1024];

/* Choose what protocol is used */
protocol = getprotobyname( "tcp" );
if ( !protocol )
{
perror( "getprotobyname()" );
// return (errno);
}

/* Create socket */
sd = socket( PF_INET, SOCK_STREAM, protocol->p_proto );
if ( sd == -1 )
{
perror( "socket()" );
// return (errno);
}

/* Setup info about the remote host*/
memset( &socketaddr, 0, sizeof(socketaddr) );

socketaddr.sin_family = AF_INET;
socketaddr.sin_port = htons(port);
socketaddr.sin_addr.s_addr = inet_addr(ptr);

/* Connect to the host*/
rval = connect( sd, (struct sockaddr *) &socketaddr, sizeof(socketaddr) );
if ( rval == -1 )
{
perror( "connect()" );
// return (errno);
}

/* Now that we're connected, we can send and receive all we want.
* I've decided to use this example as a means of simply grabbing
* whatever banner the server sends us and sending it to stdout.
*/
/* Send the commands to the module */
rval = send(sd, commands, strlen(commands), 0);
if( rval == -1)
{
perror("send()");
// return(errno);
}
/* Receive messages sent from module */
rval = recv( sd, response, sizeof(response), 0 );
if ( rval == -1 )
{
perror( "recv()" );
// return(errno);
}
else
{
printf("%s\n",response);
}

/* Shut down the socket */
close( sd );
shutdown(sd, SHUT_RDWR);
return response;
}
int main(int argc, char **argv)
{
int choice;
char commands[1024]={0};
char response[1024]={0};
char strcommand[100]={0};

/* Print the operation option */
printf("Please choose the operation:\n");
printf("1. Read voltage configuration\n");
printf("2. Read temperature & fan configuration\n");
printf("3. Write voltage configuration\n");
printf("4. Write temperature & fan configuration\n");
printf("5. Read voltage data\n");
printf("6. Read temperature data\n");
printf("7. Read fan revolution data\n");
printf("8. Read switch status\n");
printf("9. Read system monitor status\n");
printf("0. Exit\n");

scanf("%d", &choice);

while(choice !=0 && choice>=0 && choice<=9)
{
switch(choice)
{
case 1:
strcpy(commands,"$U");
strcpy(response,io_operation(commands));
break;

case 2:
strcpy(commands,"$T");
strcpy(response,io_operation(commands));
break;

...

case 9:
strcpy(commands,"#S");
strcpy(response,io_operation(commands));
break;

default:
break;
}
scanf("%d", &choice);
}
return (0);
}


All times are GMT -5. The time now is 03:26 PM.