#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <arpa/inet.h>
#define TRUE 1
#define PORT 51500
int main(int argc, char *argv[]) {
int master_sock,
addrlen,
new_sock,
maximum_clients = 30,
client_sock[maximum_clients],
act,
i,
value_read,
sock_descriptor,
maximum_socket_descriptor;
struct sockaddr_in adr{};
char buff[1024]; //data buffer of 1K
fd_set read_fds; //set of socket file descriptors
char *message = "ECHO Daemon v1.0 \r\n"; //connect notice message
//initialise all client_sock to 0
for (i = 0; i < maximum_clients; i++) {
client_sock[i] = 0;
}
//creating a master socket
if ((master_sock = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
perror("Failed_Socket");
exit(EXIT_FAILURE);
}
//These are the types of sockets that we have created
adr.sin_family = AF_INET;//PROTOCOL = IP
adr.sin_addr.s_addr = INADDR_ANY;//SOURCE ADDRESS = 0.0.0.0/0
adr.sin_port = htons(PORT);//LISTENING PORT = PORT
//bind the socket to localhost port
if (bind(master_sock, (struct sockaddr *) &adr, sizeof(adr)) < 0) {
perror("Failed_Bind");
exit(EXIT_FAILURE);
}
printf("Port having listener: %d \n", PORT);
//Specify 3 as maximum pending connections for master socket
if (listen(master_sock, 3) < 0) {
perror("listen");
exit(EXIT_FAILURE);
}
//Accepting the Incoming Connection
addrlen = sizeof(adr);
puts("Looking For Connections");
//*******************************//
// Here we start using select functions and the macros for multiple client handling
while (TRUE) {
//Clearing the socket set
FD_ZERO(&read_fds);
//Adding the master socket to the set
FD_SET(master_sock, &read_fds);
maximum_socket_descriptor = master_sock;
//Adding child sockets to set
for (i = 0; i < maximum_clients; i++) {
//Descriptor for Socket
sock_descriptor = client_sock[i];
//if the socket descriptor is valid then adding it to the read list
if (sock_descriptor > 0) {
FD_SET(sock_descriptor, &read_fds);
}
//Highest File Descriptor Number which is needed for the select function
if (sock_descriptor > maximum_socket_descriptor) {
maximum_socket_descriptor = sock_descriptor;
}
}
//Waiting for something to happen on the master socket. As the wait time is NULL the wait is indefinite
act = select(maximum_socket_descriptor + 1, &read_fds, nullptr, nullptr, nullptr);
if ((act < 0) && (errno != EINTR)) {
printf("Failed_Select");
}
//Any activity on the master socket is treated as an incoming connection
if (FD_ISSET(master_sock, &read_fds)) {
if ((new_sock = accept(master_sock, (struct sockaddr *) &adr, (socklen_t *) &addrlen)) < 0) {
perror("Accept!");
exit(EXIT_FAILURE);
}
//Informing the user of the socket number which will be sued to send and receive messages
printf("This is a New Connection,The socket file descriptor is %d and the IP is : %s on Port : %d\n",
new_sock,
inet_ntoa(adr.sin_addr),
ntohs(adr.sin_port));
// Sending Greeting Message on New Connection
if (send(new_sock, message, strlen(message), 0) != strlen(message)) {
perror("Send!!");
}
puts("Welcome Text Sent Affirmative.");
// Adding new socket to the array of sockets
for (i = 0; i < maximum_clients; i++) {
// Checking if the position is empty
if (client_sock[i] == 0) {
client_sock[i] = new_sock;
printf("Adding new socket to the list of sockets as %d\n", i);
break;
}
}
}
//If not the master socket then it is some i/o activity on some other socket
for (i = 0; i < maximum_clients; i++) {
sock_descriptor = client_sock[i];
if (FD_ISSET(sock_descriptor, &read_fds)) {
//Checking if the activity was for closing and reading the incoming message
if ((value_read = read(sock_descriptor, buff, 1024)) == 0) {
//If someone disconnected, getting their details and printing a message
getpeername(sock_descriptor, (struct sockaddr *) &adr, (socklen_t *) &addrlen);
printf("Disconnected Host. Their , IP %s and PORT %d \n",
inet_ntoa(adr.sin_addr), ntohs(adr.sin_port));
//Closing the socket and marking it as 0 in the list to be reused
close(sock_descriptor);
client_sock[i] = 0;
} else {
//Setting the string terminating NULL byte on the end of the data that is read
buff[value_read] = '\0';
//Echoing back the message that came in the socket
send(sock_descriptor, buff, strlen(buff), 0);
}
}
}
}
return 0;
}