ch5-tcp client server example
TRANSCRIPT
-
8/13/2019 Ch5-TCP Client Server Example
1/47
Chapter 5
TCP Client/ServerExample
-
8/13/2019 Ch5-TCP Client Server Example
2/47
TCP Client-Server Example TCP echo server: main and str_echo
TCP echo client: main and str_cli
Normal startup and termination
POSIX signal handling
Handling SIGCHILD, interrupted system calls,
and preventing zombies Connection abort before accept returns
Crash of server process
-
8/13/2019 Ch5-TCP Client Server Example
3/47
SIGPIPE signal
Crash, reboot, shutdown of server host
Summary of TCP example
Data format: passing string or binary
-
8/13/2019 Ch5-TCP Client Server Example
4/47
TCP Echo Server and Client
To expand this example to other applications,just change what the server does with the client input.
Many boundary conditions to handle: signal, interruptedsystem call, server crash, etc. The first version does nothandle them.
-
8/13/2019 Ch5-TCP Client Server Example
5/47
TCP Echo Server main() Algorithm A typical fork()-based concurrent server
Algorithm outline : Create socket
Bind it to a designated port (supposedly to be a well-knownport)
Allow incoming traffic for any local network interface (wildcardaddress: INADDR_ANY)
Convert it to a listening socket Set up a listening queue
Loop around forever : Block in call to accept(), wait for a client to connect
Spawn a child to handle each client upon successful connection Close listening socket
Execute str_echo()
Close connected socket for child. parent no wait 5
-
8/13/2019 Ch5-TCP Client Server Example
6/47
TCP Echo Server: main
function#include "unp.h"intmain(int argc, char **argv)
{ int listenfd, connfd;pid_t childpid;socklen_t clilen;struct sockaddr_in cliaddr, servaddr;listenfd = Socket(AF_INET, SOCK_STREAM, 0);
bzero(&servaddr, sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_addr.s_addr = htonl(INADDR_ANY);servaddr.sin_port = htons(SERV_PORT);Bind(listenfd, (SA *) &servaddr, sizeof(servaddr));
tcpcliserv/tcpserv01.c
9877
-
8/13/2019 Ch5-TCP Client Server Example
7/47
Listen(listenfd, LISTENQ);for ( ; ; ) {
clilen = sizeof(cliaddr);
connfd = Accept(listenfd, (SA *) &cliaddr, &clilen);if ( (childpid = Fork()) == 0) { /* child process */Close(listenfd); /* close listening socket */str_echo(connfd); /* process the request */exit(0);}
Close(connfd); /* parent closes connected socket*/}
}
-
8/13/2019 Ch5-TCP Client Server Example
8/47
str_echo() Algorithm It provides very simple service for each client
It reads data from a client and echoes it back to theclient
Algorithm outline :
Read a buffer from the connected socket If n (number of characters read) > 0,
Echo back to the client (writen(): p. 89), read again
Else if n < 0 & EINTR (got interrupt), read again Else just n < 0 (error occurred), display error message (and
terminate child process in err_sys())
Else if n = 0 (receipt of FIN from client, the normal scenario),return
8
-
8/13/2019 Ch5-TCP Client Server Example
9/47
TCP Echo Server: str_echo
function#include "unp.h"void
str_echo(int sockfd){
ssize_t n;char line[MAXLINE];for ( ; ; ) {if ( (n = Readline(sockfd, line, MAXLINE)) == 0)
return; /* connection closed by other end */Writen(sockfd, line, n);}
}
lib/str_echo.c
-
8/13/2019 Ch5-TCP Client Server Example
10/47
TCP Echo Client main() Algorithm Algorithm outline :
Check number of commandline arguments It must be 2 (program name and server address)
Quit if not 2 (call to sys_quit())
Open socket
Fill in internet socket address structure
Connect to server
Call str_cli() to handle the rest of the client processing
Exit when no more user input
Note: All errors end up in termination of theclient in this function. Real applications may needto recover differently 10
-
8/13/2019 Ch5-TCP Client Server Example
11/47
TCP Echo Client: main
function#include "unp.h"int main(int argc, char **argv){
int sockfd;
struct sockaddr_in servaddr;if (argc != 2)
err_quit("usage: tcpcli ");sockfd = Socket(AF_INET, SOCK_STREAM, 0);bzero(&servaddr, sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_port = htons(SERV_PORT);Inet_pton(AF_INET, argv[1], &servaddr.sin_addr);Connect(sockfd, (SA *) &servaddr, sizeof(servaddr));str_cli(stdin, sockfd); /* do it all */exit(0);
}
tcpcliserv/tcpcli01.c
-
8/13/2019 Ch5-TCP Client Server Example
12/47
TCP Echo Client: str_cli
function#include "unp.h"voidstr_cli(FILE *fp, int sockfd){
char sendline[MAXLINE], recvline[MAXLINE];
while (Fgets(sendline, MAXLINE, fp) != NULL) {
Writen(sockfd, sendline, strlen(sendline));if (Readline(sockfd, recvline, MAXLINE) == 0)
err_quit("str_cli: server terminated prematurely");Fputs(recvline, stdout);}
}
lib/str_cli.c
-
8/13/2019 Ch5-TCP Client Server Example
13/47
Normal Startup (1/2) To watch the sequence of client/server
To start the server in background :linux% tcpserv01 &
[1] 17870
To check the status of all sockets on a system (-a)
before the client starts :linux% netstat a
Active Internet connections (servers and established)Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 *:9877 *:* LISTEN
Note : The output above shows only partial results, and the outputformat may be different from system to system
13
-
8/13/2019 Ch5-TCP Client Server Example
14/47
Normal Startup (2/2) To start the client on the same machine (using the
loopback address) :linux% tcpcli01 127.0.0.1
Then, check the status of all sockets again :linux% netstat a
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 localhost:9877 localhost:42758 ESTABLISHED
tcp 0 0 localhost:42758 localhost:9877 ESTABLISHED
tcp 0 0 *:9877 *:* LISTEN
Note : The first tcp connection is for the server child, and thesecond is for the client, and the third is the server parent
14
-
8/13/2019 Ch5-TCP Client Server Example
15/47
-
8/13/2019 Ch5-TCP Client Server Example
16/47
Normal Termination (2/2)
server TCPFINserver childreadlinereadline0
server childstr_echomain Server childexitserver TCP(server childclient)
Server childzombie
-
8/13/2019 Ch5-TCP Client Server Example
17/47
Zombie Process
()
-
8/13/2019 Ch5-TCP Client Server Example
18/47
Cleaning Up Zombie Processes
Child processzombie
Zombiechildparentkernel
Parentzombie
kernelsignal(SIGCHLD)
-
8/13/2019 Ch5-TCP Client Server Example
19/47
POSIX Signal Handling
Signal (software interrupt): sent by oneprocess to another process (or to itself) or bythe kernel to a process
SIGCHLD: by the kernel to the parent whena child process is terminated
Disposition of a signal:
catch the signal by a specified signal handler SIG_IGN: ignore it
SIG_DFL: default: terminate or ignore
-
8/13/2019 Ch5-TCP Client Server Example
20/47
signal Function That EnablesSystem Call Restart#include "unp.h"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_INTERRUPTact.sa_flags |= SA_INTERRUPT; /* SunOS 4.x */
#endif} else {
#ifdef SA_RESTARTact.sa_flags |= SA_RESTART; /* SVR4, 44BSD */
#endif}if (sigaction(signo, &act, &oact) < 0)return(SIG_ERR);
return(oact.sa_handler);}
singalsystem callrestart
Posixsignal dispositionsigactionsignalsigaction
lib/signal.c
-
8/13/2019 Ch5-TCP Client Server Example
21/47
-
8/13/2019 Ch5-TCP Client Server Example
22/47
Handling Zombies
Whenever we fork children, we must waitfor them to prevent them from becoming
Zombies
To do this, we establish a signal handler to
cache SIGCHLD
and within the handler we call wait.
-
8/13/2019 Ch5-TCP Client Server Example
23/47
Signal Handler for SIGCHLD
#include "unp.h"voidsig_chld(int signo){
pid_t pid;int stat;pid = wait(&stat);
printf("child %d terminated\n", pid);return;}
tcpcliserv/sigchldwait.c
child
process id
waitchildzombie
-
8/13/2019 Ch5-TCP Client Server Example
24/47
Interrupted System Calls
kernelSIGCHLD signalparentparentblockacceptsystem callsystem callinterrupthandler
signal handler returninterruptedsystem callrestartsystem call(EINTR) signalrestart system call
EINTRAccept(abort)
-
8/13/2019 Ch5-TCP Client Server Example
25/47
Handling Interrupted SystemCalls
Definition: Slow system call system call that canblock forever
Some kernels automatically restart some interrupted
system calls, while some dont We must prepare for slow system calls to return EINTR
for ( ; ; ){clilen = sizeof (cliaddr);
if ( (connfd = accept (listenfd, (SA) &cliaddr, &clilen)) < 0) {if (errno == EINTR) continue; /* back to for ( ) */else err_sys (accept error);
}restart acceptsystem call
-
8/13/2019 Ch5-TCP Client Server Example
26/47
-
8/13/2019 Ch5-TCP Client Server Example
27/47
Client terminates all fiveconnections
catching all SIGCHLD signals in server parent
-
8/13/2019 Ch5-TCP Client Server Example
28/47
SIGCHLD HandlerUsingWaitpid
#include "unp.h"voidsig_chld(int signo){
pid_t pid;int stat;
while ( (pid = waitpid(-1, &stat, WNOHANG)) > 0)printf("child %d terminated\n", pid);return;
}
#include pid_t waitpid (pid_t pid, int *statloc, int options);
returns: process ID if OK, o, or -1 on error
Wait for the first terminated child
Not block if there areno terminated children
-
8/13/2019 Ch5-TCP Client Server Example
29/47
Final (correct) Version of TCPEcho Serverhandling SIGCHLD, EINTR from accept, zombies
#include "unp.h"intmain(int argc, char **argv)
{int listenfd, connfd;pid_t childpid;socklen_ t clilen;struct sockaddr_in cliaddr, servaddr;void sig_chld(int);
listenfd = Socket(AF_INET, SOCK_STREAM, 0);bzero(&servaddr, sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_addr.s_addr = htonl(INADDR_ANY);servaddr.sin_port = htons(SERV_PORT);Bind(listenfd, (SA *) &servaddr, sizeof(servaddr));
Listen(listenfd, LISTENQ);
tcpcliserv/tcpserv04.c
-
8/13/2019 Ch5-TCP Client Server Example
30/47
-
8/13/2019 Ch5-TCP Client Server Example
31/47
Connection Abort Beforeaccept Returnsimplementation dependent !
In BSD, kernel handles this. accept does not return.In SVR4, accept is returned with EPROTO.
In POSIX.1g, accept is returned with ECONNABORTEDThe server can ignore the error and just call accept again
-
8/13/2019 Ch5-TCP Client Server Example
32/47
Crashing of Server ChildProcess
Procedure:1. Kill the child. Server TCP sends FIN to client TCP, which responds with an
ACK. (TCP half-close)(The client process is blocked in fgets when client TCP receives FIN.)
2. SIGCHLD signal is sent to the server parent.3. User inputs. The client process calls writen to send data to server.4. The server TCP responds with an RST.5. The client process returns from readline, 0, when client TCP receives RST.6. The client process terminates.
The client is blocked on the call to fgets when FIN isreceived.(it should block on input from either source)Solution:Use select or poll to block on either socket or stdio
Clientinput
-
8/13/2019 Ch5-TCP Client Server Example
33/47
SIGPIPE Signalwhen writing to a socket that has received an RST
Procedure:1. The client writes to a crashed server process. An RST is received
at the client TCP and readline returns 0 (EOF).2. If the client ignores the error returned from readline and write more,
SIGPIPE is sent to the client process.3. If SIGPIPE is not caught, the client terminates with no output
Problem:
Nothing is output even by the shell to indicate what has happened.(Have to use echo $?to examine the shells return value of last command.)
Solution:1. Setting the signal disposition to SIG_IGN2. Catch the SIGPIPE signal for further processing. (handle EPIPE error
returned from write).
-
8/13/2019 Ch5-TCP Client Server Example
34/47
-
8/13/2019 Ch5-TCP Client Server Example
35/47
-
8/13/2019 Ch5-TCP Client Server Example
36/47
Crash of Server Host
Scenario 1. client and server run on different hosts 2. make a connection between client and server 3. client types something to transmit data to the server 4. disconnect the server host from the network (destination
unreachable) 5. client types something again.
client TCP continuously retx data and timeout around 9 min The client process will then return with the error ETIMEDOUT. If some intermediate router determined that the server host was down
and responded with an ICMPdestination unreachable
message, theerror returned will then be either EHOSTUNREACH or ENETUNREACH
To quickly detect: timeout on readline, SO_KEEPALIVE socketoption, heartbeat functions
-
8/13/2019 Ch5-TCP Client Server Example
37/47
Reboot of Server Host
The client does not see the server hostshut down
Client sends data to server after theserver reboots
server TCP responds to client data with
an RST because it loses all connectioninformation
readline returns ECONNRESET
-
8/13/2019 Ch5-TCP Client Server Example
38/47
Shutdown of Server Host (byOperator)
init process sends SIGTERM to allprocesses
We can catch this signal and close all opendescriptors by ourselves
init waits 5-20 sec and sends SIGKILL
to all processes all open descriptors are closed by kernel
-
8/13/2019 Ch5-TCP Client Server Example
39/47
Summary of TCP Example
From clients perspective:
socket and connect specifies servers port and
IP client port and IP chosen by TCP and IP
respectively
From servers perspective:
socket and bind specifies servers local port andIP
listen and accept return clients port and IP
-
8/13/2019 Ch5-TCP Client Server Example
40/47
TCP Client/Server Clients Perspective
40
-
8/13/2019 Ch5-TCP Client Server Example
41/47
TCP Client/Server Clients Perspective
41
-
8/13/2019 Ch5-TCP Client Server Example
42/47
Data Format: Text Strings
server process gets two numbers (in aline of text) from client and returns
their sum In str_echo: sscanf converts string to
long integer, snprintf converts long
back to string
-
8/13/2019 Ch5-TCP Client Server Example
43/47
str_echo() Adding 2 Numbers
tcpcliserv/str_echo08.c
43
-
8/13/2019 Ch5-TCP Client Server Example
44/47
Data Format: Binary Structure
Passing binary structure between client andserver does not work when the client and server are run on hosts with
different byte orders or sizes of long integer
Since different implementations can store thesame C datatype differently.
Suggestions: pass in string only explicitly define the format of data types (e.g.
RPCs XDR -- external data representation)
-
8/13/2019 Ch5-TCP Client Server Example
45/47
str_cli() Sending 2 Binary Ints
tcpcliserv/str_cli09.c
45
-
8/13/2019 Ch5-TCP Client Server Example
46/47
str_echo() Adding 2 Binary Ints
tcpcliserv/str_echo09.c
46
-
8/13/2019 Ch5-TCP Client Server Example
47/47
Beware of Different Byte Orders
Due to the big-endian and little-endian implementations,sending binary numbers between different machinearchitectures may end up with different results
An example of two big-endian SPARC machines : solaris% tcpcli09 12.106.32.254
11 12 # user input in bold
33 # result back from server
-11 -14
-55
An example of big-endian SPARC and little-endian Intel machines : linus% tcpcli09 206.168.112.96
1 2 # user input in bold
3 # It seems to work
-22 -77
-16777314 # oops! It does not work!