LinuxQuestions.org
Share your knowledge at the LQ Wiki.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 02-10-2009, 03:24 PM   #1
Jane2008
Member
 
Registered: Oct 2008
Posts: 36

Rep: Reputation: 15
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);
 
Old 02-10-2009, 07:37 PM   #2
j-osh
Member
 
Registered: Nov 2008
Location: Madison, WI
Posts: 34

Rep: Reputation: 16
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?
 
Old 02-10-2009, 08:13 PM   #3
ta0kira
Senior Member
 
Registered: Sep 2004
Distribution: FreeBSD 9.1, Kubuntu 12.10
Posts: 3,078

Rep: Reputation: Disabled
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.

Last edited by ta0kira; 02-10-2009 at 08:17 PM.
 
Old 02-10-2009, 08:13 PM   #4
ta0kira
Senior Member
 
Registered: Sep 2004
Distribution: FreeBSD 9.1, Kubuntu 12.10
Posts: 3,078

Rep: Reputation: Disabled
(it posted twice)

Last edited by ta0kira; 02-10-2009 at 08:15 PM.
 
Old 02-11-2009, 12:37 AM   #5
j-osh
Member
 
Registered: Nov 2008
Location: Madison, WI
Posts: 34

Rep: Reputation: 16
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.
 
Old 02-11-2009, 06:40 AM   #6
dwhitney67
Senior Member
 
Registered: Jun 2006
Location: Maryland
Distribution: Kubuntu, Fedora, RHEL
Posts: 1,541

Rep: Reputation: 335Reputation: 335Reputation: 335Reputation: 335
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);
}

... 

Last edited by dwhitney67; 02-11-2009 at 06:44 AM.
 
Old 02-11-2009, 08:04 AM   #7
wje_lq
Member
 
Registered: Sep 2007
Location: Mariposa
Distribution: FreeBSD,Debian wheezy
Posts: 811

Rep: Reputation: 179Reputation: 179
Quote:
Are you initializing [the buffer] with nulls before using it?
Generally it serves no purpose to do this.
 
Old 02-11-2009, 08:14 AM   #8
dwhitney67
Senior Member
 
Registered: Jun 2006
Location: Maryland
Distribution: Kubuntu, Fedora, RHEL
Posts: 1,541

Rep: Reputation: 335Reputation: 335Reputation: 335Reputation: 335
Quote:
Originally Posted by wje_lq View Post
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).
 
Old 02-11-2009, 09:09 AM   #9
Jane2008
Member
 
Registered: Oct 2008
Posts: 36

Original Poster
Rep: Reputation: 15
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);
}

Last edited by Jane2008; 02-11-2009 at 09:19 AM.
 
Old 02-11-2009, 09:25 AM   #10
Jane2008
Member
 
Registered: Oct 2008
Posts: 36

Original Poster
Rep: Reputation: 15
The printf sentence indicated that the command is changed with the option I choosed. But the data returned by recv() still remains the same.
 
Old 02-11-2009, 10:09 AM   #11
dwhitney67
Senior Member
 
Registered: Jun 2006
Location: Maryland
Distribution: Kubuntu, Fedora, RHEL
Posts: 1,541

Rep: Reputation: 335Reputation: 335Reputation: 335Reputation: 335
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.
 
Old 02-11-2009, 10:33 AM   #12
Jane2008
Member
 
Registered: Oct 2008
Posts: 36

Original Poster
Rep: Reputation: 15
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]
 
Old 02-11-2009, 10:34 AM   #13
Jane2008
Member
 
Registered: Oct 2008
Posts: 36

Original Poster
Rep: Reputation: 15
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 View Post
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]
 
Old 02-11-2009, 12:51 PM   #14
dwhitney67
Senior Member
 
Registered: Jun 2006
Location: Maryland
Distribution: Kubuntu, Fedora, RHEL
Posts: 1,541

Rep: Reputation: 335Reputation: 335Reputation: 335Reputation: 335
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!

Last edited by dwhitney67; 02-11-2009 at 12:52 PM.
 
Old 02-13-2009, 08:49 AM   #15
Jane2008
Member
 
Registered: Oct 2008
Posts: 36

Original Poster
Rep: Reputation: 15
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);
}
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
high recv-q and send-q and collision rate sarah_haff Linux - Networking 2 08-19-2008 06:49 AM
Simultaneous Socket Send/Recv in Perl? juanbobo Programming 10 07-28-2008 03:30 AM
MPI Send and Recv mkrems Programming 1 05-25-2008 12:05 PM
recv() and send() in socket lrios Programming 5 04-23-2008 11:32 AM
Infomration regarding the send() and recv() function karimasif Linux - Networking 1 01-13-2008 10:49 AM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 01:35 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration