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); |
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? |
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. |
(it posted twice)
|
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. |
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:
|
Quote:
|
Quote:
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). |
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); } |
The printf sentence indicated that the command is changed with the option I choosed. But the data returned by recv() still remains the same.
|
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:
... |
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:
... |
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:
|
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 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! |
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. |