Week 5: TCP Client-Server and UDP Sockets: Module 4, 5 & Chapter 5, 8
Week 5: TCP Client-Server and UDP Sockets: Module 4, 5 & Chapter 5, 8
Objectives
understand normal startup and termination of TCP connections and how to examine the established TCP connections understand the concepts and techniques of signal handling in Unix; understand how to avoid generating zombie child processes at server site; understand the various abnormal terminations of TCP connections and the techniques to make TCP applications more robust.
fputs
TCP client
writen readline
readline writen
TCP server
Normal startup
When the server starts, it calls socket, bind, listen and accept, blocking in the call to accept. When the client start on the same host, the client calls socket and connect, the latter causing TCPs three-way handshake to take place. When the three-way handshake completes, connect returns in the client and accept returns in the server. The connection is established.
Normal termination
When a EOF (^D) is typed, fgets returns NULL and str_cli returns to main, then main terminates. In client site, closing of all open descriptors, so the client socket is closed by the kernel.
This sends a FIN to the server, to which the server TCP responds with an ACK. At this point the server socket is in the CLOSE_WAIT state and the client socket is in the FIN_WAIT_2 state.
When the server TCP receives the FIN, the server child is blocked in a readline, then return 0. This causes the str_echo to return to the server child main. In server site, closing the connected socket by child
a FIN sent from the server to the client, and an ACK sent from the client to the client. The client socket enters the TIME_WAIT state.
Normal termination
Another part of process termination is for the SIGCHLD signal to be sent to the parent when the server child terminates
we dont catch the signal in this case, and the default action of this signal is to be ignored. The child enters the zombie state.
Signal handling
A signal is a notification to a process that an event has occurred. The process doesnt know ahead of time exactly when a signal will occur. Signals can be sent
by one process to another process by the kernel to a process
Every signal has a disposition (the action). We set the disposition of a signal by calling the sigaction function. Three choices for disposition
providing a function that is called whenever a specific signal occurs ignoring a signal by setting its deposition to SIG_IGN setting the default disposition for a signal by setting its disposition to SIG_DFL.
signal function
typedef void Sigfunc(int) Sigfunc *signal(int signo, Sigfunc *func) { struct sigaction act, oact; act.sa_handler = func; sigemptyset(&act.sa_mask); act.sa_flags = 0; if (signo == SIGALRM) #ifdef SA_INTERRUPT act.sa_flags |= SA_INTERRUPT; #endif else #ifdef SA_RESTART act.sa_flags |= SA_RESTART; #endif if (sigaction(signo, &act, &oact) < 0 ) return SIG_ERR; return oact.sa_handler; }
Zombie process
Zombie process is a process which lost its life.
for instance, a process has been terminated, then its child process will be in zombie state. the zombie process has some information about its process ID, termination status, and resource utilisation. It a process terminates, and that process has children in the zombie state, the parent process ID of all the zombie children is set to 1.
The zombie process takes up space in the kernel. Whenever we fork children, we must wait for them to prevent them from becoming zombies.
We can establish a signal handler to catch SIGCHILD and within the handler we call wait.
is used to handle the situation when many child processes raise signals SIGCHLD at about the same time.
If a client establish multiple TCP connections of the concurrent server, each of which is handled by a child process of the server. the solution is to use function waitpid() in a while loop.
Abnormal termination
To make the TCP network applications more robust, we must consider various situations of abnormal termination of TCP connection.
termination of server process SIGPIPE signal problem Crashing of server host Crashing and rebooting of server host shutdown of server host
There is no actual connection between the client and server processes. Each datagram is a self-contained unit of data with the socket address of its destination After receiving the first datagram from the client, the server can use this pair of IP address and port number to send its own datagrams back to the client.
The datagram received by the server process also contains the IP address and the port number of the UDP socket of the client process. unlike TCP which can get the clients IP address and port number from connect(), the server can start communicating after receiving the first datagram.
UDP client
well-know port
socket()
UDP server
socket()
bind()
socket()
bind()
well-know port
connect()
listen()
sendto
recvfrom
blocks until datagram received from a client
close
and sendto() are two functions used to receive and sent datagrams through UDP sockets.
ssize_t recvfrom(int sockfd, void *buff, size_t nbytes, int flags, struct sockaddr *from, socklen_t *addrlen) ssize_t sendto(int sockfd, const void *buff, size_t nbytes, int flags, const struct sockaddr *to, socklen_t addrlen)
read/write to in sendto() is a socket address structure containing IP address and port number of where the data is to be sent. the recvfrom() fills in the socket address structure pointed to by from with the protocol address of who sent the datagram. final argument in sendto() is an integer, while it is a pointer to an integer in recvfrom(). (why?) A NULL for the 5th argument in recvfrom() means that the receiving process is not interested in the socket address of the source of datagram.
TCP
TCP
TCP
client
client
UDP
UDP
UDP
datagram
datagram
Improvements
To solve the problem of verifying received response,
we could allocate another socket address structure by calling
malloc().
We compare the length returned by recvfrom() in the value-result argument and then compare the socket address structure themselves using
memcmp().
This solution could cause another problem that the client will ignore the response from the server if
the server has multiple interface and its kernel choose a different interface for the outgoing datagrams it sends back to the client; if the client sends the datagrams to the non-primary IP address of the interface.
The solution to the problem of server not running is using a connected UDP socket.
the client will receive the asynchronous error from its UDP additional benefits: improved performance and the client will receive the datagrams only from the connected server.
206.62.226.32/27 206.62.226.64/27 Y
A
.66
A connected UDP socket can also be used to determine the outgoing interface that will be used to a particular destination.
connecting B from A, the interface .35 will be the outgoing interface Connecting X from A, the interface .66 will be the one.