130 likes | 137 Views
15-213 Recitation 10 – 4/22/02. Outline File I/O Networking. James Wilson e-mail: wilson2@andrew.cmu.edu Office Hours: Friday 1:30 – 3:00 Today 6-8pm Wean 520X. Reminders Lab 6: Dynamic Memory Allocator Lab Due 4/22. Unix I/O vs. Standard I/O.
E N D
15-213 Recitation 10 – 4/22/02 Outline • File I/O • Networking James Wilson e-mail: wilson2@andrew.cmu.edu Office Hours: Friday 1:30 – 3:00 Today 6-8pm Wean 520X • Reminders • Lab 6: Dynamic Memory Allocator • Lab Due 4/22
Unix I/O vs. Standard I/O • Standard I/O almost always preferred • Standard I/O a higher-level abstraction than UNIX I/O • Standard I/O models files as a stream, like file descriptors in being full-duplex • Restrictions exist that interact badly with restrictions on sockets • Input function cannot follow an output function (or vise versa) without a call to fflush, fseek, fsetpos, rewind, or and end-of-file
Logging and Network I/O • Have a server set up to receive requests and respond to them. • Read in request, parse, and return response. • Need to read/write to a network stream, and log events to a file for record-keeping purposes • Main loop opens file for logging and spawns children threads • Each thread has own network streams, but shares logging file stream • Use of mutex to lock resources glossed over for now (will be covered in detail)
Reading to/from Network & File • void main () • { • FILE* log; • /* open file */ • log = fopen ( "log.txt“, "a“ ); • while ( true ) • { • /* • * Main Loop (inside thread) • */ • } • fclose ( log ); • }
Reading to/from Network & File • void *thread ( void *vargp ) • { • FILE* stream; • char method[BUFSIZE], uri[BUFSIZE], version[BUFSIZE]; • /* create mutex */ • /* given argument, set file descriptor for proper access to streams */ • childfd = *((int *)vargp); • free(vargp); • /* open file descriptors for reading network socket, set buffer type */ • if ((stream = fdopen(childfd, "r+")) == NULL) • error("ERROR on fdopen"); • setvbuf(stream, NULL, _IONBF, 0); • /* get header off the stream and save */ • fgets(buf, BUFSIZE, stream); • sscanf(buf, "%s %s %s\n", method, uri, version);
Reading to/from Network & File • /* • * Parse, error check, ready for server communication. • */ • /* • * determine size of information to be written back • * in this case, copying from some other stream (buf) • * to the network stream (stream) • */ • /* get size of remaining buffer from stream */ • temp = read ( serverfd, buf, BUFSIZE ); • while ( temp > 0 ) • { • data.byte += temp; • /* • * write current buffered amount to network socket • * get size of remaining buffer from stream • */ • fwrite ( buf, sizeof ( char ), temp, stream ); • temp = read ( serverfd, buf, BUFSIZE ); • }
Reading to/from Network & File • /** init mutex **/ • /** lock mutex **/ • /* write to log file */ • fprintf(log, "%s %s %s %d\n", data.date, data.ip, data.address, data.byte); • /** unlock mutex **/ • /* close network buffer */ • fclose(stream); • }
Networking • Two sides to networking • Client / Server • Distinction is fading • Peer-to-peer systems mean a node is both
Networking: Client Code Path • Clients typically connect to servers, perform a task, then close the connection • Create a socket() • Connect() • Write()/read() • Close()
Networking: Server Code Path • Servers wait for connections and handle them as they arrive • Create a socket() • Bind() to a port • Listen() for connections • Accept() a connection • Select() a ready connection • Read()/Write() • Close() the connection • We’ll focus on TCP, but UDP is just as important
Networking: Server Code: Initialization void CreateTCPServer(){ struct sockaddr_in myAddr; int myAddrLen; int reuseAddrFlg=1; tcpSocketfd=socket(AF_INET,SOCK_STREAM,0); bzero((void *)(&myAddr),sizeof(myAddr)); myAddr.sin_family=AF_INET; myAddr.sin_port= htons((unsigned short)atoi(chatTCPServerPort)); myAddr.sin_addr.s_addr=htonl(INADDR_ANY); setsockopt(tcpSocketfd,SOL_SOCKET,SO_REUSEADDR,(void *)&reuseAddrFlg,sizeof(reuseAddrFlg)); bind(tcpSocketfd,(struct sockaddr *)&myAddr,sizeof(myAddr)); listen(tcpSocketfd,MAX_BACKLOG); }
Networking: Server Code: Main Loop /*** Code to setup allSet, which contains all the sockets we need ***/ while(1){ readSet=allSet; numReadyDescriptors=select(maxfd+1,&readSet,NULL,NULL,NULL); if(FD_ISSET(udpSocketfd,&readSet)){ /* Packet arrived on UDP Socket: Must be chat message: Process it */ ProcessIncomingChatMessage(udpSocketfd); numReadyDescriptors--; if(numReadyDescriptors <= 0) continue; } if(FD_ISSET(tcpSocketfd,&readSet)){ /* Incoming request for new connection */ struct sockaddr_in clientAddr; int clientAddrLen; slavefd=accept(tcpSocketfd,(struct sockaddr *)&clientAddr,&clientAddrLen) ; /*** Save slavefd so we know to check it later ***/ FD_SET(slavefd,&allSet); if(slavefd > maxfd) maxfd=slavefd; fflush(stdout); numReadyDescriptors--; if(numReadyDescriptors <= 0) continue; }
Networking: Server Code: The Rest • Check whether interesting socket descriptors are in the read/write set • Do appropriate action if they are (i.e., read() or write()) • Close() the connection when appropriate