Concurrent Servers December 7, 2000Error-handling sockets wrappersEcho client revisitedEcho client (cont)Slide 5open_streamsock helper functionIterative serversIterative echo serverIterative echo server (cont)Pros and cons of iterative serversConcurrent serversExample: Concurrent echo serverProcess-based concurrent serverProcess-based server (cont)Reaping zombie childrenIssues with process-based designPros and cons of process-based designThreads-based serverThreads-based server (cont)Slide 20Issues with threads-based serversPros and cons of thread-based designselect functionMacros for manipulating set descriptorsselect exampleSlide 26Slide 27I/O multiplexing with selectI/O multiplexing with select (cont)Slide 30Slide 31Slide 32Pro and cons of select-based designConcurrent Servers December 7, 2000 Topics•Baseline iterative server•Process-based concurrent server•Threads-based concurrent server•select-based concurrent serverclass29.ppt15-213“The course that gives CMU its Zip!”CS 213 F’00– 2 –class29.pptError-handling sockets wrappersvoid unix_error(char *msg) { printf("%s: %s\n", msg, strerror(errno)); exit(0);};int Accept(int s, struct sockaddr *addr, int *addrlen) { int rc = accept(s, addr, addrlen); if (rc < 0) unix_error("Accept"); return rc;}To simplify our code, we will use error handlingwrappers of the form:CS 213 F’00– 3 –class29.pptEcho client revisited/* * echoclient.c - A simple connection-based echo client * usage: echoclient <host> <port> */#include <ics.h>#define BUFSIZE 1024int main(int argc, char **argv) { int sockfd; /* client socket */ struct sockaddr_in serveraddr; /* server socket addr struct */ struct hostent *server; /* server's DNS entry */ char *hostname; /* server's domain name */ int portno; /* server's port number */ char buf[BUFSIZE]; /* check command line arguments */ if (argc != 3) { fprintf(stderr,"usage: %s <hostname> <port>\n", argv[0]); exit(0); } hostname = argv[1]; portno = atoi(argv[2]);CS 213 F’00– 4 –class29.pptEcho client (cont) /* create the socket */ sockfd = Socket(AF_INET, SOCK_STREAM, 0); /* initialize the server's socket address struct */ server = Gethostbyname(hostname); bzero((char *) &serveraddr, sizeof(serveraddr)); serveraddr.sin_family = AF_INET; bcopy((char *)server->h_addr, (char *)&serveraddr.sin_addr.s_addr, server->h_length); serveraddr.sin_port = htons(portno); /* request a connection to the server */ Connect(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr));CS 213 F’00– 5 –class29.pptEcho client (cont) /* get a message line from the user */ printf("Please enter msg: "); bzero(buf, BUFSIZE); fgets(buf, BUFSIZE, stdin); /* send message line to server and read its echo */ Write(sockfd, buf, strlen(buf)); bzero(buf, BUFSIZE); Read(sockfd, buf, BUFSIZE); printf("Echo from server: %s", buf); Close(sockfd); exit(0);}CS 213 F’00– 6 –class29.pptopen_streamsock helper functionint open_streamsock(int portno) { int listenfd, optval = 1; struct sockaddr_in serveraddr; /* create a socket descriptor */ listenfd = Socket(AF_INET, SOCK_STREAM, 0); Setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (const void *)&optval , sizeof(int)); /* accept requests to (any IP addr, portno) */ bzero((char *) &serveraddr, sizeof(serveraddr)); serveraddr.sin_family = AF_INET; serveraddr.sin_addr.s_addr = htonl(INADDR_ANY); serveraddr.sin_port = htons((unsigned short)portno); Bind(listenfd, (struct sockaddr *) &serveraddr sizeof(serveraddr)); /* Make it a listening socket ready to accept conn requests */ Listen(listenfd, 5); return listenfd;}CS 213 F’00– 7 –class29.pptIterative serversIterative servers process one request at a time.client 1 server client 2call connectcall acceptret connectret acceptcall connectcall readwriteret readcloseclosecall acceptret connectcall readret readclosewriteret acceptcloseCS 213 F’00– 8 –class29.pptIterative echo server/* * echoserveri.c - iterative echo server * Usage: echoserveri <port> */#include <ics.h>#define BUFSIZE 1024void echo(int connfd);int main(int argc, char **argv) { int listenfd, connfd; int portno; struct sockaddr_in clientaddr; int clientlen = sizeof(struct sockaddr_in); /* check command line args */ if (argc != 2) { fprintf(stderr, "usage: %s <port>\n", argv[0]); exit(0); } portno = atoi(argv[1]);CS 213 F’00– 9 –class29.pptIterative echo server (cont)/* open the listening socket */ listenfd = open_streamsock(portno); /* main server loop */ while (1) { connfd = Accept(listenfd, (struct sockaddr *) &clientaddr, &clientlen); echo(connfd); Close(connfd); }}/* echo - read and echo a line from a client connection */void echo(int connfd) { int n; char buf[BUFSIZE]; bzero(buf, BUFSIZE); n = Read(connfd, buf, BUFSIZE); printf("server received %d bytes: %s", n, buf); Write(connfd, buf, strlen(buf));}CS 213 F’00– 10 –class29.pptPros and cons of iterative servers+ simple- can process only one request at a time•one slow client can hold up thousands of others•Example: echo clients and serverclient 1 server client 2call connectcall acceptcall readret connectret acceptcall connectcall fgetsUser goesout to lunchClient 1 blockswaiting for userto type in dataClient 2 blockswaiting to completeits connection request until afterlunch!Server blockswaiting fordata fromClient 1CS 213 F’00– 11 –class29.pptConcurrent serversConcurrent servers process multiple requests concurrently.•The basic idea is to use multiple control flows to handle multiple requests. Example concurrent server designs:•Fork a new child process for each request.• Create a new thread for each request.•Pre-fork a pool of child processes to handle requests. (not discussed)•Pre-create a pool of threads to handle requests. (not discussed)•Manually interleave the processing for multiple open connections.–Uses Linux select() function to notice pending socket activity–Form of application-level concurrencyCS 213 F’00– 12 –class29.pptExample: Concurrent echo serverclient 1 server client 2call connectcall acceptcall readret connectret acceptcall connectcall fgetsforkchild 1User goesout to lunchClient 1 blockswaiting for user to type in datacall acceptret connectret acceptcall
View Full Document