190 likes | 333 Vues
Programming with TCP – II. Sending/Receiving Data on Connected TCP Sockets Concurrent Servers fork () shutdown () Half - close “ howto ” argument. Sending/Receiving Data on Connected TCP Sockets. Two functions are used to send/receive data from/to connected TCP sockets.
E N D
Programmingwith TCP – II Sending/Receiving Data on Connected TCP Sockets ConcurrentServers fork() shutdown() Half-close “howto” argument
Sending/Receiving Data on Connected TCP Sockets • Two functions are used to send/receive data from/to connected TCP sockets. • send/ writetosend (cannotusesendto) • recv/ readtoreceive (cannotuserecvfrom)
Notes: (1) • TCP pipe is a byte-stream. Meaningthatmessageboundariesare not preserved. SenderReceiver Specifiesthemax. # of bytesyouwanttoread send(“AA”); send(“BBB”); Recv(buffer,10) Can receiveAABBB all at once Can receivejustAAB Can receivejustA …. There is no waytotellbeforehandhowmuch data “recv” willreturnalthoughwespecified 10 bytes! Ex: TcpServer.c & TcpClient.c
Notes: (2) • TCP connection (pipe) is full-duplex. Eachpeer can send/receivethroughthepipe. Ex: TcpEchoServer.c & TcpEchoClient.c
Notes: (3) • Can wewrite a receivefunctionthatdoes not returnbeforereading a specifiedamount of bytes? Ifyes, how? Ex: TcpFullReadServer.c / Same is trueforSEND.
Notes: (3) • Whatifwewanttodelimitmessageboundaries? (framing problem) • Needto put explicitmarkerswithinthemessages. • Idea 1: Beforesendingthemessage, sendthenumber of bytesthatmakeupthemessage. • RecallContent-Length:__ header in HTTP. Ex: TcpMessageClient.c & TcpMessageServer.c
Notes: (3) cont. • Idea 2: Usesentinelcharactesto mark thebeginningandend of messages. • Recall“\r\n”to mark theend of eachheaderline in HTTP, SMTP, FTP. Ex: GET index.html HTTP/1.1\r\n Host: 10.10.100.180\r\n \r\n <Message Body> Ex: TcpLineReaderSlow.c & TcpLineReaderFast.c
ConcurrentServers • So far wehavecoverediterativeservers: listenfd = socket(TCP); bind(listenfd, ...); listen(listenfd, 10); while(1){ connfd = accept(listenfd, ...); while(morerequeststoserve){ read(connfd, ...); write(connfd, ...); } close(connfd); } Whilethe server is serving a client, it cannotacceptconnectionsfromotherclientsandservethem. Service a client • Ex: TcpEchoServer.c • When a clientrequesttakeslongto service, • the server is tiedupwith a singleclient.
ConcurrentServerscont. • Question: How can wehandlemultipleclients at thesame time? • Concurrentservers • Allnon-trivialserversareconcurrent. E.g. FTP Server, HTTP Server, SMTP Server, ... • 2 waystowrite a concurrent server • Forka heavyweightprocessforeachacceptedconnection (thisclass) • Create a threadtohandleeachacceptedconnection (nextclass)
Outline of a Typical CS usingfork listenfd = socket(TCP); bind(listenfd, ...); listen(listenfd, 10); while(1){ connfd = accept(listenfd, ...); if(fork() == 0){ close(listenfd); // childcloseslisteningsocket doit(connfd); close(connfd); // done withthisclient exit(0); // closeconnection } close(connfd); // parentclosesconnectedsocket } voiddoit(intconnfd){ while(moreclientrequeststoserve){ read(connfd, ...); write(connfd, ...); } } Ex: TcpConcurrentServer1.c
Pointstoconsider.. • Wesaidbeforethatcallingcloseon a TCP socketcausesFINto be sent. Whydoes not closeon connfdbytheparentterminateitsconnectionwiththeclient? • Becauseeverysocketordescriptor has a referencecount. Whenthechildprocess is created, thesocket’sreferencecountis incremented.
Pointstoconsider.. • Whenthe server closesconnfd, thereferencecountis decrementedto 1. Since it is not 0 yet, theconnection is not terminated. It is onlyaftertheclientcallsclose(connfd), thatthereferencecountwill be 0 andtheconnectionwill be terminated. • Noticethatifthe server does not callclose(connfd), referencecountwill be 2. Whenchildcallsclose(connfd), referencecountwill be 1 but theconnectionwillnever be closed. Also, since the server does not closeconnfd, it willrunout of descriptors since there is usually a limit tothenumber of descriptorsthatanyprocess can haveopen at any time.
Pointstoconsider.. • Thedefaultaction of closewith a TCP socket is to mark thesocket as closedandreturntotheprocessimmediately. Thesocketdescriptor is no longerusablebytheprocess: Itcannot be used as an argumenttosend/recv. But, TCP willtrytosendany data that is alreadyqueuedto be sent totheotherend. Afterall data is successfullydelivered, the normal TCP connectionterminationsequencetakesplace.
shutdown()systemcall • Ifyouwanttoclosetheconnectionregardless of whatreferencecountvalue is, you can callshutdown(). • #include<sys/socket.h> • intshutdown(intsockfd, inthowto) • returns 0 if OK, -1 on failure.
shutdown()systemcall • shutdown()should be used in 2 cases • ifyouwantto start TCP connectionterminationsequenceregardless of thevalue of the of referencecount. • Closeterminatesbothdirections of data transfers, bothreading & writing. Since TCP is fullduplex, theremay be timeswhenwewanttotelltheotherendthatwehavefinishedsendingeventhoughthatendmighthavemore data tosend us (calledthehalf-close)
Half-closeexample write data shutdown readreturns > 0 FIN readreturns 0 ACK of data and FIN write data write readreturns > 0 data readreturns > 0 FIN readreturns 0 ACK of data and FIN
shutdown() – SHUT_RD • Theaction of shutdown()depends on thehowtoargument. SHUT_RD: Thereadhalf of theconnection is closed. No more data can be received on thesocketandany data currently in thesocketreceivebuffer is discarded. Theprocess can no longerissueany of thereadfunctions on thesocket. Any data receivedafterthiscall is ACKed, andthensilentlydiscarded.
shutdown() – SHUT_WR • Theaction of shutdown()depends on thehowtoargument. SHUT_WR: Thewrite-half of theconnection is closed. This is called “half-close”. Any data in thesocketsendbufferwill be sent, followedby a FIN. Theprocess can no longerissueany of thewritefunctions on thissocket, but can read(receive) data fromthepeer.
shutdown() – SHUT_RDWR • Theaction of shutdown()depends on thehowtoargument. SHUT_RDWR: Bothreadandwritehalves of theconnectionareclosed. This is equivalenttocallingshutdowntwice: FirstwithSHUT_RDandthenwithSHUT_WR.