tcp sockets

38
1 TCP Sockets Computer Network Programming

Upload: garson

Post on 14-Jan-2016

36 views

Category:

Documents


1 download

DESCRIPTION

TCP Sockets. Computer Network Programming. TCP Echo Server. We will write a simple echo server and client client read a line of text from standard input and wii send it to the server server will read the line from network and will write it back to client - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: TCP Sockets

1

TCP Sockets

Computer Network Programming

Page 2: TCP Sockets

2

TCP Echo Server

• We will write a simple echo server and client

– client read a line of text from standard input and wii send it to the server

– server will read the line from network and will write it back to client

– the client reads the echoed line from network and prints it on the screen

TCP client

TCP server

stdin

stdout

fgets

fputs

writen readline

writen readline

Page 3: TCP Sockets

3

TCP echo Server#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); /* 9877 */

Bind(listenfd, (SA *) &servaddr, sizeof(servaddr));

Listen(listenfd, LISTENQ);

Continued on the next page

Page 4: TCP Sockets

4

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 */

}}

Blue code shows the section of the code that is executed by thechild process.

Page 5: TCP Sockets

5

Wrapper FunctionsintSocket(int family, int type, int protocol){ int n;

if ( (n = socket(family, type, protocol)) < 0) err_sys("socket error"); return(n);}

voidBind(int fd, const struct sockaddr *sa, socklen_t salen){ if (bind(fd, sa, salen) < 0) err_sys("bind error");}

You can find the wrapperfunctions in the source codeof the examples, in filelib/wrapsocket.c

Similarly we have wrapper functions: Accept, Listen, Close, ….

For examples we are usingwrapper functions so that we are not bothered to handle the error cases.

Page 6: TCP Sockets

6

str_echo functionvoidstr_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); }}

Page 7: TCP Sockets

7

tcp echo server

– TCP echo server is concurrent server– We are creating a new child process for every

client request to server that request.– str_echo() function is used to receive and serve

the request (read a line and echo it back). – child process uses exit(0) to terminate at which

time all the open descriptors belonging to the child process is closed.

Page 8: TCP Sockets

8

TCP echo client#include "unp.h"

int main(int argc, char **argv){ int sockfd; struct sockaddr_in servaddr;

if (argc != 2) err_quit("usage: tcpcli <IPaddress>");

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);}

Page 9: TCP Sockets

9

str_cli function

void str_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); }}

Page 10: TCP Sockets

10

Running the application

parentserver

child server

child server

client

client

fork()

fork()

Port# 9877

Port# 9877

Port# 9877Port# 49617

Port# 49616

Run the server and clients on the same host. use the loopback address as the IP address of the host: 127.0.0.1 - localhost

Connection requests come to here

Echo request/reply

Echo request/reply

Page 11: TCP Sockets

11

Running the applicationRun server first: (server is waiting on port 9877)tcpserv01 & netstat -a | grep 9877TCPLocal Address Remote Address Swind Send-Q Rwind Recv-Q State------------ -------------------- ----- ------ ----- ------ ------- *.9877 *.* 0 0 0 0 LISTEN

Run two clients on two different windowstcpcli01 127.0.0.1 (establish connection to the same host)

Execute the netstat command on a third windownetstat -a | grep 9877

*.9877 *.* 0 0 0 0 LISTENlocalhost.49616 localhost.9877 32768 0 32768 0 ESTABLISHEDlocalhost.9877 localhost.49616 32768 0 32768 0 ESTABLISHEDlocalhost.49617 localhost.9877 32768 0 32768 0 ESTABLISHEDlocalhost.9877 localhost.49617 32768 0 32768 0 ESTABLISHED

Page 12: TCP Sockets

12

Running the applicationaspendos{korpe}:> ps -efl | grep tcp 8 S korpe 26623 26613 0 61 20 f63dd718 406 f5e84b8e 12:05:54 pts/17 0:00 tcpcli01 127.0.0.1 8 S korpe 26611 26372 0 61 20 f6230448 406 f62d6b1e 12:05:37 pts/13 0:00 tcpcli01 127.0.0.1 8 S korpe 26595 26360 0 54 20 f65b1780 405 f63aa0d0 11:56:50 pts/12 0:00 tcpserv01 8 S korpe 26624 26595 0 44 20 f66a2898 406 f62d631e 12:05:54 pts/12 0:00 tcpserv01 8 S korpe 26612 26595 0 45 20 f62b0710 406 f5fed4f6 12:05:37 pts/12 0:00 tcpserv01

