1 / 20

Concurrent TCP connections

Concurrent TCP connections. A look at design-changes which permit a TCP server to handle multiple clients without delays. Recall design-paradigm. The ‘server’ application. socket(). bind(). The ‘client’ application. socket(). listen(). bind(). 3-way handshake. connect().

bperkins
Download Presentation

Concurrent TCP connections

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Concurrent TCP connections A look at design-changes which permit a TCP server to handle multiple clients without delays

  2. Recall design-paradigm The ‘server’ application socket() bind() The ‘client’ application socket() listen() bind() 3-way handshake connect() accept() read() data flow to server write() write() data flow to client read() close() 4-way handshake close()

  3. Three sockets used The server’s ‘listening socket’ is strictly for one-way communication: it can only receive connection-requests from clients, but it does not receive a client’s data, nor is it able to send any data back to a client The ‘server’ process The ‘client’ process server’s listening socket server’s connection socket client’s connection socket The server’s ‘connected socket’ is for doing two-way communication: it can be used by the server to receive data from its connected client, and it can be used by the server to send data to that connected client

  4. Fast service only • The design-paradigm we just described is OK for servers that reply very quickly to a single client request (as with our original echo application: a short sentence is sent by the client, the server capitalizes all its letters and sends that sentence back, and then the connection is immediately closed • But this design-paradigm is not well-suited for a more general kind of TCP application

  5. Original ‘echo’ example Our ‘server’ application socket() Our ‘client’ application bind() Ask user to type in a short sentence and read reply listen() socket() 3-way handshake connect() accept() The duration of this connection is very brief read() data flow to server write() write() data flow to client read() close() 4-way handshake close()

  6. Delayed-service problem • To demonstrate the problem that arises with our original “iterative server” design, we need to make a small revision in our client’s code – to prolong the duration of the connection of the server to the client • If we ‘cut-and-paste’ a few lines of code, we can arrange for our client to connect to the server before it reads the user’s input

  7. New ‘echo’ example Our ‘server’ application Ask user to type in a short sentence and read reply socket() bind() Our ‘client’ application listen() cut and paste socket() accept() 3-way handshake connect() An indeterminate delay after connection occurs while user types input Ask user to type in a short sentence and read reply read() data flow to server write() write() data flow to client read() close() 4-way handshake close()

  8. Demo: ‘tcpclient2.cpp’ • Run our original ‘tcpserver.cpp’ in one of the windows on your graphical desktop • Then run our revised ‘tcpclient2.cpp’ demo in several other windows at the same time $./tcpserver Server is listening on port 54321 $./tcpclient2 localhost Please type a short sentence: $./tcpclient2 localhost Please type a short sentence: $./tcpclient2 localhost Please type a short sentence:

  9. A ‘concurrent’ server • To avoid such service delays, most TCP servers use a different design-paradigm, taking advantage of UNIX’s multitasking • Each connection-request that the server receives will handled by a different task • The operating system will schedule these multiple tasks to be executed concurrently, so delays by one task will not affect others

  10. Server’s code-outline // the basic steps in an initial ‘concurrent server’ design int sock = socket( AF_INET, SOCK_DGRAM, IPPROTO_TCP ); bind( sock, (sockaddr*)&serveraddr, salen ); listen( sock, 5 ); for(;;) { int conn = accept( sock, (sockaddr*)&clientaddr, &calen ); int pid = fork(); if ( pid == 0 ) // child-process { close( sock ); int rx = read( conn, buf, sizeof( buf ) ); if ( rx > 0 ) write( conn, buf, rx ); close( conn ); exit(0); } // parent-process close( conn ); continue; }

  11. No change in ‘connection-setup’ The ‘server’ process The ‘client’ process server’s listening socket server’s connection socket client’s connection socket The server’s ‘listening socket’ is strictly for one-way communication: it can only receive connection-requests from clients, but it does not receive a client’s data, nor is it able to send any data back to a client

  12. Connect, then fork The ‘server’ parent-process parent closes connection-socket server’s listening socket server’s connection socket The ‘client’ process client’s connection socket The ‘server’ child-process server’s listening socket server’s connection socket child closes listening-socket The server’s ‘listening socket’ will not used by the child-process, so it immediately gets closed, and the server’s ‘connection socket’ will not be used by the parent-process, so it immediately gets closed

  13. Server continues ‘listening’ The ‘server’ parent-process Next ‘client’ process server’s listening socket client’s connection socket The ‘server’ child-process The ‘client’ process server’s connection socket client’s connection socket The server’s ‘listening socket’ can continue to receive connection-requests from other clients that are made to the server’s parent-process, while the earlier client is maintaining its connection with the server’s child-process

  14. Demo: ‘tcpserver2.cpp’ • Execute our revised ‘tcpserver2.cpp’ in one of your windows, and again run our ‘tcpclient2.cpp’ demo in other windows • The ‘service delay’ problem has vanished! $./tcpserver2 Server is listening on port 54321 $./tcpclient2 localhost Please type a short sentence: $./tcpclient2 localhost Please type a short sentence: $./tcpclient2 localhost Please type a short sentence:

  15. New problem: ‘zombies’ • When you use the ‘ps’ command to look at the list of all of your processes, you notice that our revised server’s ‘child-processes’ are still residing within the system -- even though they have already terminated – as so called ‘zombie’ processes, and they are using system resources (e.g., memory): $ ps -a

  16. Parent didn’t ‘wait’ • When a child-process exits, its existence is remembered within the Linux system until its parent-process calls one of the ‘wait()’ functions, to find out that child’s status -- and to relinquish its resources • Failure to ‘wait’ could eventually exhaust the system’s memory, preventing further useful work from being done!

  17. But ‘wait()’ blocks! • If a parent calls the usual ‘wait()’ function before its child has terminated, the parent will be put to sleep, and is awakened only when one of its child-processes exits • But putting out server-process to sleep would delay it from accepting any more connection-requests from new clients • To avoid this we need a new mechanism

  18. The SIGCHLD signal • Whenever a process exits, the operating system will automatically notify its parent by delivering a ‘signal’ to the parent • We can arrange for our concurrent server to ‘catch’ any such signals, because then there’s no risk of sleeping if it calls ‘wait()’ • That way, the resources owned by child- processes will get released (no zombies!)

  19. Signal-handler #include <signal.h> // for signal() #include <wait.h> // for wait() void sigchld_action( int signo ) { wait( NULL ); // release a child-process’s resources signal( SIGCHLD, sigchld_action ); // reinstall handler } int main( int argc, char *argv[] ) { signal( SIGCHLD, sigchld_action ); // install handler … }

  20. In-class exercise • Try running our ‘tcpserver3.cpp’ example, which invokes a signal-handler to ‘wait()’ as soon as a child-process calls ‘exit()’ • Now run ‘tcpclient2.cpp’ to satisfy yourself that a ‘zombie’ process is no longer being left in the system to consume resources

More Related