I wrote a code about sockets and I cannot prevent the server to close when the client sends a message or when the client do a CTRL + C
The server goes off.
Server.c:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/time.h>
#define PORT 8888
#define BACKLOG 10
#define LOOP(i, n) for((i) = 0; (i) < (n); (i)++)
#define BUFFSIZE 6500
int create_fd( struct sockaddr_in *server );
int bind_fd ( struct sockaddr_in *server, int servSocket );
int list_fd( int servSocket );
int accept_fd( struct sockaddr_in *server, int servSocket );
int select_fd ( fd_set *readfds, int max_sd );
ssize_t send_fd( int new_fd, const char *const msg );
int main( void ){
const char msg[BUFFSIZE] = "Server is On\n";
char recive[BUFFSIZE];
int servSocket ,clientSocket ,i ,sd;
int client_socket_max[30] = { 0 } , max_clients = 30;
int max_sd;
ssize_t valread;
struct sockaddr_in server;
for (i = 0; i < max_clients; i++)
{
client_socket_max[i] = 0;
}
//set of socket descriptors
fd_set readfds;
size_t addr_size = sizeof(server);
//create
servSocket = create_fd( &server );
//bind the socket to localhost port 8888
bind_fd(&server, servSocket );
//listen the socket to localhost port 8888
printf("\tServer is On\nListener on port %d \n", PORT);
list_fd( servSocket );
//accept the incoming connection
printf( "\n\tWaiting for connections ...\n" );
while(1){
//clear the socket set
FD_ZERO(&readfds);
//add master socket to set
FD_SET(servSocket, &readfds);
max_sd = servSocket;
//add child sockets to set
LOOP( i, max_clients ){
//socket descriptor
sd = client_socket_max[i];
//if valid socket descriptor then add to read list
if(sd > 0){
FD_SET( sd , &readfds);
}
//highest file descriptor number, need it for the select function
if(sd > max_sd){
max_sd = sd;
}
}
//wait for an activity on one of the sockets , timeout is NULL , so wait indefinitely
select_fd( &readfds, max_sd );
//select( max_sd + 1 , &readfds , NULL , NULL , NULL);
//If something happened on the master socket , then its an incoming connection
if ( FD_ISSET( servSocket, &readfds ) ){
clientSocket = accept_fd( &server, servSocket );
//inform user of socket number - used in send and receive commands
printf("New connection , socket fd is %d , ip is : %s , port : %d \n" , clientSocket , inet_ntoa(server.sin_addr) , ntohs(server.sin_port));
//send new connection greeting msg
send_fd( clientSocket, msg );
/*if( send(clientSocket, msg, strlen(msg), 0) != (long int)strlen(msg) ){
perror("send");
}*/
puts("Welcome msg sent successfully");
//add new socket to array of sockets
LOOP( i, max_clients ){
//if position is empty
if( client_socket_max[i] == 0 ){
client_socket_max[i] = clientSocket;
printf("Adding to list of sockets as %d\n" , i);
break;
}
}
}
//else its some IO operation on some other socket :)
LOOP( i, max_clients ){
sd = client_socket_max[i];
if (FD_ISSET( sd , &readfds)){
//Check if it was for closing , and also read the incoming msg
if (( valread = read( sd , recive, 1024)) == 0){
//Somebody disconnected , get his details and print
getpeername(sd , (struct sockaddr*)&server , (socklen_t*)&addr_size);
printf("Host disconnected , ip %s , port %d \n" , inet_ntoa(server.sin_addr) , ntohs(server.sin_port));
//Close the socket and mark as 0 in list for reuse
close( sd );
client_socket_max[i] = 0;
}else{//Echo back the msg that came in
//set the string terminating NULL byte on the end of the data read
recive[valread] = '\0';
send(sd , recive , strlen(recive) , 0 );
}
}
}
}
close( servSocket );
}
int create_fd( struct sockaddr_in *server ){
int opt = 1;
int servSocket = socket(AF_INET , SOCK_STREAM , 0);
if (servSocket == -1 ){
printf("Error, socket()\n");
fprintf(stderr, "socket: %s (%d)\n", strerror(errno), errno);
exit ( EXIT_FAILURE );
}
//set master socket to allow multiple connections , this is just a good habit, it will work without this
if( setsockopt(servSocket, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt)) < 0 ){
perror("setsockopt");
exit(EXIT_FAILURE);
}
//type of socket created
server->sin_family = AF_INET;
server->sin_addr.s_addr = INADDR_ANY;
server->sin_port = htons( PORT );
//printf("socket() \tOK\n");
return servSocket;
}
int bind_fd ( struct sockaddr_in *server, int servSocket ){
int bindfd = bind( servSocket, (struct sockaddr *)server, sizeof(*server) );
if (bindfd == -1 ){
printf("Error, bind(), check line 34\n");
fprintf(stderr, "bind: %s (%d)\n", strerror(errno), errno);
exit ( EXIT_FAILURE );
}else{
//printf("bind() \t\tOK\n");
return bindfd;
}
}
int list_fd( int servSocket ){
int listfd = listen(servSocket, BACKLOG);
if (listfd == -1 ){
printf("Error, listen()\n");
fprintf(stderr, "listen: %s (%d)\n", strerror(errno), errno);
exit ( EXIT_FAILURE );
}else{
//printf("listen() \tOK\n");
return listfd;
}
}
int accept_fd( struct sockaddr_in *server, int servSocket ){
int new_fd;
socklen_t addr_size = sizeof( server );
new_fd = accept(servSocket, (struct sockaddr *)server, (socklen_t*)&addr_size);
if (new_fd == -1 ){
printf("Error, accept()\n");
fprintf(stderr, "accept: %s (%d)\n", strerror(errno), errno);
exit ( EXIT_FAILURE );
}else{
//printf("accept() \tOK\n");
return new_fd;
}
}
int select_fd ( fd_set *readfds, int max_sd ){
int activity = select( max_sd + 1 , readfds , NULL , NULL , NULL);
if ((activity < 0) && (errno!=EINTR)){
printf("select error");
exit ( EXIT_FAILURE );
}else{
return activity;
}
}
ssize_t send_fd( int new_fd, const char *const msg ){
size_t len = strlen(msg);
ssize_t sendfd;
sendfd = send( new_fd, msg, len, 0 );
if (sendfd == -1 ){
printf("Error, write()\n");
fprintf(stderr, "recv: %s (%d)\n", strerror(errno), errno);
exit ( EXIT_FAILURE );
}else{
printf("write() \tOK\n");
printf("Client sent:\t%s", msg );
return sendfd;
}
}
Client.c:
#include <stdio.h>
#include <string.h> //strlen
#include <stdlib.h>
#include <errno.h>
#include <unistd.h> //close
#include <arpa/inet.h> //close
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/time.h> //FD_SET, FD_ISSET, FD_ZERO macros
#define PORT 8888
#define BUFFSIZE 6500
int create_fd( struct sockaddr_in server );
int connect_fd( const int servSocket, struct sockaddr_in *server );
int opt = 1;
int main ( void ){
struct sockaddr_in server;
char recivemsg[BUFFSIZE];
char sendmsg[BUFFSIZE];
memset( recivemsg, 0, sizeof(*recivemsg) );
memset( sendmsg, 0, sizeof(*sendmsg) );
int servSocket = socket(AF_INET , SOCK_STREAM , 0);
if (servSocket == -1 ){
printf("Error, socket()\n");
fprintf(stderr, "socket: %s (%d)\n", strerror(errno), errno);
exit ( EXIT_FAILURE );
}
//set master socket to allow multiple connections , this is just a good habit, it will work without this
if( setsockopt(servSocket, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt)) < 0 ){
perror("setsockopt");
exit(EXIT_FAILURE);
}
//type of socket created
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons( PORT );
if ( ( connect( servSocket, ( struct sockaddr* )&server, sizeof( server ) ) ) < 0 ){
printf("Error, connect()\n");
fprintf(stderr, "connect: %s (%d)\n", strerror(errno), errno);
exit( EXIT_FAILURE );
}
if ( recv( servSocket, recivemsg, sizeof ( recivemsg ), 0 ) < 0 ){
printf("Error, recv()\n");
fprintf(stderr, "recv: %s (%d)\n", strerror(errno), errno);
exit( EXIT_FAILURE );
}
printf("Send a msg to the Server:> ");
fgets(sendmsg, BUFFSIZE, stdin );
if ( send( servSocket, sendmsg, sizeof ( sendmsg ), 0 ) < 0 ){
printf("Error, send()\n");
fprintf(stderr, "send: %s (%d)\n", strerror(errno), errno);
exit( EXIT_FAILURE );
}
close( servSocket );
}
There are a few problems with the code that together could lead to premature exits from your server program.
The most important is that you don't check for errors from either your read or send calls.
If the read call fails it will return -1 which you don't check for (and which will lead to you using -1 as index into your array receive, which is out of bounds and lead to undefined behavior). That will in turn lead to you calling send with a broken connection, which will cause the operating system to send a SIGPIPE signal to your process.
The default behavior of SIGPIPE is to terminate the process.
The usual way to handle this is to ignore the SIGPIPE signal, as then send would return with an error (it returns -1 with errno set to EPIPE) that you should handle.
The common way to handle errors (from either read or send) is to simply close your end of the connection. That's because most errors are simply not recoverable.
Related
I am implementing a Linux C program for client/server. I am using select() to connect with multiple clients. The 1st client connected successfully, but 2nd, 3rd and so on, have not give response any response in terminal(server), although client program is executed. The server is connected with some custom shell that run on client side.My server code is:
/**Handle multiple socket connections with select and fd_set on Linux*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/time.h>
#include <pthread.h>
#define TRUE 1
#define FALSE 0
#define PORT 80
#define BUFSIZE 1025
void *sending( void *fdc)
//void sending(int fd_client)
{
int fd_client= *((int *)fdc);
char buffer[BUFSIZE];
while(1)
{
memset(buffer,0,sizeof(buffer));
fgets(buffer,512,stdin);
if((write(fd_client,buffer,strlen(buffer)))==0)
{
printf("HOST [%d] DISCONNECTED \n",fd_client);
close(fd_client);
}
if((!strcmp(buffer,"quit")) || (!strcmp(buffer,"q")) || (!strcmp(buffer,"QUIT")) || (!strcmp(buffer,"Q")))
{
exit(1);
}
}
}
void *receiving( void *arg)
//void receiving(int fd_client)
{
int fd_client= *((int *)arg);
char buffer[BUFSIZE];
ssize_t size;
while(1)
{
do{
if((size=read(fd_client,buffer,BUFSIZE))==0)
{
printf("HOST [%d] DISCONNECTED \n",fd_client);
close(fd_client);
}
if((write(1,buffer,size))==-1)
{
printf("Eror in Writting to client\n");
perror("");
exit(0);
}
}while(size==BUFSIZE);
}
}
//void *socket_thread(void *arg)
void socket_thread(int fd_client)
{
pthread_t th1,th2;
pthread_create(&th1,NULL,&sending,&fd_client);
pthread_create(&th2,NULL,&receiving,&fd_client);
pthread_join(th1,NULL);
pthread_cancel(th2);
}
int main(int argc , char *argv[])
{
int opt = TRUE;
int master_socket , addrlen , new_socket , client_socket[30] , max_clients = 30 , activity, i , valread , sd;
int max_sd;
struct sockaddr_in address;
char buffer[1025]; //data buffer of 1K
//set of socket descriptors
fd_set readfds;
//a message
char *message = "ECHO Daemon v1.0 \r\n";
//initialise all client_socket[] to 0 so not checked
for (i = 0; i < max_clients; i++)
{
client_socket[i] = 0;
}
//create a master socket
if( (master_socket = socket(AF_INET , SOCK_STREAM , 0)) == 0)
{
perror("socket failed");
exit(EXIT_FAILURE);
}
//set master socket to allow multiple connections , this is just a good habit, it will work without this
if( setsockopt(master_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt)) < 0 )
{
perror("setsockopt");
exit(EXIT_FAILURE);
}
//type of socket created
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons( PORT );
//bind the socket to localhost port 8888
if (bind(master_socket, (struct sockaddr *)&address, sizeof(address))<0)
{
perror("bind failed");
exit(EXIT_FAILURE);
}
printf("Listener on port %d \n", PORT);
//try to specify maximum of 3 pending connections for the master socket
if (listen(master_socket, 3) < 0)
{
perror("listen");
exit(EXIT_FAILURE);
}
//accept the incoming connection
addrlen = sizeof(address);
puts("Waiting for connections ...");
pthread_t tid[30];
while(TRUE)
{
//clear the socket set
FD_ZERO(&readfds);
//add master socket to set
FD_SET(master_socket, &readfds);
max_sd = master_socket;
//add child sockets to set
for ( i = 0 ; i < max_clients ; i++)
{
//socket descriptor
sd = client_socket[i];
//if valid socket descriptor then add to read list
if(sd > 0)
FD_SET( sd , &readfds);
//highest file descriptor number, need it for the select function
if(sd > max_sd)
max_sd = sd;
}
//wait for an activity on one of the sockets , timeout is NULL , so wait indefinitely
activity = select( max_sd + 1 , &readfds , NULL , NULL , NULL);
if ((activity < 0) && (errno!=EINTR))
{
printf("select error");
}
//If something happened on the master socket , then its an incoming connection
if (FD_ISSET(master_socket, &readfds))
{
if ((new_socket = accept(master_socket, (struct sockaddr *)&address, (socklen_t*)&addrlen))<0)
{
perror("accept");
exit(EXIT_FAILURE);
}
//inform user of socket number - used in send and receive commands
printf("New connection , socket fd is %d , ip is : %s , port : %d \n" , new_socket , inet_ntoa(address.sin_addr) , ntohs(address.sin_port));
puts("Welcome message sent successfully");
for (i = 0; i < max_clients; i++)
{
//if position is empty
if( client_socket[i] == 0 )
{
client_socket[i] = new_socket;
printf("Adding to list of sockets as %d\n" , i);
break;
}
}
}
//else its some IO operation on some other socket :)
for (i = 0; i < max_clients; i++)
{
sd = client_socket[i];
if (FD_ISSET( sd , &readfds))
{
socket_thread(sd);
}
}
}
return 0;
}
The program work perfectly for one client but not for multiple. I also tries multi-threads for each file descriptor instead of using select(), but in this case the 2nd client connection overtake the first one in terminal. I want the following outcomes:
Switch between multiple connected clients from Linux terminal(i,e by pressing some keys from keyboard).
When new client is connected in-between, , it prompt a signal , and also can be switch to further read and write operations.
Any help regrading this will be appreciated.
I have wrote simple socket programming in c in for Handle multiple socket connections client and sever.
But when I run it, client showed that connection refused error.
Server side
/**
Handle multiple socket connections with select and fd_set on Linux
*/
#include <stdio.h>
#include <string.h> //strlen
#include <stdlib.h>
#include <errno.h>
#include <unistd.h> //close
#include <arpa/inet.h> //close
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/time.h> //FD_SET, FD_ISSET, FD_ZERO macros
#define TRUE 1
#define FALSE 0
#define PORT 8889
int main(int argc , char *argv[])
{
int opt = TRUE;
int master_socket , addrlen , new_socket , client_socket[30] , max_clients = 30 , activity, i , valread , sd;
int max_sd;
struct sockaddr_in address;
char buffer[1025]; //data buffer of 1K
//set of socket descriptors
fd_set readfds;
//a message
char *message = "ECHO Daemon v1.0 \r\n";
//initialise all client_socket[] to 0 so not checked
for (i = 0; i < max_clients; i++)
{
client_socket[i] = 0;
}
//create a master socket
if( (master_socket = socket(AF_INET , SOCK_STREAM , 0)) == 0)
{
perror("socket failed");
exit(EXIT_FAILURE);
}
//set master socket to allow multiple connections , this is just a good habit, it will work without this
if( setsockopt(master_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt)) < 0 )
{
perror("setsockopt");
exit(EXIT_FAILURE);
}
//type of socket created
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons( PORT );
//bind the socket to localhost port 8888
if (bind(master_socket, (struct sockaddr *)&address, sizeof(address))<0)
{
perror("bind failed");
exit(EXIT_FAILURE);
}
printf("Listener on port %d \n", PORT);
//try to specify maximum of 3 pending connections for the master socket
if (listen(master_socket, 3) < 0)
{
perror("listen");
exit(EXIT_FAILURE);
}
//accept the incoming connection
addrlen = sizeof(address);
puts("Waiting for connections ...");
while(TRUE)
{
//clear the socket set
FD_ZERO(&readfds);
//add master socket to set
FD_SET(master_socket, &readfds);
max_sd = master_socket;
//add child sockets to set
for ( i = 0 ; i < max_clients ; i++)
{
//socket descriptor
sd = client_socket[i];
//if valid socket descriptor then add to read list
if(sd > 0)
FD_SET( sd , &readfds);
//highest file descriptor number, need it for the select function
if(sd > max_sd)
max_sd = sd;
}
//wait for an activity on one of the sockets , timeout is NULL , so wait indefinitely
activity = select( max_sd + 1 , &readfds , NULL , NULL , NULL);
if ((activity < 0) && (errno!=EINTR))
{
printf("select error");
}
//If something happened on the master socket , then its an incoming connection
if (FD_ISSET(master_socket, &readfds))
{
if ((new_socket = accept(master_socket, (struct sockaddr *)&address, (socklen_t*)&addrlen))<0)
{
perror("accept");
exit(EXIT_FAILURE);
}
//inform user of socket number - used in send and receive commands
printf("New connection , socket fd is %d , ip is : %s , port : %d \n" , new_socket , inet_ntoa(address.sin_addr) , ntohs(address.sin_port));
//send new connection greeting message
if( send(new_socket, message, strlen(message), 0) != strlen(message) )
{
perror("send");
}
puts("Welcome message sent successfully");
//add new socket to array of sockets
for (i = 0; i < max_clients; i++)
{
//if position is empty
if( client_socket[i] == 0 )
{
client_socket[i] = new_socket;
printf("Adding to list of sockets as %d\n" , i);
break;
}
}
}
//else its some IO operation on some other socket :)
for (i = 0; i < max_clients; i++)
{
sd = client_socket[i];
if (FD_ISSET( sd , &readfds))
{
//Check if it was for closing , and also read the incoming message
if ((valread = read( sd , buffer, 1024)) == 0)
{
//Somebody disconnected , get his details and print
getpeername(sd , (struct sockaddr*)&address , (socklen_t*)&addrlen);
printf("Host disconnected , ip %s , port %d \n" , inet_ntoa(address.sin_addr) , ntohs(address.sin_port));
//Close the socket and mark as 0 in list for reuse
close( sd );
client_socket[i] = 0;
}
//Echo back the message that came in
else
{
//set the string terminating NULL byte on the end of the data read
buffer[valread] = '\0';
send(sd , buffer , strlen(buffer) , 0 );
}
}
}
}
return 0;
}
Client side
// Client side C/C++ program to demonstrate Socket programming
#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#define PORT 8889
int main(int argc, char const *argv[])
{
int sock = 0, valread;
struct sockaddr_in serv_addr;
char *hello = "Hello from client";
char buffer[1024] = {0};
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
printf("\n Socket creation error \n");
return -1;
}
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(PORT);
// Convert IPv4 and IPv6 addresses from text to binary form
if(inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr)<=0)
{
printf("\nInvalid address/ Address not supported \n");
return -1;
}
if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
{
printf("\nConnection Failed \n");
return -1;
}
send(sock , hello , strlen(hello) , 0 );
printf("Hello message sent\n");
valread = read( sock , buffer, 1024);
printf("%s\n",buffer );
return 0;
}
When I compile and run the code getting Connection refused
Compile
gcc server1.c -o server1
gcc client2.c -o client2
Run
./client2 127.0.0.1
Client Error: Connection Failed.: Connection refused
binded successfully
I want to pass an argument to the client, send it to the server, then print it there, currently I am getting no output.
Current codes:
Client:
#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include<errno.h>
#define PORT 8080
int main(int argc, char const *argv[])
{
int sock = 0, valread;
struct sockaddr_in serv_addr;
char buffer[1024] = {0};
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
printf("\n Socket creation error \n");
return -1;
}
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(PORT);
if(inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr)<=0)
{
printf("Invalid address \n");
return -1;
}
if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
{
printf("Connection Failed \n");
return -1;
}
int i;
if(argc>=2){
for(i=0; i<argc; i++) {
if(write( sock, argv[i], 1 + strlen( argv[i] ))<0)
{
printf("Error in write() ! %s\n", strerror(errno));
return -1;
}
}
}
return 0;
}
Server:
#include <unistd.h>
#include <stdio.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <string.h>
#include<errno.h>
#define PORT 8080
int main(int argc, char const *argv[])
{
int server_fd, new_socket, valread;
struct sockaddr_in address;
int opt = 1;
int addrlen = sizeof(address);
char buffer[1024] = {0};
char *hello = "Hello from server";
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0)
{
perror("socket failed");
exit(EXIT_FAILURE);
}
if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR , &opt, sizeof(opt)))
{
perror("setsockopt");
exit(EXIT_FAILURE);
}
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons( PORT );
if (bind(server_fd, (struct sockaddr *)&address,
sizeof(address))<0)
{
perror("bind failed");
exit(EXIT_FAILURE);
}
if (listen(server_fd, 3) < 0)
{
perror("listen");
exit(EXIT_FAILURE);
}
if ((new_socket = accept(server_fd, (struct sockaddr *)&address,
(socklen_t*)&addrlen))<0)
{
perror("accept");
exit(EXIT_FAILURE);
}
valread = read(new_socket , buffer, 1024);
puts("The client sent the value: ");
int* valuerec=(int *)buffer;
int val2=*valuerec;
return 0;
}
Currently I am getting no number as an output, how can I do fix this? Ultimately my goal would be to send and receive multiple arguments but for now I am only sending one.
the following proposed code:
cleanly compiles
performs the desired server functionality
properly checks for errors
properly handles errors
uses an appropriate signature for function: main()
does not include header files those contents are not used
uses meaningful names rather than 'magic' numbers
uses appropriate horizontal spacing for readability
properly NUL terminates the input buffer
note the function: atoi() does not indicate when an error occurs, so suggest using strtol() instead
properly cleared the struct address before setting some of the fields
and now the proposed code:
#include <unistd.h>
#include <stdio.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#define PORT 8080
#define MAX_BUFFER_LEN 1025
int main( void )
{
int server_fd, new_socket;
struct sockaddr_in address;
if ( ( server_fd = socket( AF_INET, SOCK_STREAM, 0 ) ) < 0 )
{
perror( "socket failed" );
exit( EXIT_FAILURE );
}
int opt = 1;
if ( setsockopt( server_fd, SOL_SOCKET, SO_REUSEADDR , &opt, sizeof(opt) ) )
{
perror("setsockopt failed" );
exit( EXIT_FAILURE );
}
memset( &address, 0, sizeof( address ) );
address.sin_family = AF_INET;
address.sin_addr.s_addr = htonl( INADDR_ANY );
address.sin_port = htons( PORT );
socklen_t addrlen = sizeof( address );
if ( bind( server_fd, (struct sockaddr *)&address, addrlen ) < 0 )
{
perror( "bind failed" );
exit( EXIT_FAILURE );
}
if ( listen( server_fd, 3 ) < 0 )
{
perror( "listen failed" );
exit( EXIT_FAILURE );
}
if (( new_socket = accept(server_fd, (struct sockaddr *)&address,
(socklen_t*)&addrlen ) ) < 0 )
{
perror( "accept failed" );
exit( EXIT_FAILURE );
}
ssize_t valread;
char buffer[ MAX_BUFFER_LEN ] = { 0 };
if( ( valread = read( new_socket, buffer, MAX_BUFFER_LEN -1 ) ) > 0 )
{ // then read successful
buffer[ valread ] = '\0';
int value = atoi( buffer );
printf( "The client sent the string: %s, which began with integer value: %d\n", buffer, value );
}
else if( ! valread )
{
puts( "client hungup" );
}
else
{
perror( "read failed" );
}
return 0;
}
I am making an assignment in which a server fork's multiple children, one for each sensor connected to the server (and each child then has a tcp connection to that sensor node).
Now as it's my first time working with fork's, I'm not entirely sure it's working correctly.
The tcpsocket.h is a file provided, giving some basic tcp-functionality. This is working, since the data is sent and received succesfully.
Here's a short explanation of the code: The main process listens passively to incoming tcp connections. The tcp_wait_for_connection() waits in blocking mode for a connection to be established. Once this is done, it should give the connection to a new child. The Child should of course then close the passive listening on the port, and the main process should not listen to the connection with the sensor.
Now it all works fine, but I'm not sure whether children are correctly killed. A sensorNode for example just quits (cntrl + c), thus the connection stops, but I'm not sure whether the child then dies or keeps looping for eternity. I've also included tcpsocket.c since this might give more clarity.
server.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include "tcpsocket.h"
#define BUFSIZE 1024
#define PORT 1234
struct package{
unsigned sensorId:12;
unsigned sequence:4;
unsigned flag:2;
unsigned sign:1;
unsigned value:12;
unsigned parity:1;
};
typedef struct package packs;
union sensor{
packs pack;
unsigned sensorValue;
};
typedef union sensor Sensor;
char buffer[BUFSIZE];
int main( void )
{
Socket server, client;
int bytes;
server = tcp_passive_open( PORT );
while( 1 ) {
client = tcp_wait_for_connection( server );
#ifdef DEBUG
printf("Incoming client connection\n");
#endif
pid_t pid;
pid = fork();
if(pid == -1){
printf("Something went wrong creating a child.\n");
}else if(pid == 0){
tcp_close( &server );
#ifdef DEBUG
pid_t parentPid;
parentPid = getppid();
printf("New child created with parent id %d, own pid: %d\n",parentPid, pid);
#endif
Sensor * mySensor = malloc(sizeof(packs));
while(1){
memset(buffer, 0, BUFSIZE);
bytes = tcp_receive( client, (void *)buffer, BUFSIZE );
if(bytes > 0){
mySensor->sensorValue = atoi(buffer);
#ifdef DEBUG
printf("Received message of %d bytes. ID: %i, Sequence: %i, flag: %i, sign: %i, value: %i\n",
bytes, mySensor->pack.sensorId, mySensor->pack.sequence, mySensor->pack.flag, mySensor->pack.sign, mySensor->pack.value);
#endif
}
}
tcp_close( &client );
exit(0);
}
tcp_close( &client );
}
tcp_close( &server );
return 0;
}
tcpsocket.c
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "tcpsocket.h"
#define CHAR_IP_ADDR_LENGTH 16 // 4 numbers of 3 digits, 3 dots and \0
#define ERROR_SD -1
#define ERROR_PORT 0
#define MIN_PORT 1
#define MAX_PORT 65536
#define PROTOCOLFAMILY AF_INET // internet protocol suite
#define TYPE SOCK_STREAM // streaming protool type
#define PROTOCOL IPPROTO_TCP // TCP protocol
typedef struct {
int sd;
char *ip_addr;
int port;
} MySocket; // My definition of a socket: a socket descriptor,
// the IP address and port number of the PC hosting this socket
// private functions used for error checking
static void die(char* message);
static void check_socket_ptr(char *pre_msg, Socket s);
static void check_sd(char *pre_msg, int sd);
static void check_ip_addr(char *pre_msg, char *ip_addr);
static void check_port(char *pre_msg, int port);
// private error message string
static char error_msg[256];
/*-------------------------------------------------------------------------------------*/
Socket tcp_passive_open(int port)
/*-------------------------------------------------------------------------------------*/
{
// parameter check
check_port("tcp_open_server() failed", port);
MySocket *s = (MySocket *)malloc( sizeof(MySocket) );
if ( s == NULL )
die("tcp_open__socket() failed: mem alloc error");
struct sockaddr_in addr;
s->sd = socket(PROTOCOLFAMILY, TYPE, PROTOCOL);
check_sd("tcp_open_server failed(): socket creation error", s->sd);
/* Construct the server address structure */
memset(&addr, 0, sizeof(struct sockaddr_in));
addr.sin_family = PROTOCOLFAMILY;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(port);
if ( bind(s->sd, (struct sockaddr *)&addr, sizeof(addr)) != 0 ) {
die("tcp_open_server failed(): bind() failed"); //will fail if e.g; port is in use
}
if( listen(s->sd, MAX_PENDING) != 0 )
die("tcp_open_server failed(): listen() failed");
s->port = port;
s->ip_addr = NULL; //INADDR_ANY ...
return (Socket)s;
}
/*-------------------------------------------------------------------------------------*/
Socket tcp_active_open( int remote_port, char *remote_ip )
/*-------------------------------------------------------------------------------------*/
{
// parameter check
check_port("tcp_open_client() failed", remote_port);
check_ip_addr("tcp_open_client() failed", remote_ip);
MySocket *client = (MySocket *)malloc( sizeof(MySocket) );
if ( client == NULL )
die("tcp_open_client() failed: mem alloc error");
struct sockaddr_in addr;
int length;
char *p;
client->sd = socket(PROTOCOLFAMILY, TYPE, PROTOCOL);
check_sd("tcp_open_client() failed: socket creation error", client->sd);
/* Construct the server address structure */
memset(&addr, 0, sizeof(struct sockaddr_in));
addr.sin_family = PROTOCOLFAMILY;
if ( inet_aton(remote_ip, (struct in_addr *) &addr.sin_addr.s_addr) == 0 )
die("tcp_open_client failed(): invalid ip address");
addr.sin_port = htons(remote_port);
if ( connect(client->sd, (struct sockaddr *) &addr, sizeof(addr) ) < 0 )
die("tcp_open_client failed(): connect () failed");
memset(&addr, 0, sizeof(struct sockaddr_in));
length = sizeof(addr);
if ( getsockname(client->sd, (struct sockaddr *)&addr, (socklen_t *)&length) != 0 )
die("tcp_open_client failed(): getsockname() failed");
p = inet_ntoa(addr.sin_addr); //returns addr to statically allocated buffer
client->ip_addr = (char *)malloc( sizeof(char)*CHAR_IP_ADDR_LENGTH);
if ( client->ip_addr == NULL )
die("tcp_open_client failed(): mem alloc error");
client->ip_addr = strcpy( client->ip_addr, p );
client->port = ntohs(addr.sin_port);
return (Socket)client;
}
/*-------------------------------------------------------------------------------------*/
Socket tcp_wait_for_connection( Socket socket )
/*-------------------------------------------------------------------------------------*/
{
// parameter check
check_socket_ptr("tcp_wait_for_connection() failed", socket);
MySocket *serv = (MySocket *)socket;
MySocket *clie = (MySocket *)malloc( sizeof(MySocket) );
if ( clie == NULL )
die("tcp_wait_for_connection() failed: mem alloc error");
struct sockaddr_in addr;
unsigned int length = sizeof(struct sockaddr_in);
char *p;
check_sd("tcp_wait_for_connection() failed", serv->sd);
clie->sd = accept(serv->sd, (struct sockaddr*) &addr, &length);
check_sd("tcp_wait_for_connection() failed: accept() error", clie->sd);
p = inet_ntoa(addr.sin_addr); //returns addr to statically allocated buffer
clie->ip_addr = (char *)malloc( sizeof(char)*CHAR_IP_ADDR_LENGTH);
if ( clie->ip_addr == NULL )
die("tcp_wait_for_connection failed(): mem alloc error");
clie->ip_addr = strcpy( clie->ip_addr, p );
clie->port = ntohs(addr.sin_port);
return (Socket)clie;
}
/*-------------------------------------------------------------------------------------*/
void tcp_close( Socket *socket )
/*-------------------------------------------------------------------------------------*/
{
// parameter check
check_socket_ptr("tcp_close() failed", socket);
check_socket_ptr("tcp_close() failed", *socket);
MySocket *s = (MySocket *)*socket;
check_sd("tcp_close() failed", s->sd);
close( s->sd );
free(s);
*socket = NULL;
}
/*-------------------------------------------------------------------------------------*/
void tcp_send(Socket socket, void *buffer, int bufsize )
/*-------------------------------------------------------------------------------------*/
{
// parameter check
check_socket_ptr("tcp_send() failed", socket);
if ( buffer == NULL )
die("tcp_send failed(): buffer param is NULL");
MySocket *s = (MySocket *)socket;
int result;
int sen = 0;
int to_sen = bufsize;
check_sd("tcp_send() failed", s->sd);
do {
result = send(s->sd, (const void*) (buffer+sen), to_sen, 0);
if (result < 0)
die("tcp_send() failed: not able to send");
sen += result;
to_sen -= result;
} while ( to_sen > 0 );
}
/*-------------------------------------------------------------------------------------*/
int tcp_receive (Socket socket, void* buffer, int bufsize)
/*-------------------------------------------------------------------------------------*/
{
// parameter check
check_socket_ptr("tcp_receive() failed", socket);
if ( buffer == NULL )
die("tcp_receive() failed: buffer param is NULL");
if ( bufsize == 0 )
die("tcp_receive() failed: bufsize is zero");
MySocket *s = (MySocket *)socket;
check_sd("tcp_receive() failed", s->sd);
int rec = recv(s->sd, buffer, bufsize, 0);
return rec;
}
/*-------------------------------------------------------------------------------------*/
char * get_ip_addr( Socket socket )
/*-------------------------------------------------------------------------------------*/
{
// parameter check
check_socket_ptr("get_ip_addr() failed", socket);
MySocket *s = (MySocket *)socket;
check_ip_addr("get_ip_addr() failed", s->ip_addr);
return s->ip_addr;
}
/*-------------------------------------------------------------------------------------*/
int get_port( Socket socket )
/*-------------------------------------------------------------------------------------*/
{
// parameter check
check_socket_ptr("get_port() failed", socket);
MySocket *s = (MySocket *)socket;
check_port("get_port() failed", s->port);
return s->port;
}
/*-------------------------------------------------------------------------------------*/
int get_socket_descriptor( Socket socket )
/*-------------------------------------------------------------------------------------*/
{
// parameter check
check_socket_ptr("get_socket_descriptor() failed", socket);
MySocket *s = (MySocket *)socket;
check_sd("get_socket_descriptor() failed", s->sd);
return s->sd;
}
/*-------------------------------------------------------------------------------------*/
static void die(char* message)
/*-------------------------------------------------------------------------------------*/
{
perror(message);
exit(-1);
}
/*-------------------------------------------------------------------------------------*/
static void check_socket_ptr(char *pre_msg, Socket socket)
/*-------------------------------------------------------------------------------------*/
{
if ( socket == NULL )
{
sprintf(error_msg, "%s: socket ptr is NULL", pre_msg);
die(error_msg);
}
}
/*-------------------------------------------------------------------------------------*/
static void check_sd(char *pre_msg, int sd)
/*-------------------------------------------------------------------------------------*/
{
if ( sd <= ERROR_SD )
{
sprintf(error_msg, "%s: invalid socket descriptor", pre_msg);
die(error_msg);
}
}
/*-------------------------------------------------------------------------------------*/
static void check_ip_addr(char *pre_msg, char *ip_addr)
/*-------------------------------------------------------------------------------------*/
{
if ( ip_addr == NULL )
{
sprintf(error_msg, "%s: invalid socket ip address", pre_msg);
die(error_msg);
}
}
/*-------------------------------------------------------------------------------------*/
static void check_port(char *pre_msg, int port)
/*-------------------------------------------------------------------------------------*/
{
if ( (port < MIN_PORT) || (port > MAX_PORT) )
{
sprintf(error_msg, "%s: invalid socket port", pre_msg);
die(error_msg);
}
}
I'm not sure whether the child then dies or keeps looping for eternity.
In the code you show there are no tests for recv() returning 0 which would indicate that the connection had been closed by the other side.
You might like to modify the code like this
if(bytes > 0){
mySensor->sensorValue = atoi(buffer);
#ifdef DEBUG
printf("Received message of %d bytes. ID: %i, Sequence: %i, flag: %i, sign: %i, value: %i\n",
bytes, mySensor->pack.sensorId, mySensor->pack.sequence, mySensor->pack.flag, mySensor->pack.sign, mySensor->pack.value);
#endif
}
else if (bytes == 0)
{
printf("Connection closed by other side. Exiting ...\n");
break;
}
else /* bytes < 0 */
{
printf("Error receiving. Exiting ...\n");
break;
}
to end the child. There is no need to "kill" any process in term of sending it a SIGKILL signal, btw.
Also the tcp_receive() function misses to test how much data had been received for each call to recv() and then if necessary to loop around recv() until all data requested had been received. (See tcp_send() to see how it is done for send().)
I've got an assignment to write a server program that accepts multiple clients. I'm writing in C language and trying to accomplish this using a select() statement. I am able to compile, but whenever I telnet in, I get a "Socket operation on non-socket error." I've tried researching the error, but can't find anything too helpful. Any assistance would be appreciated.
The output of my server is:
$ ./assign2 33333
Waiting for connection...
fd is 0
EchoServ recv error: Socket operation on non-socket
fd is 1
EchoServ recv error: Socket operation on non-socket
EchoServ recv error: Socket operation on non-socket
The output of telnet is:
$ telnet localhost 33333
Trying 127.0.0.1...
Connected to localhost.localdomain (127.0.0.1).
Escape character is '^]'.
Welcome to EchoServ chat.
My server code:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#define PORT 50000
main( int argc, char *argv[] )
{
char buf[ BUFSIZ ], /* buffer for incoming data */
*endptr, /* for strtol() */
*message = "Welcome to EchoServ chat. \r\n"; /* welcome message */
int masterSocket, /* main listening socket for server */
newSocket, /* new sockets for connecting clients */
opt = 1, /* for port reuse code */
nBytes, /* # of incoming bytes */
addrlen;
int i,j; /* temp vars */
short int port; /* port number */
fd_set master; /* master file descriptor list */
fd_set temp_fds; /* temp file descriptor list for select() */
int fdmax; /* maximum file descriptor number */
struct sockaddr_in sin;
/* Get port number from the command line, or
set to default port if no arguments were supplied */
if ( argc == 2 ) {
port = strtol(argv[1], &endptr, 0);
if ( *endptr ) {
fprintf(stderr, "EchoServ: Invalid port number.\n");
exit(EXIT_FAILURE);
}
}
else {
port = PORT;
}
FD_ZERO(&master); /* clear the master and temp sets */
FD_ZERO(&temp_fds);
/* Get an internet domain socket */
if ( ( masterSocket = socket( AF_INET, SOCK_STREAM, 0) ) == -1 ) {
perror( "EchoServ socket error" );
exit( 1 );
}
/* Complete the socket structure */
memset( &sin, 0, sizeof(sin) );
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
sin.sin_port = htons(port);
/* Bind the socket to the port number */
if ( bind( masterSocket, ( struct sockaddr *) &sin, sizeof( sin ) ) == -1) {
perror( "EchoServ bind failed" );
exit( 1 );
}
/* Allow port reuse */
if ( setsockopt( masterSocket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof( opt ) ) == -1 ) {
perror( "EchoServ setsockopt error" );
exit(1);
}
/* Listen for clients that want to connect. */
if ( listen( masterSocket, 5 ) == -1 ) {
perror( "EchoServ listen error" );
exit( 1 );
}
/* add masterSocket to the master set */
FD_SET(masterSocket, &master);
/* track largest file descriptor, starting with masterSocket */
fdmax = masterSocket;
/* Wait for a client connection, then accept it. */
puts ( "Waiting for connection..." );
while(1){
temp_fds = master; /* copy master set to temp set */
//addrlen = sizeof(sin);
/* wait for activity on a socket */
if (select(fdmax+1, &temp_fds, NULL, NULL, NULL) == -1) {
perror("EchoServ select error");
exit(1);
}
for ( i = 0; i <= fdmax; i++ ){
printf("fd is %d\n", i); /*debug*/
if ( FD_ISSET( i, &temp_fds ) ){ /* true if file descriptor is in set */
/* accept new connection */
if ( i == masterSocket ){
addrlen = sizeof( sin );
if ( (newSocket = accept( masterSocket, ( struct sockaddr *) &sin, &addrlen )) == -1 )
perror("EchoServ: accept error");
else {
printf("New connection accepted\n"); /*debug*/
FD_SET( newSocket, &master ); /* add new connection to master set */
if ( newSocket > fdmax ) /* update max descriptor */
fdmax = newSocket;
//print details of new connection
printf("New connection on %s:%d, socket fd is %d \n",
inet_ntoa(sin.sin_addr), ntohs(sin.sin_port), newSocket );
//send new connection greeting message
if( send( newSocket, message, strlen( message ), 0) == -1 )
{
perror("EchoServ welcome message error");
}
puts("Welcome message sent successfully");
}
}
}
/* handle incoming data */
else{
if ( ( nBytes = recv( i, buf, sizeof( buf ), 0 ) ) <= 0 ){ /* error or closed connection */
if ( nBytes == 0 ) /* connection closed */
printf( "EchoServ: socket %d closed by client\n", i );
else /* recv error */
perror("EchoServ recv error");
close( i ); /* close socket */
FD_CLR( i, &master ); /* remove from master set */
}
else { /* got some data */
for( j = 0; j <= fdmax; j++ ){
if ( FD_ISSET( j, &master ) ){ /* send data to all sockets */
if( j != i && j != masterSocket ){ /* except self and masterSocket */
if ( send( j, buf, nBytes, 0) == -1)
perror("EchoServ send error");
}
}
}
}
}
}
}
return( 0 );
}
Thanks for helping.
So you test if (FD_ISSET(i, &temp_fds)) and on the else branch you attempt to recv on i. So basically you're only trying to receive if i is invalid or would block.
This all of course stems from the unbounded use of blocks and braces. You probably meant that else to be paired with if (i == masterSocket).