Created
June 4, 2017 13:16
-
-
Save yanxurui/11c8e8966265228319d8d5df3cec8bea to your computer and use it in GitHub Desktop.
echo server using select with minor modification from http://www.geeksforgeeks.org/socket-programming-in-cc-handling-multiple-clients-on-server-without-multi-threading/
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//Example code: A simple server side code, which echos back the received message. | |
//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 | |
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 | |
if (argc != 2) | |
{ | |
fprintf(stderr, "Usage: %s [port]\n", argv[0]); | |
exit(EXIT_FAILURE); | |
} | |
//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(atoi(argv[1])); | |
//bind the socket to localhost port 8888 | |
if (bind(master_socket, (struct sockaddr *)&address, sizeof(address))<0) | |
{ | |
perror("bind failed"); | |
exit(EXIT_FAILURE); | |
} | |
//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 : %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)) | |
{ | |
//Somebody disconnected | |
if ((valread = read( sd , buffer, 1024)) == 0) | |
{ | |
printf("Socket %d closed\n", sd); | |
//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; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment