In: Computer Science
A limitation of the chat server is that it can handle only one client because it is a single threaded application. Using the pThread library, modify the chat server so that it can handle multiple clients simultaneously, i.e., by creating a new thread whenever a client is connected so that the client is handled individually with a new thread, and at the same time, by having the main thread (i.e., the thread that runs the main function) of the chat server continue to wait for an incoming connection from a client.
The current implementation of the chat server allows the server to exchange messages with a client individually. Modify the server code so that when the server sends a message, that message is sent to all connected clients. We will test your program with three clients.
Create another thread for the chat server that broadcasts current system time to all connected clients every 5 seconds. For example, all clients should receive a message containing current system time periodically and print it out.
Server.c
#include <stdio.h>
#include <netdb.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#define MAX 80
#define PORT 8080
#define SA struct sockaddr
#define MAX 80
#define PORT 8080
#define SA struct sockaddr
// Function designed for chat between client and server.
void func(int sockfd)
{
char buff[MAX];
int n;
// infinite loop for chat
for (;;) {
bzero(buff, MAX);
// read the message from client and copy it in buffer
read(sockfd, buff, sizeof(buff));
// print buffer which contains the client contents
printf("From client: %s\t To client : ", buff);
bzero(buff, MAX);
n = 0;
// copy server message in the buffer
while ((buff[n++] = getchar()) != '\n')
;
// and send that buffer to client
write(sockfd, buff, sizeof(buff));
// if msg contains "Exit" then server exit and chat ended.
if (strncmp("exit", buff, 4) == 0) {
printf("Server Exit...\n");
break;
}
}
}
// Driver function
int main()
{
int sockfd, connfd, len;
struct sockaddr_in servaddr, cli;
// socket create and verification
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1) {
printf("socket creation failed...\n");
exit(0);
}
else
printf("Socket successfully created..\n");
bzero(&servaddr, sizeof(servaddr));
// assign IP, PORT
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(PORT);
// Binding newly created socket to given IP and verification
if ((bind(sockfd, (SA*)&servaddr, sizeof(servaddr))) != 0) {
printf("socket bind failed...\n");
exit(0);
}
else
printf("Socket successfully binded..\n");
// Now server is ready to listen and verification
if ((listen(sockfd, 5)) != 0) {
printf("Listen failed...\n");
exit(0);
}
else
printf("Server listening..\n");
len = sizeof(cli);
// Accept the data packet from client and verification
connfd = accept(sockfd, (SA*)&cli, &len);
if (connfd < 0) {
printf("server acccept failed...\n");
exit(0);
}
else
printf("server acccept the client...\n");
// Function for chatting between client and server
func(connfd);
// After chatting close the socket
close(sockfd);
}
Client.c
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#define MAX 80
#define PORT 8080
#define SA struct sockaddr
void func(int sockfd)
{
char buff[MAX];
int n;
for (;;) {
bzero(buff, sizeof(buff));
printf("Enter the string : ");
n = 0;
while ((buff[n++] = getchar()) != '\n')
;
write(sockfd, buff, sizeof(buff));
bzero(buff, sizeof(buff));
read(sockfd, buff, sizeof(buff));
printf("From Server : %s", buff);
if ((strncmp(buff, "exit", 4)) == 0) {
printf("Client Exit...\n");
break;
}
}
}
int main()
{
int sockfd, connfd;
struct sockaddr_in servaddr, cli;
// socket create and varification
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1) {
printf("socket creation failed...\n");
exit(0);
}
else
printf("Socket successfully created..\n");
bzero(&servaddr, sizeof(servaddr));
// assign IP, PORT
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
servaddr.sin_port = htons(PORT);
// connect the client socket to server socket
if (connect(sockfd, (SA*)&servaddr, sizeof(servaddr)) != 0) {
printf("connection with the server failed...\n");
exit(0);
}
else
printf("connected to the server..\n");
// function for chat
func(sockfd);
// close the socket
close(sockfd);
}
Client.c
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <fcntl.h> #include <pthread.h> #include <netinet/in.h> #include <sys/socket.h> #include <sys/types.h> #include <arpa/inet.h> void * doRecieving(void * sockID){ int clientSocket = *((int *) sockID); while(1){ char data[1024]; int read = recv(clientSocket,data,1024,0); data[read] = '\0'; printf("%s\n",data); } } int main(){ int clientSocket = socket(PF_INET, SOCK_STREAM, 0); struct sockaddr_in serverAddr; serverAddr.sin_family = AF_INET; serverAddr.sin_port = htons(8080); serverAddr.sin_addr.s_addr = htonl(INADDR_ANY); if(connect(clientSocket, (struct sockaddr*) &serverAddr, sizeof(serverAddr)) == -1) return 0; printf("Connection established ............\n"); pthread_t thread; pthread_create(&thread, NULL, doRecieving, (void *) &clientSocket ); while(1){ char input[1024]; scanf("%s",input); if(strcmp(input,"LIST") == 0){ send(clientSocket,input,1024,0); } if(strcmp(input,"SEND") == 0){ send(clientSocket,input,1024,0); scanf("%s",input); send(clientSocket,input,1024,0); scanf("%[^\n]s",input); send(clientSocket,input,1024,0); } } }
Server.c
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <fcntl.h> #include <pthread.h> #include <netinet/in.h> #include <sys/socket.h> #include <sys/types.h> #include <arpa/inet.h> int clientCount = 0; static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; static pthread_cond_t cond = PTHREAD_COND_INITIALIZER; struct client{ int index; int sockID; struct sockaddr_in clientAddr; int len; }; struct client Client[1024]; pthread_t thread[1024]; void * doNetworking(void * ClientDetail){ struct client* clientDetail = (struct client*) ClientDetail; int index = clientDetail -> index; int clientSocket = clientDetail -> sockID; printf("Client %d connected.\n",index + 1); while(1){ char data[1024]; int read = recv(clientSocket,data,1024,0); data[read] = '\0'; char output[1024]; if(strcmp(data,"LIST") == 0){ int l = 0; for(int i = 0 ; i < clientCount ; i ++){ if(i != index) l += snprintf(output + l,1024,"Client %d is at socket %d.\n",i + 1,Client[i].sockID); } send(clientSocket,output,1024,0); continue; } if(strcmp(data,"SEND") == 0){ read = recv(clientSocket,data,1024,0); data[read] = '\0'; int id = atoi(data) - 1; read = recv(clientSocket,data,1024,0); data[read] = '\0'; send(Client[id].sockID,data,1024,0); } } return NULL; } int main(){ int serverSocket = socket(PF_INET, SOCK_STREAM, 0); struct sockaddr_in serverAddr; serverAddr.sin_family = AF_INET; serverAddr.sin_port = htons(8080); serverAddr.sin_addr.s_addr = htons(INADDR_ANY); if(bind(serverSocket,(struct sockaddr *) &serverAddr , sizeof(serverAddr)) == -1) return 0; if(listen(serverSocket,1024) == -1) return 0; printf("Server started listenting on port 8080 ...........\n"); while(1){ Client[clientCount].sockID = accept(serverSocket, (struct sockaddr*) &Client[clientCount].clientAddr, &Client[clientCount].len); Client[clientCount].index = clientCount; pthread_create(&thread[clientCount], NULL, doNetworking, (void *) &Client[clientCount]); clientCount ++; } for(int i = 0 ; i < clientCount ; i ++) pthread_join(thread[i],NULL); }
The client first needs to connect with the server and can then
issue two commands -
1. GET - This command fetches the list of client's that are
currently connected to server.
2. SEND (client number) (message) - SEND followed by client number
which can be be used to send the message to particular to that
particular client number. (please issue the complete send command
in one go).
To run these program first run ChatServer.c and then run multiple
instatnces of ChatServer.c .
OR
This is the server program,put your client code on different machine and try to connect from multiple client.
#include<stdio.h> #include<string.h> //strlen #include<stdlib.h> //strlen #include<sys/socket.h> #include<arpa/inet.h> //inet_addr #include<unistd.h> //write #include<pthread.h> //for threading , link with lpthread #define MAX 80 #define PORT 6543 #define SA struct sockaddr // Function designed for chat between client and server. void join( pthread_t *thread_id) { if(!pthread_join( *thread_id , NULL)) printf("thread %ld complted\n",*thread_id); pthread_exit(0);//to exit the current thread } void func(int *sockfd) { char buff[MAX]; int n; // infinite loop for chat for (;;) { bzero(buff, MAX); // read the message from client and copy it in buffer read(*sockfd, buff, sizeof(buff)); // print buffer which contains the client contents printf("From client: %s\t To client : ", buff); bzero(buff, MAX); n = 0; // copy server message in the buffer while ((buff[n++] = getchar()) != '\n'); // and send that buffer to client write(*sockfd, buff, sizeof(buff)); // if msg contains "Exit" then server exit and chat ended. if (strncmp("exit", buff, 4) == 0) { printf("Server Exit...\n"); break; } } } // Driver function int main() { int sockfd, connfd, len; struct sockaddr_in servaddr, cli; pthread_t thread_id,jointhread_id; // socket create and verification sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd == -1) { printf("socket creation failed...\n"); exit(0); } else printf("Socket successfully created..\n"); bzero(&servaddr, sizeof(servaddr)); // assign IP, PORT servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = INADDR_ANY; servaddr.sin_port = htons(PORT); // Binding newly created socket to given IP and verification if ((bind(sockfd, (SA*)&servaddr, sizeof(servaddr))) != 0) { printf("socket bind failed...\n"); exit(0); } else printf("Socket successfully binded..\n"); // Now server is ready to listen and verification if ((listen(sockfd, 5)) != 0) { printf("Listen failed...\n"); exit(0); } else printf("Server listening..\n"); len = sizeof(cli); // Accept the data packet from client and verification while(connfd = accept(sockfd, (SA*)&cli, &len)) { if (connfd < 0) { printf("server acccept failed...\n"); exit(0); } else printf("server acccept the client..%d.\n",connfd); if( pthread_create( &thread_id , NULL , func , (void*) &connfd) < 0) { perror("could not create thread"); return 1; } if( pthread_create( &jointhread_id , NULL , join , (void*) &thread_id) < 0) { perror("could not create thread"); return 1; } } // After chatting close the socket close(sockfd); }
first thread is created to handle the client and second thread is created to wait for client thread termination and then exit itself.