We can see the processes using the ps command. 3 tcp server processes exists: one parent, two children2 tcp client processes exists. All processes are sleeping (S) because they are blocking on a function call:

parent server: accept()child servers: read()clients: fgets()

Page 13: TCP Sockets

13

Normally terminating the Client

aspendos{korpe}:> netstat -a | grep 9877 *.9877 *.* 0 0 0 0 LISTENlocalhost.49617 localhost.9877 32768 0 32768 0 ESTABLISHEDlocalhost.9877 localhost.49617 32768 0 32768 0 ESTABLISHEDlocalhost.49616 localhost.9877 32768 0 32768 0 TIME_WAITaspendos{korpe}:>

aspendos{korpe}:> ps -efl | grep tcp 8 S korpe 27125 27121 0 43 20 f66a1458 406 f5fed6f6 14:10:02 pts/17 0:00 tcpserv01 8 S korpe 27121 26613 0 54 20 f65b1780 405 f63aa0d0 14:09:41 pts/17 0:00 tcpserv01 8 S korpe 27124 26360 0 41 20 f65b2bc0 406 f64df2c6 14:10:01 pts/12 0:00 tcpcli01 127.0.0.1 8 Z korpe 27123 27121 0 0 0:00 <defunct>

(the output of the ps shows different pids, since I had to restart theclients and server)

I typed ^D as input to one of the clients. The client terminates.

Page 14: TCP Sockets

14

Normal Termination– When we type EOF character (^D) , fgets returns a NULL

pointer and str_cli returns. – Clients call exit(0)– Client process terminates and open descriptors of the client is

closed. Hence a FIN segment is sent to the server and an ACK is received.

– When TCP server receives FİN, this causes and EOF notification to be passed to the read() and server returns with 0 from readline().

– The server child exits with exit(0). – All open descriptors of child is closed and a FIN is sent to the

client and ack ACK is received. Client socket enters to TIME_WAIT state.

– The child server process enters to zombie state (look ps command). A SIGCHLD signal is sent to the parent but not handled.

Page 15: TCP Sockets

15

SIGNALSA signal is a notification to a process that an event has occurred. They are called sometimes software interrupts. Signalls usually occur asynchronously, meaning that the process does not know ahead of time exactly when the signal will occur.

Signals can be sent • by a process to an other process (or to itself)• by kernel to a process

kernel

process1 process2

signal

signalsignal

3-ways that a processcan receive signals

Page 16: TCP Sockets

16

SignalsEvery signal has a disposition: the action associated with the signal. Sigaction function is called to set the action for a signal.

There choices for a disposition

• Provide a function that will be called whenever a specific signal occurs. This function is called signal handler and this action is called catching the signal.

void handler (int signo)SIGKILL and SIGSTOP can not be caught.

• Ignore the signal by setting the disposition to SIG_IGN. SIGKILL and SIGSTOP can not be ignored

• Set a default disposition for a signal by setting its disposition to SIG_DFL.

Page 17: TCP Sockets

17

Signal functionSigfunc *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; /* SunOS 4.x */#endif } else {#ifdef SA_RESTART act.sa_flags |= SA_RESTART; /* SVR4, 44BSD */#endif } if (sigaction(signo, &act, &oact) < 0) return(SIG_ERR); return(oact.sa_handler);}

We write our own signalfunction to set a disposition for a signal.

typedef void Sigfunc(int);

Sigfunc *signal(int signo, Sigfunc *func);

Page 18: TCP Sockets

18

Signal Semantics• Once a signal handler installed, it remains

installed• While a signal handler is executing, the signal being

delivered is blocked. Additional signals that are specified with sa_mask is also blocked.

• If a signal is generated one or more times while its is blocked, it is normally delivered only one time afterthe signal is unblocked. Signals are not queued..

• It is also possible to block and unblock signals using sigprocmask function. This lets us protect certain critical region of the code by preventing certain signals from being caught while that region of code is executing.

Page 19: TCP Sockets

19

Handling SIGCHLD signals• Zombie state: the child stays in this state after

