The document discusses a TCP echo client-server program. It includes:
1. An overview of how the client reads input, writes it to the server, and the server echoes it back to the client.
2. Descriptions of the echo server and client code, including the main and processing functions.
3. Explanations of normal startup and termination when the client exits gracefully, as well as error handling for events like the server crashing or disconnecting.
In this document
Powered by AI
Introduction to the topics covered including TCP Echo Server, TCP Echo Client, start-up, termination, and signal handling.
Details the process of a TCP Echo Client reading input, sending to the server, which echoes it back.
Main functions of the TCP Echo Server, including socket creation, binding, and echoing received data using str_echo.
Functionality of the TCP Echo Client including socket creation and data reading/writing with the server using str_cli.
Detailed loop for reading input from client, sending to server, and handling server response.
Overview of connection establishment in TCP, processes blocking on input, and parent/child server interactions.
Process of normal termination for both client and server upon receiving EOF or FIN, and handling of child processes.
Aborted connections handled by TCP, comparison of behavior across different Unix implementations regarding errors.
Handling premature server termination scenarios and client responses to FIN and RST signals.
Impact of server crashes on client applications and handling reconnect scenarios after crashes.
Handling of process terminations and signal processes during system shutdown.
Introduction to signal handling in Unix, focusing on SIGCHLD and managing child processes.
Strategies for handling zombies and the use of signals to clean up terminated child processes.
Description of wait and waitpid functions for managing child processes post-termination.
Contents
Introduction
TCP Echo Server
TCP Echo Client
Normal Startup and Termination
Handling SIGCHLD Signals
2.
Introductioon
fgets
stdin writen readline
TCP TCP
stdout client readline writen server
fputs
1. The Client reads a line of text from its standard input
and writes the line to the server.
2. The server reads the line from its network input and
echoes the line back to the client.
3. The client reads the echoed line and prints it on its
standard output.
3.
TCP Echo Server:main Function
Create socket, bind server's well-known
port
Wait for client connection to complete
Concurrent server
G:echo_server.c
4.
TCP Echo Server:str_echo Function
Read a buffer and echo the buffer
str_echo function: echoes data on a socket
#include "unp.h"
void str_echo(int sockfd)
{ ssize_t n;
char buf[MAXLINE];
again:
while ( (n = read(sockfd, buf, MAXLINE)) > 0)
Writen(sockfd, buf, n);
if (n < 0 && errno == EINTR)
goto again;
else if (n < 0)
err_sys("str_echo: read error");
}
5.
TCP echo client.
Create socket, fill in Internet socket
address structure
Connect to server
G:echo_client.c.txt
6.
TCP Echo Client:str_cli Function
Read a line, write to server
Read echoed line from server, write to
standard output
Return to main
Normal Startup
whathappens when something goes wrong: the
client host crashes, the client process crashes,
network connectivity is lost
% tcpserv01 &
% netstat -a
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address
State
tcp 0 0 *:9877 *:*
LISTEN
9.
Normal Startup
linux % tcpcli01 127.0.0.1
When the three-way handshake completes, connect returns in
the client and accept returns in the server.
The connection is established. The following steps then take
place:
The client calls str_cli, which will block in the call to fgets,
because we have not typed a line of input yet.
10.
Normal Startup
When accept returns in the server, it calls fork and the
child calls str_echo. This function calls readline, which
calls read, which blocks while waiting for a line to be sent
from the client.
The server parent, on the other hand, calls accept again,
and blocks while waiting for the next client connection.
11.
Normal Startup
% netstat -a
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 local host:9877 localhost:42758 ESTABLISHED
tcp 0 0 local host:42758 localhost:9877
ESTABLISHED tcp 0 0 *:9877 *:*
LISTEN
% ps -t pts/6 -o pid,ppid,tty,stat,args,wchan
PID PPID TT STAT COMMAND WCHAN
22038 22036 pts/6 S –bash wait4
17870 22038 pts/6 S ./tcpserv01 wait_for_connect
19315 17870 pts/6 S ./tcpserv01 tcp_data_wait
19314 22038 pts/6 S ./tcpcli01127.0 read_chan
12.
Normal Termination
% tcpcli01 127.0.0.1 we showed this line earlier
hello, world we now type this
hello, world and the line is echoed
good bye
good bye
^D Control-D is our terminal EOF character
13.
Steps involved inthe normal termination
of our client and server:
When we type our EOF character, fgets returns a null pointer
and the function str_cli returns.
When str_cli returns to the client main function ,the latter
terminates by calling exit.
Part of process termination is the closing of all open descriptors,
so the client socket is closed by the kernel.
14.
Steps involved inthe normal termination of
our client and server:
When the server TCP receives the FIN, the server child
is blocked in a call to readline ,and readline then returns
0.
The server child terminates by calling exit.
All open descriptors in the server child are closed.
The SIGCHLD signal is sent to the parent when the
server child terminates.
15.
linux % ps -t pts/6 -o pid,ppid,tty,stat,args,wchan
PID PPID TT STAT COMMAND WCHAN
22038 22036 pts/6 S - bash read_chan
17870 22038 pts/6 S ./tcpserv01 wait_for_connect
19315 17870 pts/6 Z tcpserv01 <defu do_exit
16.
Connection Abort beforeaccept Returns
The three-way handshake completes, the connection is established,
and then the client TCP sends an RST(reset).
On the server side the connection is queued by its TCP, waiting for the
server process to call accept when the RST arrives.
Some time later the server process calls accept.
17.
Connection Abort beforeaccept Returns
Berkeley-derived implementations handle the aborted connection
completely within the kernel, and the server process never sees it.
Most SVR4 implementations, however, return an error to the process as
the return from accept, and the error depends on the implementation.
These SVR4 implementations return an errno of EPROTO ("protocol
error"),
But POSIX specifies that the return must be ECONNABORTED
("software caused connection abort") instead.
18.
Connection Abort beforeaccept Returns
The reason for the POSIX change is that EPROTO is also returned
when some fatal protocol-related events occur on the streams
subsystem.
Returning the same error for the nonfatal abort of an established
connection by the client makes it impossible for the server to know
whether to call accept again or not.
In the case of the ECONNABORTED error, the server can ignore
the error and just call accept again.
19.
Termination of ServerProcess
solaris % tcpcli01 206.62.226.35
hello
hello
another line
str_cli: server terminated prematurely
Our client is not expecting to receive an end-of-file at this
point so it quits with the error message “server
terminated prematurely”.
20.
Termination of ServerProcess
We start the server and client and type one line
kill child process. All open descriptors in the child are closed.
This causes a FIN to be sent to the client, and the client TCP
responds with an ACK.
The SIGCHLD signal is sent to the server parent and handled
correctly.
21.
Termination of ServerProcess
Nothing happens at the client. The client TCP receives
the FIN from the server TCP and responds with an ACK,
client process is blocked in the call to fgets waiting for a
line from the terminal.
Type a line of input to the client
Client can send data but server can not…
22.
Termination of ServerProcess
The server TCP responds with an RST
The client process will not see the RST because it calls
readline immediately after the call to writen and readline
returns 0 (EOF) immediately because of the FIN that was
received in Step 2.
client quits with the error message "server terminated
prematurely."
23.
Termination of ServerProcess
When the client terminates , all its open descriptors are closed.
The client's call to readline may happen before the server's RST is
received by the client, or it may happen after. But if the RST
arrives first, the result is an ECONNRESET ("Connection reset by
peer") error return from readline.
24.
Crashing of ServerHost
Disconnect server host from he network and type another line at the
client.
When the server host crashes, nothing is sent out on the existing
network connections.
We type a line of input to the client. The client then blocks in the call
to readline, waiting for the echoed reply.
we will see the client TCP continually retransmitting the data
segment, trying to receive an ACK from the server.
25.
Crashing of ServerHost
Berkeley-derived implementations retransmit the data segment 12
times, waiting for around 9 minutes before giving up. When the
client TCP finally gives up an error is returned to the client
process.
Since the client is blocked in the call to readline, it returns an
error. Assuming the server host crashed and there were no
responses at all to the client's data segments, the error is
ETIMEDOUT.
But if some intermediate router determined that the server host
was unreachable and responded with an ICMP "destination
unreachable' message, the error is either EHOSTUNREACH or
ENETUNREACH.
26.
Crashing and Rebootingof Server Host
We start the server and then the client. We type a line to verify
that the connection is established.
The server host crashes and reboots.
We type a line of input to the client, which is sent as a TCP
data segment to the server host.
When the server host reboots after crashing, its TCP loses all
information about connections that existed before the crash.
Therefore, the server TCP responds to the received data
segment from the client with an RST.
Our client is blocked in the call to readline when the RST is
received, causing readline to return the error ECONNRESET.
27.
Shutdown of ServerHost
When a Unix system is shut down,
The init process normally sends the SIGTERM signal to all
processes ,waits some fixed amount of time ,and then sends the
SIGKILL signal to any processes still running.
This gives all running processes a short amount of time to clean up
and terminate.
If we do not catch SIGTERM and terminate, our server will be
terminated by the SIGKILL signal.
When the process terminates, all open descriptors are closed.
28.
Posix Signal Handling
A signal (software interrupt) : a notification to a process that an
event has occurred.
Signals can be sent
by one process to another process(or itself)
by the kernel to a process
SIGCHLD signal: a signal sent by the kernel whenever a
process terminates, to the parent of the terminating process
29.
Every signal has a disposition (action associated with the signal)
We can provide a function that is called whenever a specific signal
occurs. This function is called a signal handler and this action is
called catching the signal. (SIGKILL(x) and SIGSTOP(X)),
void handler(int signo);
We can ignore a signal by setting its disposition to SIG_IGN.
(SIGKILL(x) and SIGSTOP(X)),
We can set the default disposition for a signal by setting its
disposition to SIG_DFL. (terminate a process on the receipt of a
signal)
SIGCHLD(X),
30.
Handling SIGCHLD Signals
Zombie State
maintain information about the child for the parent
to fetch at some later time
the process ID of the child, its termination status, the
resource of the child(CPU time, memory)
the parent process ID of all the zombie children: 1(init
process)-inherit the children and clean them up
<defunct>
Handling Zombies
space waste of the kernel, out of process
wait for the children to prevent them from becoming
zombies
31.
Handling SIGCHLD Signals
We establish the signal handler by adding the
function call
Signal (SIGCHLD, sig_chld);
in Figure 5.2, after the call to listen.
#include "unp.h"
void sig_chld(int signo)
{
pid_t pid;
int stat;
pid = wait(&stat);
printf("child %d terminatedn", pid);
return;
}
Figure 5.7 Version of SIGCHLD signal handler that calls wait
32.
Tcpserv02 &
tcpcli01 127.0.0.1
hi, there
hi, there
^D
child 16942 terminated
accept error: Interrupted system call
// the parent is blocked in its call to accept when the
SIGCHLD is delivered
//sig_chld function executes, wait fetches the child’PID and
termination status, printf
// kernel causes the accept to return an error of EINTER
wait and waitpidFunctions
#include <sys/wait.h>
pid_t wait(int *statloc);
pid_t waitpid(pid_t pid, int *statloc, int option);
pit_t: the process ID of the terminated child
statloc : the termination status of the child(an integer) is
returned through the statloc pointer.
pid : specify the process ID that we want to wait for.
A value of -1 say to wait for the first of our children to
terminate.
option : specify additional option.
The most common option is WNOHANG.
36.
>tcpserv03 & 21282 p1 S ./tcpserv03
>tcpcli03 206.62.226.35 21284 p1 Z (tcpcli03)
hello 21285 p1 Z (tcpcli03)
hello 21286 p1 Z (tcpcli03)
^D 21287 p1 Z (tcpcli03)
child 21288 terminated
37.
wait and waitpidFunctions
Difference between wait and waitpid
The problem is that all five signals are generated before the signal handler is executed,
and the signal handler is executed only one time because Unix signals are normally not
queued.
we cannot call wait in a loop, because there is no way to prevent wait from blocking if
there are running children that have not yet terminated.
waitpid
we must specify the WNOHANG option: this tells waitpid not to block if there exist
running children that have not yet terminated.
void sig_chld(int signo)
{
pid_t pid;
int stat;
while((pid = waitpid(-1,&stat,WNOHANG)) > 0)
printf("child %d terminatedn", pid);
return;
}