Reputation: 1407
I'm trying to establish a communication between 2 stations (A and B). A should sent multiple data to B (and viceversa): "multiple data" means that I would like to use send and recv from both stations within a single accept session. At the moment I'm simply trying to send more than 1 packet per connection. Since I'm not familiar handling sockets, chances are high that I haven't fully understood the concepts behind sockets. In the following code the receiver successfully retrieve the first int the transmitter sent, but not the following ones. Can you show me what I did wrong?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdarg.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <errno.h>
#define DATA_TO_SEND_LENGTH 9
#define PRINT_ERRNO_EXIT(who,id) { \
int verrno=errno; \
printf("%s ERRNO: %d\nexit id: %d\n",who==0?"sender":"receiver",verrno,id); \
return id; \
}
int main(){
char* ipaddress="127.0.0.1";
int portNumber=12345;
int socketOptionalValue=1;
const int dataToSend[]={1,2,3,4,5,6,7,8,9};
if (fork()==0){
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
// @@@@@@@@@@@@@@@ CHILD: HE IS THE SENDER @@@@@@@@@@@@@@@@
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
int socketSenderDescriptor;
struct sockaddr_in destinationInfos;
struct sockaddr_in tmp;
int i;
// ************** CREATE AND OPEN THE SOCKET *****************
inet_aton(ipaddress,&tmp.sin_addr);
socketSenderDescriptor = socket(AF_INET, SOCK_STREAM, 0); // socket file descriptor
if (socketSenderDescriptor < 0 ){
PRINT_ERRNO_EXIT(0,1);
}
if (setsockopt(socketSenderDescriptor,SOL_SOCKET,SO_REUSEADDR,&socketOptionalValue,sizeof(socketOptionalValue))!=0){
PRINT_ERRNO_EXIT(0,2);
}
if (setsockopt(socketSenderDescriptor,SOL_SOCKET,SO_KEEPALIVE,&socketOptionalValue,sizeof(socketOptionalValue))!=0){
PRINT_ERRNO_EXIT(0,2);
}
memset(&destinationInfos,0,sizeof(destinationInfos)); //clean the structure used to store destination information
destinationInfos.sin_family=AF_INET; //we want to use inet class
destinationInfos.sin_addr.s_addr=tmp.sin_addr.s_addr;//Set destination IP
destinationInfos.sin_port=htons(portNumber); //communiction port number
//connection
if (connect(socketSenderDescriptor,(struct sockaddr *)&(destinationInfos),sizeof(destinationInfos)) < 0){
PRINT_ERRNO_EXIT(0,3);
}
// ******************* SEND DATA **********************
sleep(1); //wait for the parent to start listening...
for (i=0;i<DATA_TO_SEND_LENGTH;i++){
printf("sender: i'm sending %d\n",dataToSend[i]);
send(socketSenderDescriptor,&(dataToSend[i]),sizeof(dataToSend[i]),0);
sleep(1);
}
// ******************* CLOSE SOCKET *******************
if (close(socketSenderDescriptor)!=0){
PRINT_ERRNO_EXIT(0,4);
}
printf("SENDER FINISH!\n");
return EXIT_SUCCESS;
}else {
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
// @@@@@@@@@@@@@@@@ PARENT: HE IS THE RECEIVER @@@@@@@@@@@@
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
struct sockaddr_in remoteSocketInfos;
struct sockaddr_in localSocketInfos;
int localSocketDescriptor;
int sessionSocket;
int valueReceived;
int i=0;
static socklen_t socksize=sizeof(struct sockaddr_in);
// ******************* CREATE AND BIND THE SOCKET ******************
//write inside localSocketInfos the information about our server
memset(&localSocketInfos,0,sizeof(localSocketInfos));
localSocketInfos.sin_family=AF_INET;
localSocketInfos.sin_addr.s_addr=htonl(INADDR_ANY);
localSocketInfos.sin_port= htons(portNumber);
//create the main socket where all connection to our server will be received
localSocketDescriptor=socket(AF_INET,SOCK_STREAM,0);
if (localSocketDescriptor<0){
PRINT_ERRNO_EXIT(1,1);
}
//On Linux, SO_REUSEADDR allows you to bind to an address unless an active connection is present
//see https://stackoverflow.com/questions/4979425/difference-between-address-in-use-with-bind-in-windows-and-on-linux-errno
setsockopt(localSocketDescriptor,SOL_SOCKET,SO_REUSEADDR,&socketOptionalValue,sizeof(socketOptionalValue));
//Bind our socket to the socketDescription: this allows the machine to know the data
//received on the port specified in the sockaddr_in should be handled by our specified socket.
if (bind(localSocketDescriptor,(struct sockaddr*)&localSocketInfos,sizeof(struct sockaddr))!=0){
PRINT_ERRNO_EXIT(1,2);
}
//tells our program to start listening the socket we have created. This will NOT block the flow of the program because
//we are not waiting anything at all.
if (listen(localSocketDescriptor,10)!=0){
PRINT_ERRNO_EXIT(1,3);
}
// ************************ WAIT FOR CONNECTIONS ********************
do {
i++;
printf("Waiting transmission on %s, port %d...\n",inet_ntoa(localSocketInfos.sin_addr),localSocketInfos.sin_port);
sessionSocket=accept(localSocketDescriptor,(struct sockaddr*)&remoteSocketInfos,&socksize);
if (sessionSocket<0){
int verrno=errno;
printf("receiver ERRNO: %d\n",verrno);
continue;
}
printf("Incoming transmission from %s, port %d...\n",inet_ntoa(remoteSocketInfos.sin_addr),remoteSocketInfos.sin_port);
recv(sessionSocket,&valueReceived,sizeof(valueReceived),0);
printf("DATA READ! %d\n",valueReceived);
close(sessionSocket);
} while(i<DATA_TO_SEND_LENGTH);
if (close(localSocketDescriptor)==0){
PRINT_ERRNO_EXIT(1,4);
}
printf("RECEIVER FINISH!\n");
return EXIT_SUCCESS;
}
}
I'm also posting the output of my program, hoping it might help you finding what I did wrong:
Waiting transmission on 0.0.0.0, port 14640...
Incoming transmission from 127.0.0.1, port 63718...
sender: i'm sending 1
DATA READ! 1
Waiting transmission on 0.0.0.0, port 14640...
sender: i'm sending 2
sender: i'm sending 3
sender: i'm sending 4
sender: i'm sending 5
sender: i'm sending 6
sender: i'm sending 7
sender: i'm sending 8
sender: i'm sending 9
SENDER FINISH!
Upvotes: 0
Views: 40
Reputation: 296
In the receiver process, accept()
only needs to be called once. Since you put accept()
inside the while
loop, the second iteration of the loop will be blocked on accept
, as there is no new connection coming in.
A simple fix would be to put the accept
out of the loop. You can try the following fix and see if it works. Note that the close
is also moved after the loop.
// ************************ WAIT FOR CONNECTIONS ********************
printf("Waiting transmission on %s, port %d...\n",inet_ntoa(localSocketInfos.sin_addr),localSocketInfos.sin_port);
sessionSocket=accept(localSocketDescriptor,(struct sockaddr*)&remoteSocketInfos,&socksize);
if (sessionSocket<0){
int verrno=errno;
printf("receiver ERRNO: %d\n",verrno);
PRINT_ERRNO_EXIT(1,5);
}
do {
i++;
printf("Incoming transmission from %s, port %d...\n",inet_ntoa(remoteSocketInfos.sin_addr),remoteSocketInfos.sin_port);
recv(sessionSocket,&valueReceived,sizeof(valueReceived),0);
printf("DATA READ! %d\n",valueReceived);
} while(i<DATA_TO_SEND_LENGTH);
close(sessionSocket);
Upvotes: 1