terminating to maintain information about the child so that the parent can fetch some later time. (process ID, termination status, resource utilization information etc).

• We don’t want to leave zombies around. They take up space in the kernel (process table).

• Waiting for a zombie process removes the zombie• Hence, in parent, we have to wait for terminating

children so that they don’t become zombies» waiting means: waiting until the process terminates and

getting the status information after the process terminates.

Page 20: TCP Sockets

20

Waiting for terminating Children

– We should establish a signal handler for SIGCHLD signal: the signal that is sent to the parent when child terminates.

– In the signal handler we should wait for the terminating process - reads it terminating status information.

– Simply call wait or waitpid functions inside signal handler.

Page 21: TCP Sockets

21

SIGCHLD handlerEstablish signal handler by callingsignal (SIGCHLD, sig_chld)

voidsig_chld(int signo){ pid_t pid; int stat;

pid = wait(&stat); printf("child %d terminated\n", pid); return;} aspendos{korpe}:> tcpserv02 &

[1] 28751aspendos{korpe}:> tcpcli01 127.0.0.1testtest^Daspendos{korpe}:> child 28753 terminated

Run the tcp server and client again

Put the signal handler into the tcp server code.

Page 22: TCP Sockets

22

Observations– We type EOF character on the client, client TCP sends FIN to the

server and receives ACK. – The receipt of the FIN delivers EOF to the readline of the child

server. Hence child terminates. – The child sends a SIGCHLD signal to the parent server – The parent server is blocked in the call to accept. The accept() is

interrupted and signal handler for SIGCHLD is executed (sig_chld)– The signal handler reads the termination status of the child by

calling wait and the child is removed from process table - so it does not become a zombie.

– The accept is interrupt, hence it return with errno=EINTR, but some systems automatically restart the accept. For example the Solaris Unix that I tested this program was restaring accept automatically without user program knows about it.

Page 23: TCP Sockets

23

Handling Interrupted system calls

• Some systems does not restart the interrupted system calls automatically, so it the job of the user program to recall the system call if the error value from previous call was errno = EINTR.

• We have seen calling the read and write system calls when the error code as EINTR.

» Look to the readn() and writen() functions that we have seen earlier.

Page 24: TCP Sockets

24

Wait and Waitpid

Wait() waits for the first terminating child and reads its termination status afterthe child terminates. (terminated normally, killed, …etc…)

If multiple childs exits and they terminate at the same time, all SIGCHLD signals will be coming to the server at the same time.

However, the signal handler will catch only one them and the rest will be lost, since the signals are not queued in UNIX.

Hence wait() will be executed only once for the first terminating child, andthe termination status of the other children will not be read, hence theywill become zombies.

pid_t wait(int *statloc); pid_t waitpid (pid_t pid, int *statloc, int options);

Page 25: TCP Sockets

25

Example

serverServerchild1

Serverchild2

Serverchild3

Serverchild4client exit(0)

FIN1FIN2

FIN3

FIN4

SIGCHLDSIGCHLD

SIGCHLDSIGCHLD

Page 26: TCP Sockets

26

Use of waitidvoidsig_chld(int signo){ pid_t pid; int stat;

while ( (pid = waitpid(-1, &stat, WNOHANG)) > 0) printf("child %d terminated\n", pid); return;}

-1 argument states that we are waiting for the first terminating childWNOHANG argument states that we are not blocking on waiting if there arechild processes that are still running.

By use of waitpid we can clean up all the child process that are terminateswithout leaving any zombies behind.

Page 27: TCP Sockets

27

Abnormal Conditions

• Server process that handle the request is killed - crashing of server process

• Crashing of server host

• Crashing and rebooting server host

• Shutdown of the server host

Page 28: TCP Sockets

28

Termination of Server Process

Serverparent

Server childclient

1-We kill thechild2-FIN is sent

to the client

3-ACK is sent to the server child

0- client blocks on fgets()for user input

4- user enters input line

5 - input line is sent

6 - server TCP replies back with RST since there is no server process waiting on the socket - died.

RST7 -read() returns errorand client terminateswith connection reseterror or some other error

a) First, A connection is established between client and server childb) Then the following steps occurs in the order given

Page 29: TCP Sockets

29

SIGPIPE signal

• SIGPIPE signal is sent by kernel to a process who tries to write to a socket who received a RST from the peer TCP.

