// chatServer.c// the main function of your chatServer#include <stdio.h>#include <signal.h> // signal#include <errno.h>#include <stdlib.h>#include <unistd.h>#include <fcntl.h>#include <string.h>#include "Socket.h"#include "Thread.h"#include "Semaphore.h"#define MAX_THREADS 3#define WORK_POOL 4// The folowing array holds the work to be done. In this program it// contains the socket cookie of the network connection a worker// thread will be responsible for.void *work[WORK_POOL];// Declare some semaphores to control access to the above work array.sem_t *mutex[3];void *workerThread(void *parm){ int bytesrecv; char buf[100]; char send[100]; char filename[100]; int fd; int i; for (;;) { // wait for work to become available //printf("Searching for work: \n"); if (work[0] == NULL && work[1] == NULL && work[2] == NULL && work[3] == NULL) { sleep(60000); } // remove work from the work pool else { for (i = 0; i < WORK_POOL; i++) { if (work[i] != NULL) { bytesrecv = socketRecv(work[i], buf, sizeof(buf)); P(mutex[i]); work[i] = NULL; V(mutex[i]); } // perform work strcpy(filename, (buf + 5)); fd = open(filename, O_RDWR); if (fd == -1) { printf ("File does not exist, sending FAIL to client.\n"); strcpy(send, "FAIL"); socketSend(work[i], send, 512); } else { printf("OK"); while (read(fd, send, 512) > 0) { socketSend(work[i], send, 512); } } } } } return NULL;}// Main takes a single argument, the port number to listen on.int main(int argc, char *argv[]){ // Do not remove the following if/then/else // statement. This setup is needed to deal // with the situation when a write is made to a // socket and the other side has already closed down if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) { perror("sigHandle, SIGPIPE cannot be handled."); exit(-1); } printf("SIGPIPE set to ignore.%d\n", SIGPIPE); // Add your code and variable declarations starting here. // Additional comments indicate some of the *important* // steps the code requires. (i.e Additional actions will be // required for a proper implementation.) The comments should // be taken as suggestions only and you may choose to implement things // differently. int i; for (i = 0; i < WORK_POOL; i++) { work[i] = NULL; } int bytesrecv; struct Socket *server; struct Thread *wk0; struct Thread *wk1; struct Thread *wk2; struct Socket *acc; char buf[100]; // create the semaphores printf("Creating semaphores:\n"); mutex[0] = createSemaphore(4); mutex[1] = createSemaphore(4); mutex[2] = createSemaphore(4); mutex[3] = createSemaphore(4); // Create the workers printf("Creating worker threads:\n"); wk0 = createThread(workerThread, NULL); wk1 = createThread(workerThread, NULL); wk2 = createThread(workerThread, NULL); printf("Running worker threads:\n"); runThread(wk0, NULL); runThread(wk1, NULL); runThread(wk2, NULL); // Create the server socket to listen on printf("Initiating server socket:\n"); server = initSocket(); if (createServerSocket(server, atoi(argv[1])) <= 0) { printf("Create server socket error."); return -1; } // Loop accepting connections for (;;) { // accept a connection printf("Waiting for connection...\n"); acc = socketAccept(server); if (acc != NULL) { printf("socketAccept error\n"); } bytesrecv = socketRecv(acc, buf, sizeof(buf)); if (bytesrecv <= 0) { printf("Socket Receive error."); return -1; } // add connection to the "work" pool. Do proper management // so that a connection is only accepted if there is space // to put an accepted connection if (work[0] == NULL) { P(mutex[0]); work[0] = acc; V(mutex[0]); } else if (work[1] == NULL) { P(mutex[1]); work[1] = acc; V(mutex[1]); } else if (work[2] == NULL) { P(mutex[2]); work[2] = acc; V(mutex[2]); } else if (work[3] == NULL) { P(mutex[3]); work[3] = acc; V(mutex[3]); } else if (work[0] != NULL && work[1] != NULL && work[2] != NULL && work[3] != NULL) { printf("Error, no available space in the work pool.\n"); } }}