Question
What is wrong with this code? I cannot get the port to connect to the socket at all. When I enter a port number the
What is wrong with this code? I cannot get the port to connect to the socket at all. When I enter a port number the client does nothing.
Instructions:
Implementing doServer(int listenFd) (10 Points):
doServer() should have a loop in which it waits for a client to connect to listenFd. When a client does, it should:
malloc() enough memory for 2 integers
put the file descriptor from accept() in one of those spaces
put the value of threadCount in the other space, and increment threadCount
Make a detached thread to handle this new client. I called my function handleClient(), but you may call yours whatever. Pass the address of your malloc()-ed array.
The loop should then go back for another accept().
void* handleClient(void* vPtr) (10 Points):
(Or whatever you call your function that runs a thread for the client.)The thread id and the file descriptor are passed, but they come in as a void* pointer.
Use another pointer to cast back to int*
Save the file descriptor and thread number in local vars
free() the memory
Print the thread number and do a loop like this:
// II.B. Read command: char buffer[BUFFER_LEN]; char command; int fileNum; char text[BUFFER_LEN]; int shouldContinue = 1; while (shouldContinue) { text[0] = '\0'; read(fd,buffer,BUFFER_LEN); printf("Thread %d received: %s ",threadNum,buffer); sscanf(buffer,"%c %d \"%[^\"]\"",&command,&fileNum,text); // YOUR CODE HERE }
It read()s a line of text from the client into buffer[], and parses the line into a command character, fileNum integer, and quote-delineated text[] string. (The fileNum and text[] may or may not be given, depending upon the value of command.)
Then do the following operations based upon the value of command. Except for QUIT_CMD_CHAR I strongly recommend using a different function for each!
When the function ends just have it do:
printf("Thread %d quitting. ",threadNum); return(NULL);
command == DIR_CMD_CHAR (15 Points):
Open the current directory (named "."). If an error occurs then just send STD_ERROR_MSG back to the client.
Copy as many entries that will fit into a buffer of length BUFFER_LEN. Be sure to put a separating ' ' after each entry.
Close the directory.
command == READ_CMD_CHAR (15 Points):
Open the file with the number fileNum. Get the name from the number with:
char fileName[BUFFER_LEN]; snprintf(fileName,BUFFER_LEN,"%d%s",fileNum,FILENAME_EXTENSION);
read() up to BUFFER_LEN into a buffer. Put a '\0' character at the end of the buffer.
Send that buffer to the client.
Close the file.
If an error occurs during any of this, then send STD_ERROR_MSG back to the client.
command == WRITE_CMD_CHAR (15 Points):
The opposite of READ_CMD_CHAR. fileNum and text have the file number and text respectively from the client. Save that text to the named file. If there is an error send then send STD_ERROR_MSG back to the client. If you succeeded then send STD_OKAY_MSG back to the client.
command == DELETE_CMD_CHAR (10 Points):
fileNum tells the file number of the file to delete. Using the unlink() command. If there is an error send then send STD_ERROR_MSGback to the client. If you succeeded then send STD_OKAY_MSG back to the client.
command == CALC_CMD_CHAR (15 Points):
fork() a child. If fork() fails then send STD_ERROR_MSG back to the client.
For the child, do the following:
char fileName[BUFFER_LEN]; snprintf(fileName,BUFFER_LEN,"%d%s",fileNum,FILENAME_EXTENSION); int inFd = open(fileName,O_RDONLY,0); int outFd = open(OUTPUT_FILENAME,O_WRONLY|O_CREAT|O_TRUNC,0660); int errFd = open(ERROR_FILENAME, O_WRONLY|O_CREAT|O_TRUNC,0660); if ( (inFd < 0) || (outFd < 0) || (errFd < 0) ) { fprintf(stderr,"Could not open one or more files "); exit(EXIT_FAILURE); } close(0); dup(inFd); close(1); dup(outFd); close(2); dup(errFd);
Then run CALC_PROGNAME. If running that fails, then do:
fprintf(stderr,"Could not execl %s ",CALC_PROGNAME); exit(EXIT_FAILURE);
For the parent wait() for the child. If the child crashed or did not return EXIT_SUCCESS then send STD_ERROR_MSG back to the client.
If the child did not crash and returned EXIT_SUCCESS, then read() the first BUFFER_LEN chars from the file named OUTPUT_FILENAME. If there is any more space left in your buffer, then read() from the file named ERROR_FILENAME into the same buffer so that it has BUFFER_LEN chars maximum.
close() both files.
Send your buffer back to the client.
command == QUIT_CMD_CHAR (10 Points):
Just send STD_BYE_MSG back to the client and set shouldContinue to 0 to quit the loop.
/*-------------------------------------------------------------------------* *--- ---* *--- mathServer.c ---* *--- ---* *--- This file defines a C program that gets file-sys commands ---* *--- from client via a socket, executes those commands in their own ---* *--- threads, and returns the corresponding output back to the ---* *--- client. ---* *--- ---* *--- ---- ---- ---- ---- ---- ---- ---- ---- ---* *--- ---* *--- Version 1.0 2017 February 20 Joseph Phillips ---* *--- ---* *-------------------------------------------------------------------------*/
// Compile with: // $ gcc mathServer.c -o mathServer -lpthread
//--- Header file inclusion ---//
#include "mathClientServer.h" #include
//--- Definition of constants: ---//
#define STD_OKAY_MSG "Okay"
#define STD_ERROR_MSG "Error doing operation"
#define STD_BYE_MSG "Good bye!"
#define THIS_PROGRAM_NAME "mathServer"
#define FILENAME_EXTENSION ".bc"
#define OUTPUT_FILENAME "out.txt"
#define ERROR_FILENAME "err.txt"
#define CALC_PROGNAME "/usr/bin/bc"
const int ERROR_FD = -1;
extern void* handleClient(void* vPtr); extern int getServerFileDescriptor();
//--- Definition of functions: ---//
// PURPOSE: To run the server by 'accept()'-ing client requests from // 'listenFd' and doing them. void doServer (int listenFd) { /* Application validity check: */
/* Server clients: */ pthread_t threadId; pthread_attr_t threadAttr; int threadCount = 0; int *iPtr;
/* YOUR CODE HERE: */ while(1) { /* Accept connection to client: */ int conffd = accept(listenFd, NULL, NULL); /* Malloc memory for two integers: */ iPtr = (int *)calloc(2, sizeof(int)); /*Put file descriptor in the first space: */ iPtr[0] = listenFd; // or just listenFd not sure
/* put threadCount into the second space and increment: */ iPtr[1] = threadCount++;
/* Creates detached thread for handleClient and passes the address of iPtr */ pthread_attr_init(&threadAttr); pthread_attr_setdetachstate(&threadAttr, PTHREAD_CREATE_DETACHED); pthread_create(&threadId, &threadAttr, handleClient, (void*)iPtr);
pthread_join(threadId, NULL); pthread_attr_destroy(&threadAttr);
} } void* handleClient(void* vPtr) { /* Read command: */ char buffer[BUFFER_LEN]; char command; int fileNum; char text[BUFFER_LEN]; int shouldContinue = 1; int threadNum; int fd; /* Cast void* vPtr back to an int */ int *iPtr = (int *)vPtr; /* Assign file descriptor to a local value named 'fd'*/ fd = iPtr[0]; /* Assign thread number to local value named 'threadNum'*/ threadNum = iPtr[1]; free(iPtr); while (shouldContinue) { memset(buffer,'\0',BUFFER_LEN); memset(text ,'\0',BUFFER_LEN);
read(fd,buffer,BUFFER_LEN); printf("Thread %d received: %s ",threadNum,buffer); sscanf(buffer,"%c %d \"%[^\"]\"",&command,&fileNum,text);
/* YOUR CODE HERE: */ if(command == DIR_CMD_CHAR) { /* 1. Open the current directory (named "."). If an error occurs then just send STD_ERROR_MSG back to the client: */ DIR* dirPtr = opendir("."); struct dirent* entryPtr; /* If error occurs send STD_ERROR_MSG to client: */ if ((dirPtr = opendir (".")) == NULL) { { write(fd, STD_ERROR_MSG, sizeof(STD_ERROR_MSG)); //return(EXIT_FAILURE); } /* Read as many entries that will fit into BUFFER_LEN put as many entries into the buffer and send the buffer to client d_name=entryPtr into the bufffer using strcat_s, make sure buffer starts empty buffer[0]=' '; add new line char using stringcat " " make sure do not go over buffer lengh */ if (dirPtr) { while ((entryPtr = readdir(dirPtr)) != NULL) { buffer[0]='\0'; int i; int sizebuf = sizeof(buffer); for (i = 0; i < sizebuf; i++) { strcat(buffer,entryPtr->d_name); strcat(buffer," "); } } } /* 3. Close directory */ closedir(dirPtr); } else if (command == READ_CMD_CHAR) { /* 1. Open the file with the number fileNum. Get the name from the number with: */ fileNum = open(FILENAME_EXTENSION,O_RDONLY, 0); //Yeah, I think this is right, except with fileNum instead. // changed fd to fileNum /* If error occurs send STD_ERROR_MSG to client: */ if(fileNum < 0) { write(fileNum, STD_ERROR_MSG, sizeof(STD_ERROR_MSG)); // it looks like this is correct exit(1); } /* 2. read() up to BUFFER_LEN into a buffer. Put a '\0' character at the end of the buffer: */ char fileName[BUFFER_LEN]; snprintf(fileName,BUFFER_LEN,"%d%s",fileNum,FILENAME_EXTENSION); fileNum = read(fileNum, fileName, BUFFER_LEN-1); fileName[fileNum] = '\0'; printf("Sending: %s", fileName); write(fileNum, fileName, fileNum); /* Close file: */ close(fileNum); }
else if (command == WRITE_CMD_CHAR) { /* 1. Open the file with the number fileNum in write mode: */ fileNum = open(FILENAME_EXTENSION,O_WRONLY|O_CREAT|O_TRUNC,0660); /* If error occurs send STD_ERROR_MSG to client: */ if(fileNum < 0) { write(fileNum, STD_ERROR_MSG, sizeof(STD_ERROR_MSG)); } if (fileNum >0) { //fileNum and text have the file number and text respectively from the client. //Save that text to the named file. char fileName[BUFFER_LEN]; write (fileNum,fileName, sizeof(fileName)); //If you succeeded then send STD_OKAY_MSG back to the client write(fileNum, STD_OKAY_MSG, sizeof(STD_OKAY_MSG)); } /* Close file: */ close(fileNum); }
else if (command == CALC_CMD_CHAR) { /* Create new fork named calcPid: */ int calcPid = fork(); /* If fork() failed: */ if(calcPid < 0) { write(fd, STD_ERROR_MSG, sizeof(STD_ERROR_MSG)); } /* Child writes files: */ else if(calcPid == 0) { char fileName[BUFFER_LEN]; snprintf(fileName,BUFFER_LEN,"%d%s",fileNum,FILENAME_EXTENSION);
int inFd = open(fileName,O_RDONLY,0); int outFd = open(OUTPUT_FILENAME,O_WRONLY|O_CREAT|O_TRUNC,0660); int errFd = open(ERROR_FILENAME, O_WRONLY|O_CREAT|O_TRUNC,0660);
if ( (inFd < 0) || (outFd < 0) || (errFd < 0) ) { fprintf(stderr,"Could not open one or more files "); exit(EXIT_FAILURE); }
close(0); dup(inFd); close(1); dup(outFd); close(2); dup(errFd); /* Run CALC_PROGNAME, if fails generate output: */ execl(CALC_PROGNAME,CALC_PROGNAME,fileName,NULL); fprintf(stderr,"Could not execl %s ",CALC_PROGNAME); exit(EXIT_FAILURE);
} /* Parent reads files: */ else { /* Wait and check status of child process, if it crashes return STD_ERROR_MSG: */ int status; pid_t return_pid = waitpid(calcPid, &status, WNOHANG); if (return_pid == -1) write(fd, STD_ERROR_MSG, sizeof(STD_ERROR_MSG)); /* If child process EXIT_SUCCESS, then run parent process: */ if (return_pid == calcPid) { char fileName[BUFFER_LEN]; snprintf(fileName,BUFFER_LEN,"%d%s",fileNum,FILENAME_EXTENSION); int numBytes = 0; int outFd = open(OUTPUT_FILENAME,O_RDONLY|O_CREAT,0660); int errFd = open(ERROR_FILENAME, O_RDONLY|O_CREAT,0660);
if ( (outFd < 0) || (errFd < 0) ) { fprintf(stderr,"Could not open one or more files "); exit(EXIT_FAILURE); } while ( (numBytes = read(outFd, fileName, BUFFER_LEN)) > 0) read(errFd, &fileName[numBytes], BUFFER_LEN); close(0); dup(outFd); close(1); dup(errFd); } } } else if (command == DELETE_CMD_CHAR) { if (fileNum > 0) { fileNum = unlink(buffer); write(fd, STD_OKAY_MSG, sizeof(STD_OKAY_MSG)); } else write(fd, STD_ERROR_MSG, sizeof(STD_ERROR_MSG)); } else if (command == QUIT_CMD_CHAR) { /* Send STD_BYE_MSG back to the client and set shouldContinue to 0 to quit the loop: */ write(fd, STD_BYE_MSG, sizeof(STD_BYE_MSG)); shouldContinue = 0; } } } printf("Thread %d quitting. ",threadNum); return(NULL); }
// PURPOSE: To decide a port number, either from the command line arguments // 'argc' and 'argv[]', or by asking the user. Returns port number. int getPortNum (int argc, char* argv[] ) { // I. Application validity check:
// II. Get listening socket: int portNum;
if (argc >= 2) portNum = strtol(argv[1],NULL,0); else { char buffer[BUFFER_LEN];
printf("Port number to monopolize? "); fgets(buffer,BUFFER_LEN,stdin); portNum = strtol(buffer,NULL,0); }
// III. Finished: return(portNum); }
// PURPOSE: To attempt to create and return a file-descriptor for listening // to the OS telling this server when a client process has connect()-ed // to 'port'. Returns that file-descriptor, or 'ERROR_FD' on failure. int getServerFileDescriptor (int port ) { // I. Application validity check:
// II. Attempt to get socket file descriptor and bind it to 'port': // II.A. Create a socket int socketDescriptor = socket(AF_INET, // AF_INET domain SOCK_STREAM, // Reliable TCP 0);
if (socketDescriptor < 0) { perror(THIS_PROGRAM_NAME); return(ERROR_FD); }
// II.B. Attempt to bind 'socketDescriptor' to 'port': // II.B.1. We'll fill in this datastruct struct sockaddr_in socketInfo;
// II.B.2. Fill socketInfo with 0's memset(&socketInfo,'\0',sizeof(socketInfo));
// II.B.3. Use TCP/IP: socketInfo.sin_family = AF_INET;
// II.B.4. Tell port in network endian with htons() socketInfo.sin_port = htons(port);
// II.B.5. Allow machine to connect to this service socketInfo.sin_addr.s_addr = INADDR_ANY;
// II.B.6. Try to bind socket with port and other specifications int status = bind(socketDescriptor, // from socket() (struct sockaddr*)&socketInfo, sizeof(socketInfo) );
if (status < 0) { perror(THIS_PROGRAM_NAME); return(ERROR_FD); }
// II.B.6. Set OS queue length: listen(socketDescriptor,5);
// III. Finished: return(socketDescriptor); }
int main (int argc, char* argv[] ) { // I. Application validity check:
// II. Do server: int port = getPortNum(argc,argv); int listenFd = getServerFileDescriptor(port); int status = EXIT_FAILURE;
if (listenFd >= 0) { doServer(listenFd); close(listenFd); status = EXIT_SUCCESS; }
// III. Finished: return(status); }
Step by Step Solution
There are 3 Steps involved in it
Step: 1
Get Instant Access to Expert-Tailored Solutions
See step-by-step solutions with expert insights and AI powered tools for academic success
Step: 2
Step: 3
Ace Your Homework with AI
Get the answers you need in no time with our AI-driven, step-by-step assistance
Get Started