• We can either catch signal or ignore it. If we ignore than the write operation will return with errno = EPIPE

Page 30: TCP Sockets

30

Crashing of Server Host

Serverparent

Server child

client

1-we type a line of inputand send it to the socket by calling write and the client will block on read() or readline()

a) First, A connection is established between client and server childb) Then the following steps occurs in the order given

Server host

0-we disconnect the serverhost from the network

2-TCP sends the input line asa TCP segment

3-TCP will not receive an ACK, henceit will timout and will retransmit the segment

…………..3-TCP will retransmit the segment couple of times (12)since it will not receive any ACK. Finally it will give up after about 9 minutes.

5- read() will return with error ETIMEOUT(EHOSTUNREACH, ENETUNREACH)

Page 31: TCP Sockets

31

Crashing and rebooting Server Host

Serverparent

Server child

client

a) First, A connection is established between client and server childb) Then the following steps occurs in the order given

0-we disconnect the serverhost from the network

4-TCP sends the input line asa TCP segment

6- read() will return with error ECONNRESET

1-we shutdown the machineand then reboot

All the information about the existing TCP connections are lost

2-we reconnect the machine to the network

3-we type a line of inputand send it to the socket by calling write and the client will block on read() or readline()

5-server TCP replies back with a RST

Page 32: TCP Sockets

32

Shutdown of Server Host

Serverparent

Server child

client

a) First, A connection is established between client and server childb) Then the following steps occurs in the order given

init Process

1. Init processsends SIGTERMand SIGKILLsignals to allprocesses

0- System Administrator shutsdown the machine byissuing shutdown command

2. Process termiteswhen it receives the SIGKILL signal

3. The sockets belongingto the terminating processare closed by the kernel

4. FIN segment is sent

Rest of the operations are the same with “Termination of Server Process”

Page 33: TCP Sockets

33

Data Formats

– Usually server does some processing on the data that is received from the client.

– Hence it is important how data is passed between client and server

• let client pass two integers to the server and the server will add them up and will send the result back to the client. There are two ways to achieve this:

» Converting the data into text strings and passing text strings between client and server

» Passing binary data between directly between client and server

Page 34: TCP Sockets

34

Passing Text Stringsvoidstr_echo(int sockfd){ long arg1, arg2; ssize_t n; char line[MAXLINE];

for ( ; ; ) { if ( (n = Readline(sockfd, line, MAXLINE)) == 0) return; /* connection closed by other end */

if (sscanf(line, "%ld%ld", &arg1, &arg2) == 2) snprintf(line, sizeof(line), "%ld\n", arg1 + arg2); else snprintf(line, sizeof(line), "input error\n");

n = strlen(line); Writen(sockfd, line, n); }}

Page 35: TCP Sockets

35

Passing Binary Data - clientstruct args { long arg1; long arg2;};

struct result long sum;};

voidstr_cli(FILE *fp, int sockfd){ char sendline[MAXLINE]; struct args args; struct result result;

while (Fgets(sendline, MAXLINE, fp) != NULL) {

if (sscanf(sendline, "%ld%ld", &args.arg1, &args.arg2) != 2) { printf("invalid input: %s", sendline); continue; } Writen(sockfd, &args, sizeof(args));

if (Readn(sockfd, &result, sizeof(result)) == 0) err_quit("str_cli: server terminated prematurely");

printf("%ld\n", result.sum); }}

Page 36: TCP Sockets

36

Passing Binary Data - servervoidstr_echo(int sockfd){ ssize_t n; struct args args; struct result result;

for ( ; ; ) { if ( (n = Readn(sockfd, &args, sizeof(args))) == 0) return; /* connection closed by other end */

result.sum = args.arg1 + args.arg2; Writen(sockfd, &result, sizeof(result)); }}

Page 37: TCP Sockets

37

Problems with passing binary data

• Different systems store binary numbers is different formats: big endian, little endian.

• Different systems can store the same C datatype differently: some systems use 32 bits for long but some use 64 bits.

• Different systems pack structures differently

• Therefore it is now wise to send binary data across a socket

Page 38: TCP Sockets

38

Two common solutions

• Pass all numeric data as text strings

• Explicitly define the binary formats of the supported datatypes: number of bits, little or big endian, etc and pass all data in this format.

– RPC for example uses XDR (External Data Representation)