Expt 9 Chat
Expt 9 Chat
Aim: To implement a chat server so that multiple users can chat simultaneously
Description
To implement chat server the select function is used. It is a function called by a process. When a
process calls this function , the process goes to sleep and wakes up only when one or more events
occur or when a specified amount of time has passed.
int select (int maxfdp1, fd_set * readset, fd_set * writeset, fd_set * exceptset, const struct
timeval * timeout);
Usage:
fd_set rset;
FD_ZERO(&rset); // all bits off
FD_SET(1, &rset); // turn on bit for fd 1
FD_SET(4, &rset); // turn on bit for fd 4
Initially you have to initialize the set. If we are not interested in a condition we can set that
argument of select to NULL, i.e; for readset, writeset or exceptset.
maxfdp1 argument specifies the number of descriptors to be tested. It is equal to value of max
descriptor to be tested plus one. This is because descriptor starts with 0. When we call select we
specify the values of the descriptors that we are interested in and on return the result indicates
which descriptors are ready. We turn on all the bits in the descriptor sets that we are interested in.
On return of the call, descriptors that are not ready will have the corresponding bit cleared in the
descriptor set.
We can use select to create a server which can handle clients without forking process for each
client.
rset
Client
-1
-1
-1
-1
.
.
.
-1
Descriptors 0, 1, 2 are respectively for standard input, output and error. Next available descriptor is
3 which is set for listening socket. Client is an array that contains the connected socket descriptor
for each client. All elements are initialized to -1. The first non zero for descriptor set is that for the
listening socket. When the first client establishes a connection with the server, the listening
descriptor becomes readable and server calls accept. The new connected descriptor will be 4. The
arrays are updated.
rset
Client
4
-1
-1
-1
.
.
.
-1
Client
4
5
-1
-1
.
.
.
-1
If the first client terminates connection by sending a FIN segment, descriptor 4 becomes readable
and read returns 0. This socket is closed by the server and data structures are updated.
rset
Client
-1
5
-1
-1
.
.
.
-1
The descriptor 4 in rset is set to zero. When clients arrive the connected socket descriptor is placed
in the first available entry, i.e; first entry with value equal to -1.
Program
client
#include<stdio.h>
#include<string.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<fcntl.h>
#include<stdlib.h>
if(argc != 3)
{
fprintf(stderr, "Usage: ./client IPaddress_of_server port\n");
exit(1);
}
bzero((char*)&servaddr, sizeof(servaddr));
bzero(line, sizeof(line));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(atoi(argv[2]));
inet_pton(AF_INET, argv[1], &servaddr.sin_addr);
fd[0] = 0;
fd[1] = sock_fd;
for(; ; )
{
FD_ZERO(&rset);
FD_SET(0, &rset);
FD_SET(sock_fd, &rset);
bzero(line, sizeof(line));
max_fd = sock_fd;
if(FD_ISSET(fd[j], &rset))
{
if(j == 0)
{
n = write(fd[j+1], line, strlen(line));
}
else
{
printf("%s \n", line);
}
if(--nready == 0)
break;
}
}
}
}
server
#include<stdio.h>
#include<string.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<fcntl.h>
#include<stdlib.h>
{
int n, i, maxi, max_fd, k;
int sock_fd, listen_fd, connfd, client_no;
int nready, num_q, client[100], chat[100], conn[1000];
client_no = 0;
if(argc != 2)
{
fprintf(stderr, "Usage: ./server port\n");
exit(1);
}
bzero((char*)&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(atoi(argv[1]));
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
listen(listen_fd, num_q);
max_fd = listen_fd;
maxi = -1;
FD_ZERO(&allset);
FD_SET(listen_fd, &allset);
for(; ;)
{
rset = allset;
nready = select(max_fd + 1, &rset, NULL, NULL, NULL);
if(FD_ISSET(listen_fd, &rset))
{
if((connfd = accept(listen_fd, (struct sockaddr *) &cliaddr, &len))<0)
{
perror("accept failed");
exit(1);
}
chat[++client_no] = connfd;
conn[connfd] = client_no;
k = client_no;
sprintf(buffer, "Client %d has joined chat\n", k);
while(k > 0 )
{
if(chat[k] >0)
n = write(chat[k--], buffer, strlen(buffer));
}
FD_SET(connfd, &allset);
if(connfd > max_fd)
max_fd = connfd;
if(--nready <= 0)
continue;
}
bzero(buffer, sizeof(buffer));
sprintf(buffer, "Client %d has left chat\n", conn[sock_fd]);
k = client_no;
while(k > 0 )
{
if(chat[k] > 0)
n = write(chat[k--], buffer, strlen(buffer));
}
}
else
{
if(chat[line[0] - 48] > 0)
write(chat[line[0] - 48], line, strlen(line));
}
if(--nready <= 0)
break;
}
}
}
Output
The server is started first. Each client then starts. The clients are numbered consecutively. If client x
wants to send message to client y, client x writes
y From x: “contents of message”
The screenshots show 3 clients chatting with each other through the server running on port 5500.
Server
Client 1
Client 2
Client 3