Multi-Request Multi-Client Fork-Based TCP
/***************************** Multi-Client TCP ***************************/
#include <sys/types.h> /******* Demo of multi-client application. *******/
#include <sys/socket.h> /******* This is the client. *******/
#include <unistd.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#define BIGBUF 50
#define SIGPIPE_ERROR 1
#define CONNECT_ERROR 2
#define INTERRUPT 3
#define READ_ERROR 4
int active;
main()
{
char buf[256];
void set_up_signals(void);
void readserver(int active, char *buf, int bufsize);
void connect_to_server(void);
set_up_signals();
connect_to_server();
while(printf("Enter string: "), memset(buf, 0, BIGBUF),
fgets(buf, BIGBUF, stdin), strncmp(buf,"quit", 4))
{
writen(active,buf, 1);
writen(acive, buf + 1, BIGBUF - 1); /* Two writes so ignite SIGPIPE */
memset(buf, 0, BIGBUF);
readn(active,buf,BIGBUF);
printf("From server: %s\n", buf);
}
memset(buf, 0, BIGBUF);
strcpy(buf,"quit");
writen(active, buf, 1);
writen(active, buf + 1, BIGBUF - 1);
close(active);
}
void set_up_signals(void)
{
struct sigaction sa;
void pipe_handler(int signum), term_handler(int signum);
sigfillset(&sa.sa_mask);
sa.sa_handler = pipe_handler;
sa.sa_flags = 0;
sigaction(SIGPIPE, &sa, NULL);
sa.sa_handler = term_handler;
sigaction(SIGQUIT, &sa, NULL);
sigaction(SIGINT, &sa, NULL);
}
void connect_to_server()
{
struct sockaddr_in sin;
active = socket(AF_INET, SOCK_STREAM, 0);
memset(&sin, 0, sizeof(struct sockaddr_in));
sin.sin_port = htons(3144);
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = inet_addr("153.18.17.11");
if (connect(active, (struct sockaddr *)&sin, sizeof(sin)) == -1)
{
perror("Bad connection.");
exit(CONNECT_ERROR);
}
}
/**************************** SIGPIPE handler *****************************/
void pipe_handler(int signum)
{
printf("Server disconnected\n");
exit(SIGPIPE_ERROR);
}
/************************* Terminal signal handler ************************/
void term_handler(int signum)
{
char buf[BIGBUF] = {'\0'};
memset(buf, 0, BIGBUF);
strcpy(buf, "quit");
writen(active, buf, BIGBUF);
close(active);
exit(INTERRUPT);
}
int readn(int fd, char *buf, int bytes)
{
int nleft;
int nread;
char *mover = buf;
nleft = bytes;
while (nleft > 0){
if ((nread = read(fd,mover,nleft)) < 0)
return -1; /**** Error!! ****/
else if (nread == 0)
break; /**** EOF! ****/
nleft -= nread;
mover += nread;
}
return (bytes - nleft);
}
int writen(int fd, char *buf, int bytes)
{
int nleft;
int nwritten;
char *mover = buf;
nleft = bytes;
while (nleft > 0){
if ((nwritten = write(fd,mover,nleft)) < 0)
return -1; /**** Error!! ****/
nleft -= nwritten;
mover += nwritten;
}
return bytes;
}
#include <unistd.h> /********** This is the server. *********/
#include <errno.h>
#include <signal.h>
#include <setjmp.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>
#include <sys/wait.h>
#define BIGBUF 50
#define BIND_ERROR 1
#define LISTEN_ERROR 2
#define ACCEPT_ERROR 3
#define FORK_ERROR 4
#define READ_ERROR 5
#define CLIENT_GONE 6
#define TIMED_OUT 7
int active, passive;
main()
{
pid_t pid;
int addr_len;
char buf[256];
struct sockaddr_in client;
void set_up_signals(void);
void create_passive_socket(void);
void readn(int active, char *buffer, int buffer_size);
void writen(int active, char *buffer, int buffer_size);
set_up_signals();
create_passive_socket();
addr_len = sizeof(struct sockaddr_in);
while (1) /***** Server stays alive for ever!!! *****/
{
active = accept(passive, (struct sockaddr *)&client, &addr_len);
if (active < 0)
{
if (errno == EINTR)
{
errno = 0;
continue;
}
else
{
perror("Accept error!");
exit(ACCEPT_ERROR);
}
}
if ((pid = fork()) < 0)
{
perror("Fork error!");
exit(FORK_ERROR);
}
if (pid != 0) /****** Parent ******/
{
close(active);
continue;
}
else /****** Child ******/
{
close(passive);
while(alarm(10), memset(buf, 0, 256),
readn(active, buf, BIGBUF), strncmp(buf, "quit", 4))
{
alarm(0);
writen(active, buf, BIGBUF);
}
exit(0); /***** Don't forget this!!!!! *****/
}
} /*** end while(1) ***/
}
/************** Handle timeout/disappearance of client **************/
void set_up_signals(void)
{
struct sigaction sa;
void alarm_handler(int signum), no_client(int signum),
sigchld_handler(int signum);
sigfillset(&sa.sa_mask); /**** Take care of signals. ****/
sa.sa_flags = 0;
sa.sa_handler = alarm_handler;
sigaction(SIGALRM, &sa, NULL);
sa.sa_handler = no_client;
sigaction(SIGPIPE, &sa, NULL);
sa.sa_handler = sigchld_handler;
sigaction(SIGCHLD, &sa, NULL);
}
void create_passive_socket(void)
{
struct sockaddr_in sin;
passive = socket(AF_INET, SOCK_STREAM, 0);
memset(&sin, 0, sizeof(sin));
sin.sin_port = htons(3144);
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(passive, (struct sockaddr *)&sin, (socklen_t) sizeof(sin)) == -1)
{
perror("Binding error!");
exit(BIND_ERROR);
}
if (listen(passive, 1) < 0)
{
perror("Listen error!");
exit(LISTEN_ERROR);
}
}
/******************* Clear zombie when child finishes. *********************/
void sigchld_handler(int signum)
{
int status;
while (waitpid(-1, &status, WNOHANG) > 0);
}
/*************** Close active socket when client disappears ***************/
void no_client(int signum)
{
close(active);
exit(CLIENT_GONE);
}
/**************** Close active socket when client is timed out *************/
void alarm_handler(int signum)
{
close(active);
exit(TIMED_OUT);
}
int readn(int fd, char *buf, int bytes)
{
int nleft;
int nread;
char *mover = buf;
nleft = bytes;
while (nleft > 0){
if ((nread = read(fd,mover,nleft)) < 0)
return -1; /**** Error!! ****/
else if (nread == 0)
break; /**** EOF! ****/
nleft -= nread;
mover += nread;
}
return (bytes - nleft);
}
int writen(int fd, char *buf, int bytes)
{
int nleft;
int nwritten;
char *mover = buf;
nleft = bytes;
while (nleft > 0){
if ((nwritten = write(fd,mover,nleft)) < 0)
return -1; /**** Error!! ****/
nleft -= nwritten;
mover += nwritten;
}
return bytes;
}
/***************************** Sample Session **************************/
$ ms&
[1] 2110
$ mc
Enter string: hello
From server: hello
Enter string: goodbye
From server: goodbye
Enter string: [2] + Stopped mc
$ mc
Enter string: what
From server: what
Enter string: when
From server: when
Enter string: quit
$ fg
mc
who
Server disconnected
$ mc
Enter string: howdy!
From server: howdy!
Enter string: quit
$