TCP Client–Server Examples Stevens의 UNP를 중심으로 TCP Client-Server - Getting Started Simple TCP Client and Server Client: simplec.c Server: simples.c Simple Daytime Client 26 bytes can be returned, but always need to code in read loop !! Why? Simple Daytime Client – over IPv6 Only runs on IPv6, but not runs on IPv4 New application should be written in a manner of protocol independence Error Handling: Wrapper Functions – in files wrap….c Standard Error Functions – lib/error.c Standard Error Functions – lib/error.c Useful UNP Library Functions(1) Useful UNP Library Functions(2) Echo Client-Server - with Concurrent Processes TCP Echo Client tcpcliserv/tcpcli01.c: stdin stdout lib/str_cli.c: fgets fputs TCP Client writen readline TCP Server Server는 동시에 여러 Client를 지원해야 한다! 1. Server는 동시에 여러 개의 client의 connection request SYN)를 받아들여야 한다. 2. Listening socket에 connection completion queue 가 있다 listen(listenfd, …): queue의 크기를 선언하고, listening socket으로 만듬 connfd = accept(listenfd, …): queue에서 connection이 완료된 connected socket을 가져옴 Server는 연결된 여러 개의 client가 보낸 데이터 (request)를 지체없이 처리해서 response해야 한다. Iterative Server 연결 후 client의 request를 차례로 반복적으로(loop을 돌면서) 처리 Client의 연결시간이 길면 지원하기 곤란 Concurrent Server Concurrent processes를 이용 Multi-thread 이용 기타 다른 방법: I/O Multiplexing, Non-blocking UNIX Process Creation Fork: create a new process Exec: replace current process image with the new executable file Typical Concurrent Servers Server Before accept listenfd After return from accept listenfd connfd After fork return listenfd connfd fork After close sockets Client connection request connection connection connect() connect() connect() listenfd connfd listenfd connfd connect() TCP Server (Parent) TCP Echo Server tcpcliserv/tcpserv01.c: fork writen TCP Client readline writen TCP Client readline lib/str_echo.c: readline writen TCP Server (Child) readline writen fork TCP Server (Child) Problems in this Echo Server 정상 종료후에도 child는 zombie process로 남아 있음 UNIX에서는 child process가 끝나도 parent가 child의 termination status 등의 정보를 전달받을 때 까지 zombie process로 남음 When a child process is terminated, the signal SIGCHLD is delivered to the parent automatically. Solution 최대 process개수를 초과하게 되면 process를 더 이상 fork할 수 없게 됨 새로운 명령을 내릴 수 없음 (먹통) The parent process should receive the SIGCHLD signal and get the exit status of child process (wait() or waitpid()) + handling interrupted system call (due to the signal handling) 비정상 종료(Abnormal Termination) 경우도 처리해야 Client host crashes Client process crashes Network connectivity is lost, and so on Posix Signal Handling Signal(software interrupt) can be sent asynchronously by one process to another process(or to itself) by the kernel to a process Signal disposition (or actions) catch: call a signal handler ignore: SIG_IGN default:SIG_DFL SIGKILL and SIGSTOP cannot be caught nor ignored Normally, the process receiving a signal is terminated Ignored for SIGCHLD and SIGURG signal() vs Posix sigaction() Posix Signal Semantics Once a signal handler is installed, it remains installed Classical UNIX signal is not… While a signal handler is executing, the signal being delivered is blocked Signals are not queued(delivered only one time) may lost Correct TCP Echo Server tcpcliserv/tcpserv04.c: with Concurrent Processes Data Format Exchange Potential problems in exchanging data structure Solutions different format of binary numbers: big endian, little endian different implementation of C data type: e.g) long, int, short different implementation packing and alignment of structures pass all the numeric data as text string define and use common exchange format - e.g) RPC TCP 상의 application protocol은 통상 PDU를 사용하지 않고 textual syntax를 사용함. Why? Echo Client-Server - with I/O Multiplexing Filling the Pipe: Echo C/S In stop-and-wait mode stdin stdout response time = RTT(round-trip time) + server’s processing time(=0) batch mode로(file을 stdin으로 redirection해서) 1000 line을 보내면 1000 x response time fgets fputs TCP Client writen readline TCP Server Continuous Tx Fill the pipe Blocking I/O Model I/O Multiplexing Model Blocking I/O versus I/O Multiplexing Blocking I/O I/O Multiplexing read() select() read() read() Ready! read() Ready! read() Usage of I/O Multiplexing Client handles an interactive input and a socket handles multiple sockets at the same time Server handles both a listening socket and its connected socket handles both TCP and UDP handles multiple services and perhaps multiple protocols (e.g., inetd daemon) Select Functions Socket API가 아님 #include <sys/time.h> /* UNIX */ #include <sys/select.h> /* UNIX */ #include <unistd.h> /* UNIX */ #include <winsock2.h> /* Windows */ int select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, const struct timeval *timeout); Returns: count of ready descriptors if positive, 0 on timeout, -1 on error Read Write Exception set set set Wait for any one of multiple events to occur and wake up the process only when one or more of these events occurs or, a specified amount of time has passed wait forever: timeout = NULL wait up to a fixed amount of time polling: do not wait at all: timer value = 0 ready ? read write exception handling readset, writeset, exceptset after select returns may be changed Need to set them again for testing file descriptors ready How to Manipulate Descriptor Sets Descriptor sets(fd_set): array of integers(FD_SETSIZE) if fdset == NULL, no interest on the condition caution: value result arguments Macros Conditions for Descriptor Ready A socket is ready for reading (readable) A socket is ready for writing (writable) data in socket receive buffer >= low-water mark SO_RCVLOWAT(==1, default) read-half of connection is closed (TCP has received a FIN) listening socket and # of completed connections > 0 socket error is pending available space in socket send buffer >= low-water mark SO_SNDLOWAT ( == 2048, default (TCP, UDP)) write-half connection is closed: write() will generate SIGPIPE and return error EPIPE A socket using nonblocking connect has completed the connection, or the connect has failed socket error is pending Socket has an exception condition pending if there exists out-of-band data still at out-of-band mark Echo client - using I/O Multiplexing EoF on input close socket 남은 reply를 socket에서 read 불가능 UNP Echo client (using shutdown) UNP TCP Echo Server - I/O Multiplexing TCP Echo Server – I/O Multiplexing UNP Echo Client-Server - with Threads Introduction Process Overhead in process creation(fork) Thread: light-weight process memory is copied all descriptor are duplicated IPC required to pass information between parent and child processes after fork All threads within a process share the same global memory raises synchronization and mutual exclusion problems 10 - 100 times faster than process creation Many different thread implementation Pthread: Posix thread Shared and Own data in Threads Shared information process instructions most data open files (e.g., descriptor) signal handlers and signal dispositions current working directory user and group IDs Thread’s own data thread ID set of registers stack errno signal masks priority Thread Creation and Termination Thread attributes priority initial stack size daemon thread or not: detached or joinable thread default: NULL Terminating a thread implicit termination when thread starting function returns explicit termination pthread_exit exit A Simpler Version of str_cli using Threads UNP TCP Echo Server using Threads threads/tcpserv01.c threads/tcpserv02.c – more portable UNP Non-determinism causes time-dependent errors Non-determinism (Race Condition) in C int ndone = 0; /* shared variable */ Thread A: Thread B: ndone++; done--; Compiled output (ASM) LOAD ndone INCR LOAD ndone DECR STORE ndone STORE ndone Result ?? An instruction is atomic (indivisible), but a statement may be divisible !! Shared variables should be used in mutually exclusive manner Critical region: code region accessing share variable Mutual Exclusion Shared data! Critical region For shared data count Condition Variables unlock lock mutex Critical section wait condition Shared variable wait for condition and wake up one thread wait for condition and wake up all thread signal Example: Condition Variables Interprocess Communication via UNIX Domain Protocols UNIX Domain Sockets A UNIX IPC method Absolute pathname is used instead of protocol address and port number Stream socket: similar to TCP socket Datagram socket: similar to UDP socket An unreliable datagram service that preserves record boundary may be discarded (receiver가 빨리 읽어내지 못하면) Normally, used for passing descriptor Usage of UNIX domain socket Twice as fast as a TCP socket on the same host Used when passing descriptors between processes on the same host (using sendmsg(), recvmsg()); Provides client’s credentials (UID, GID) to the server UNIX Domain Stream Client/Server unixdomain/unixstrcli01.c unixdomain/unixstrserv01.c UNP UNIX Domain Datagram Protocol unixdomai/unixdgcli01.c unixdomai/unixdgserv01.c UNP Binding client address (pathname) is necessary to identify client