Вы находитесь на странице: 1из 22

CEN463 NetworkProgramming

06 TCPClient/ / ServerExample S E l
Dr.Mostafa HassanDahshan
CollegeofComputerandInformationSciences

KingSaudUniversity

TCPClient/ServerExample
Useelementarysocketfunctions WritecompleteTCPclient/serverexample TCPechoserverandclient(version1) TCP echo server and client (version 1)
clientreadslinefromstdin,sendittoserver serverreadslinefromnetwork,echobacktoclient clientreadsechoedline,printsittostdout ,p

Concurrentserverusingfork
createnewchildprocessforeachconnection hild f h i
2

EchoClientandServer

stdin stdout

fgets fputs Client

writeline readline

readline Server writeline

EchoClientandServer
tcpecho1_srv.c tcpecho1_cli.c

Server:main Function
TCPsocketcreated Addressstructurefilled
wildcardaddressINADDR_ANY wildcard address INADDR ANY wellknownportSRV_PORT

Portnumberchoice
>1023:avoidconflictwithreservedports p >5000:avoidconflictwithBSDephemeralports <49152:avoidconflictwithcorrectephemeralports < 49152: avoid conflict with correct ephemeral ports
5

ConcurrentServer
Foreachclient,fork spawnchildtohandleit Childcloseslisteningsocket(copy) Parentclosesconnectedsocket(copy) Parent closes connected socket (copy) Childcallsstr_echo tohandleclient Notes
parentdoesn tcallwait parent doesnt call wait finishedchildbecomeszombie process
6

Server:str_echo Function
Createbuffertoreaddatafromsocket whilelooponread (sameasrecv)function
blockuntildataisreceivedor? block until data is received or? returnwhenconnectionisclosedbyclient

write (send)databacktosocket

Client:main Function
GetserverIPaddressfromuser
argc:parametercount(<2:noparameters) argv[0]: alwaysnameoftheprogram argv[1]: firstpassedparameter(serverIP)

Useinet_pton toconvertIPaddress Use inet pton to convert IP address


checkifuserenteredinvalidaddress

Client:main Function
CreateTCPsocket Filladdressstructure
serverIPaddressenteredbyuser server IP address entered by user serverportSRV_PORT hardcoded

Connecttoserver
checkthatconnectionsuccessful

Callstr_cli functiontohandleuserinput
9

Client:str_cli Function
Twobufferstoholduserinputandserverecho Readfromstdin (default:keyboard) fgets keeps reading until keepsreadinguntil
MAX_SEND_BUF isreached(256characters) EOF(NULL)characterisentered EOLcharacterisentered(userpressEnter) ( p )

10

Client:str_cli Function
write buffertosocket strlen getlengthofinputstring(nullterminated)

read back from socket backfromsocket


blockuntilserversendsoneresponse
thereisacatch..responsemightrequiremultiplereads h i h i h i li l d unlikelyforsmallsizepacketasinthiscase

fputs receiveddatatostdout (screen)


11

NormalStartup(Server)
Startserverinthebackground ./tcpecho1_srv & [ ] [1] 7673 :processID(pid) p (p ) Servercalls:socket,bind,listen,accept Checkstateoftheserver h k f h ./netstat -atn
Active Internet connections (servers and established) Proto Recv-Q Send-Q Local Address Foreign Address tcp 0 0 0.0.0.0:5555 0.0.0.0:* State LISTEN

12

NormalStartup(Client)
Startclient ./tcpecho1_cli 127.0.0.1 Clientcallsocket,connect Client call socket connect After3wayhandshake
connectreturnsinclient acceptreturnsinserver p

13

NormalStartup
netstat -atn
servers connected socket servers listening li t i socket k t State LISTEN ESTABLISHED ESTABLISHED Active I t A ti Internet connections ( t ti (servers and established) d t bli h d) Proto Recv-Q Send-Q Local Address Foreign Address tcp 0 0 0.0.0.0:5555 0.0.0.0:* tcp 0 0 127.0.0.1:5555 127.0.0.1:59759 tcp t 0 0 127 0 0 1 59759 127.0.0.1:59759 127.0.0.1:5555 127 0 0 1 5555

ps fo pid,ppid,stat,args
PID 7618 7673 7680 680 7679
pid of parent process

PPID 7615 7618 7673 6 3 7618

STAT COMMAND clients connected Ss bash socket S \_ tcpecho1_srv S | \_ \ tcpecho1_srv 1 S+ \_ tcpecho1_cli 127.0.0.1

parent pid for child process


14

NormalTermination(Client)
UsertypeEOF,fgets returnsNULL functionstr_cli returns,mainprogramexits Processtermination Process termination
kernelcloseallopendescriptors(clientsocket) clientsendFINtoserver,state[FIN_WAIT_1] serverrespondwithACK,state[CLOSE_WAIT] p , [ ] clientreceiveACK,state[FIN_WAIT_2]
15

NormalTermination(Client)
./tcpecho1_cli 127.0.0.1
hello, world hello, world good bye good bye ^D

netstat -atn
Proto Recv-Q Send-Q Local Address tcp 0 0 0.0.0.0:5555 tcp 0 0 127.0.0.1:59759 Foreign Address g 0.0.0.0:* 127.0.0.1:5555 State LISTEN TIME_WAIT

16

NormalTermination(Server)
ServerchildreceiveFINwhileblockedinread
read returns 0 when FIN received returns0whenFINreceived str_echo returns

Serverchildterminatesbycallingexit Allopendescriptorsclosed(connectedsocket) All open descriptors closed (connected socket)


serversendsFINtoclient,state[LAST_ACK] clientsendsACK,state[TIME_WAIT] li d ACK [TIME WAIT]

ChildsendsSIGCHLD toparent
wedidntcatch,defaultactionisignore
17

NormalTermination(Server)
ps fo pid,ppid,stat,args
PID 7618 7673 7680 PPID 7615 7618 7673 STAT COMMAND Ss+ bash S \_ tcpecho1_srv Z \_ [tcpecho1_srv] <defunct>
zombie process

Zombieprocess

childprocessterminated parenthasn treaditsexitstatus( parent hasnt read its exit status (wait or waitpid) or canfillupprocesstable wemusthandleSIGCHLD signaltocleanup
18

signal Function
#include <signal.h> void (*signal(int sig, void (*func)(int)))(int); ( signal(int ( func)(int)))(int);

Choosehowtohandlesignalsig Choose how to handle signal sig


SIG_DFL:defaulthandlerforsig SIG_IGN:ignoresig (notallsignalscanbeignored) SIG IGN ignore i (not all signals can be ignored) functionfunc:installfunc ashandlerforsig

19

wait,waitpid Functions
#include <sys/wait.h> #i l d < / it h> pid_t wait(int *stat_loc); pid_t waitpid(pid_t pid, int *stat_loc, int options); p f Both return: process ID if OK, 0 or1 on error

Obtainstatusinformationofchildprocess Ifnoterminatedchild,wait bl k If t i t d hild it blocks waitpid givesmorecontrol p


whichchildprocesstowaitfor(pid parameter) whethertoblockornot(WNOHANG whether to block or not (WNOHANG option)
20

HandlingSIGCHLD Signal
Usesignal functiontoinstallsignalhandler Signalhandlermustcallwait orwaitpid Ifmultipleconnectionsclosesimultaneously If multiple connections close simultaneously
signalsarenotqueued signalhandlercalledonlyonce wait maynotbesufficienttopreventzombies

Usingwaitpid inaloopisbetter
21

HandlingSIGCHLD Signal
/* define signal hanlder */ void sig_chld(int signo) { pid_t pid; wait for any child (as in wait) int stat; while ( (pid = waitpid(-1, &stat, WNOHANG)) > 0) printf("child %d terminated\n", pid); /* for debugging only i/o not recommended here */ only, return; } /* install signal handler */ signal (SIGCHLD, sig_chld);

tcpecho2_srv.c

22

TerminationofServerProcess
Startserver,clientnormally,type1line,OK FindprocessIDofserver(usingps),kill it
opendescriptorswillbeclosed,FINsenttoclient open descriptors will be closed FIN sent to client clientTCPrespondswithACK(halfclose) SIGCHILDsenttoparentofkilledprocess(handled)

Clientprocessblockedonfgets p g
doesntknowserverprocessterminated FINonlytellsthatserverwon tsendmoredata FIN only tells that server wont send more data
23

TerminationofServerProcess
netstat -atn
Proto Recv-Q S d Q t Q Send-Q tcp 0 0 tcp 1 0 tcp p 0 0 Local Address l dd 0.0.0.0:5555 127.0.0.1:59759 127.0.0.1:5555 Foreign Address i dd 0.0.0.0:* 127.0.0.1:5555 127.0.0.1:59759 St t State LISTEN CLOSE_WAIT FIN_WAIT2

Onclient,typeanotherline:
another line Server terminated prematurely

clientwrite tosocket(doesn tknowitisclosed) client write to socket (doesnt know it is closed) serverrespondswithRST
24

TerminationofServerProcess
Clientcallsread immediately,doesntseeRST read returns0becausesocketisclosed Clientterminateswithmessageshown Client terminates with message shown
alldescriptorsareclosed(automatically)

WhatifRSTarrivesbeforeclientcallsread? read will return ECONNRESET (in errno) willreturnECONNRESET (in


homework:modifycodetosimulatethisbehavior
25

Notes
TodetectRSTimmediately
block useselect orpoll use select or poll

Coveredinnextchapter

26

HandlingSIGPIPE Signal
Whatifclientignoreserrorandwrite again?
SIGPIPE issenttoclientcausingtermination cancatchSIGPIPE topreventthis can catch SIGPIPE to prevent this seesection5.13inthebook homework:modifycodetosimulatethisbehavior h k dif d t i l t thi b h i

27

Debuggingwithtcpdump
sudo tcpdump -ftn -i lo
IP127.0.0.1.5555>127.0.0.1.54488:S607558336:607558336(0)ack 618225084win32768<mss 16396,sackOK,timestamp1631716616317166,nop,wscale5> 16396 kOK ti t 16317166 16317166 l 5 IP127.0.0.1.54488>127.0.0.1.5555:.ack 1win1025<nop,nop,timestamp 1631716616317166> IP127.0.0.1.54488>127.0.0.1.5555:P1:7(6)ack 1win1025<nop,nop,timestamp 1631821816317166> IP127.0.0.1.5555 127.0.0.1.54488: . ack 7win1024 nop,nop,timestamp 1631821816318218 IP 127.0.0.1.5555 >127.0.0.1.54488:.ack 7 win 1024 <nop,nop,timestamp 16318218 16318218> IP127.0.0.1.5555>127.0.0.1.54488:P1:7(6)ack 7win1024<nop,nop,timestamp 1631821816318218> IP127.0.0.1.54488>127.0.0.1.5555:.ack 7win1025<nop,nop,timestamp 1631821816318218> IP127.0.0.1.54488>127.0.0.1.5555:P7:15(8)ack 7win1025<nop,nop,timestamp 1631896016318218> IP127.0.0.1.5555>127.0.0.1.54488:P7:15(8)ack 15win1024<nop,nop,timestamp 1631896016318960> IP127.0.0.1.54488>127.0.0.1.5555:.ack 15win1025<nop,nop,timestamp 1631896016318960> IP127.0.0.1.54488>127.0.0.1.5555:F15:15(0)ack 15win1025<nop,nop,timestamp 1631934016318960> IP127.0.0.1.5555>127.0.0.1.54488:F15:15(0)ack 16win1024<nop,nop,timestamp 1631934016319340> IP 127 0 0 1 5555 > 127 0 0 1 54488 F 15 15(0) ack 16 win 1024 <nop nop timestamp 16319340 16319340> IP127.0.0.1.54488>127.0.0.1.5555:.ack 16win1025<nop,nop,timestamp 1631934016319340>
28

DebuggingwithWireshark
TCPechoclientandserver normalactivity sudo wireshark &
No. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 Time 0 0 0 3.769 3.77 3.77 3.77 3 77 9.009 9.01 9.01 10.891 10.891 10 891 10.891 11.951 11.951 11.951 Source 127.0.0.1 127.0.0.1 127.0.0.1 127.0.0.1 127.0.0.1 127.0.0.1 127.0.0.1 127 0 0 1 127.0.0.1 127.0.0.1 127.0.0.1 127.0.0.1 127.0.0.1 127 0 0 1 127.0.0.1 127.0.0.1 127.0.0.1 127.0.0.1 Destination 127.0.0.1 127.0.0.1 127.0.0.1 127.0.0.1 127.0.0.1 127.0.0.1 127.0.0.1 127 0 0 1 127.0.0.1 127.0.0.1 127.0.0.1 127.0.0.1 127.0.0.1 127 0 0 1 127.0.0.1 127.0.0.1 127.0.0.1 127.0.0.1 Protocol TCP TCP TCP TCP TCP TCP TCP TCP TCP TCP TCP TCP TCP TCP TCP TCP Info 54487>5555[SYN]Seq=0Win=32792Len=0MSS=16396TSV=16285190TSER=0WS=5 5555>54487[SYN,ACK]Seq=0Ack=1Win=32768Len=0MSS=16396TSV=16285190TSER=16285190WS=5 54487>5555[ACK]Seq=1Ack=1Win=32800Len=0TSV=16285190TSER=16285190 54487>5555[PSH,ACK]Seq=1Ack=1Win=32800[TCPCHECKSUMINCORRECT]Len=6TSV=16286136TSER=1 5555>54487[ACK]Seq=1Ack=7Win=32768Len=0TSV=16286136TSER=16286136 5555>54487[PSH,ACK]Seq=1Ack=7Win=32768[TCPCHECKSUMINCORRECT]Len=6TSV=16286136TSER=1 54487>5555[ACK]Seq=7Ack=7Win=32800Len=0TSV=16286136TSER=16286136 54487 > 5555 [ACK] Seq 7 Ack 7 Win 32800 Len 0 TSV 16286136 TSER 16286136 54487>5555[PSH,ACK]Seq=7Ack=7Win=32800[TCPCHECKSUMINCORRECT]Len=3TSV=16287446TSER=1 5555>54487[PSH,ACK]Seq=7Ack=10Win=32768[TCPCHECKSUMINCORRECT]Len=3TSV=16287446TSER= 54487>5555[ACK]Seq=10Ack=10Win=32800Len=0TSV=16287446TSER=16287446 54487>5555[PSH,ACK]Seq=10Ack=10Win=32800[TCPCHECKSUMINCORRECT]Len=4TSV=16287916TSER 5555>54487[PSH,ACK]Seq 10Ack 14Win 32768[TCPCHECKSUMINCORRECT]Len 4TSV 16287916TSER 5555 > 54487 [PSH ACK] Seq=10 Ack=14 Win=32768 [TCP CHECKSUM INCORRECT] Len=4 TSV=16287916 TSER 54487>5555[ACK]Seq=14Ack=14Win=32800Len=0TSV=16287916TSER=16287916 54487>5555[FIN,ACK]Seq=14Ack=14Win=32800Len=0TSV=16288181TSER=16287916 5555>54487[FIN,ACK]Seq=14Ack=15Win=32768Len=0TSV=16288181TSER=16288181 54487>5555[ACK]Seq=15Ack=15Win=32800Len=0TSV=16288181TSER=16288181

29

DebuggingwithWireshark
TerminationofServerProcess
Time 0 0 0 1.565 1.565 1.565 1 565 1.565 171.23 171.27 322.92 322.92 Info 50332>5555[SYN]Seq=0Win=32792Len=0MSS=16396TSV=15949437TSER=0WS=5 5555>50332[SYN,ACK]Seq=0Ack=1Win=32768Len=0MSS=16396TSV=15949437TSER=15949437 50332>5555[ACK]Seq=1Ack=1Win=32800Len=0TSV=15949437TSER=15949437 50332>5555[PSH,ACK]Seq=1Ack=1Win=32800[TCPCHECKSUMINCORRECT]Len=3TSV=1594982 5555>50332[ACK]Seq=1Ack=4Win=32768Len=0TSV=15949828TSER=15949828 5555>50332[PSH,ACK]Seq=1Ack=4Win=32768[TCPCHECKSUMINCORRECT]Len=3TSV=1594982 5555 > 50332 [PSH ACK] Seq 1 Ack 4 Win 32768 [TCP CHECKSUM INCORRECT] Len 3 TSV 1594982 50332>5555[ACK]Seq=4Ack=4Win=32800Len=0TSV=15949829TSER=15949828 5555>50332[FIN,ACK]Seq=4Ack=4Win=32768Len=0TSV=15992244TSER=15949829 50332>5555[ACK]Seq=4Ack=5Win=32800Len=0TSV=15992254TSER=15992244 50332>5555[PSH,ACK]Seq=4Ack=5Win=32800[TCPCHECKSUMINCORRECT]Len=2TSV=1603016 5555>50332[RST]Seq=5Win=0Len=0

30

DataFormats
Section5.18inthetextbook

31

AdditionalReferences
Unix/LinuxCodingSecrets Signals
http://crusher4.blogspot.com/2007/03/signals egsigtermsigpipesighup.html

tcpdump
www.oreillynet.com/linux/cmd/cmd.csp?path=t/t ill t /li / d/ d ? th t/t cpdump www.tcpdump.org/tcpdump_man.html /

32

File: /home/mostafa/netprog/tcpsockex/tcpecho1_srv.c

Page 1 of 2

/* TCP echo server uses fork but doesn't handle SIGCHLD child processes become zombies after finished */ #include #include #include #include #include #include <stdio.h> /* printf, fgets, fputs and standard i/o*/ <sys/socket.h> /* socket, bind, listen, accept, socklen_t */ <arpa/inet.h> /* sockaddr_in, inet_ntop */ <string.h> /* memset, strlen */ <stdlib.h> /* exit */ <unistd.h> /* close, read, write */

#define SRV_PORT 5105 /* default port number */ #define LISTEN_ENQ 5 /* for listen backlog */ #define MAX_RECV_BUF 256 void str_echo(int); /* prototype for function str_echo */ int main(int argc, char* argv[]) { int listen_fd, /* listening socket file descriptor*/ conn_fd; /* connected socket file descriptor*/ struct sockaddr_in srv_addr, /* server address structure */ cli_addr; /* client address structure */ socklen_t cli_len; /* to hold the length of cli_addr */ pid_t child_pid; /* pid of child process */ /* Start */ if ( (listen_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0 ) { perror("listen error"); return -1; } memset(&srv_addr, 0, sizeof(srv_addr)); /* zero-fill srv_addr structure*/ memset(&cli_addr, 0, sizeof(cli_addr)); /* zero-fill cli_addr structure*/ srv_addr.sin_family = AF_INET; srv_addr.sin_addr.s_addr = htonl(INADDR_ANY);/*listen on all interfaces*/ srv_addr.sin_port = htons(SRV_PORT); if ( bind(listen_fd, (struct sockaddr*) &srv_addr, sizeof(srv_addr))< 0 ){ perror("bind error"); return -1; } if ( listen(listen_fd, LISTEN_ENQ) < 0 ) { perror("listen error"); return -1; } for(;;) /* run forever */ { cli_len = sizeof(cli_addr); if ( (conn_fd = accept(listen_fd, (struct sockaddr*) &cli_addr, &cli_len) ) < 0 ) { perror("accept error"); continue; /* start over the for loop */ }

File: /home/mostafa/netprog/tcpsockex/tcpecho1_srv.c

Page 2 of 2

/* fork a new child process */ if ( (child_pid = fork()) == 0 ) /* fork returns 0 for child */ { close (listen_fd); /* close child's copy of listen_fd */ str_echo(conn_fd); /* process request (echo string) */ exit(0); /* exit child process */ } close(conn_fd); /* close parent's copy of conn_fd */ } exit(0); } void str_echo(int sock_fd) { ssize_t rcvd_bytes; char recv_str[MAX_RECV_BUF]; while ( (rcvd_bytes = read(sock_fd, recv_str, MAX_RECV_BUF)) > 0 ) write(sock_fd, recv_str, rcvd_bytes); if (rcvd_bytes < 0) perror("read error"); }

File: /home/mostafa/netprog/tcpsockex/tcpecho1_cli.c

Page 1 of 2

/* TCP echo client */ #include <stdio.h> /* printf, fgets, fputs and standard i/o*/ #include <sys/socket.h> /* socket, bind, listen, accept, socklen_t */ #include <arpa/inet.h> /* sockaddr_in, inet_ntop */ #include <string.h> /* memset, strlen */ #include <stdlib.h> /* exit */ #include <unistd.h> /* close, read */ #define #define #define #define SRV_PORT 5105 /* default port number */ LISTEN_ENQ 5 /* for listen backlog */ MAX_SEND_BUF 256 MAX_RECV_BUF MAX_SEND_BUF

int str_cli(FILE*, int); /* prototype for function str_cli */ int main(int argc, char* argv[]) { int sock_fd; /* client socket */ struct sockaddr_in srv_addr; /* server address structure */ if (argc < 2) { /* user entered no arguments */ printf("usage: %s <IP address>\n", argv[0]); /* arg[0] is prog name*/ return -1; } /* create a client socket */ sock_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); srv_addr.sin_port = htons(SRV_PORT); srv_addr.sin_family = AF_INET; /* convert command line argument to numeric IP */ if ( inet_pton(AF_INET, argv[1], &(srv_addr.sin_addr)) < 1 ) { printf("Invalid IP address\n"); return -1; } if( connect(sock_fd, (struct sockaddr*) &srv_addr, sizeof(srv_addr)) < 0 ){ perror("connect error"); return -1; } /* run the client using standard input */ if (str_cli(stdin, sock_fd) < 0 ) exit(-1); else exit(0); } int str_cli(FILE* fp, int sock_fd) { char recv_str[MAX_RECV_BUF]; /* buffer to hold received data */ char send_str[MAX_SEND_BUF]; /* buffer to hold data to be sent */ /* get input from file fp into send_str buffer */ while( fgets(send_str,MAX_SEND_BUF, fp) != NULL ) { /* fgets returns NULL when EOF, EOL or MAX_SEND_BUF reached */

File: /home/mostafa/netprog/tcpsockex/tcpecho1_cli.c

Page 2 of 2

ssize_t sent_bytes, rcvd_bytes; /* write send_str contents to socket */ if ( (sent_bytes = write(sock_fd, send_str, strlen(send_str))) < 0 ) { perror("write error"); return -1; } memset(recv_str, 0, MAX_RECV_BUF); // clear recv_str /* read back from socket into recv_str */ if ( (rcvd_bytes = read(sock_fd, recv_str, MAX_RECV_BUF)) < 0 ) { perror("read error"); return -1; } if (rcvd_bytes == 0) /* indicates server has been shutdown */ { printf("Server terminated prematurely\n"); return -1; } /* write received line to standard output */ fputs(recv_str, stdout); } return 0; }

File: /home/mostafa/netprog/tcpsockex/tcpecho2_srv.c

Page 1 of 2

/* TCP echo server uses fork handles SIGCHLD to prevent zombies */ #include #include #include #include #include #include #include #include <stdio.h> /* printf, fgets, fputs and standard i/o*/ <sys/socket.h> /* socket, bind, listen, accept, socklen_t */ <arpa/inet.h> /* sockaddr_in, inet_ntop */ <string.h> /* memset, strlen */ <stdlib.h> /* exit */ <unistd.h> /* close, read, write */ <signal.h> /* signal */ <sys/wait.h> /* waitpid */

#define SRV_PORT 5105 /* default port number */ #define LISTEN_ENQ 5 /* for listen backlog */ #define MAX_RECV_BUF 256 void str_echo(int); /* prototype for function str_echo */ void sig_chld(int); /* prototype for function sig_chld */ int main(int argc, char* argv[]) { int listen_fd, /* listening socket file descriptor*/ conn_fd; /* connected socket file descriptor*/ struct sockaddr_in srv_addr, /* server address structure */ cli_addr; /* client address structure */ socklen_t cli_len; /* to hold the length of cli_addr */ pid_t child_pid; /* pid of child process */ /* Start */ if ( (listen_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0 ) { perror("listen error"); return -1; } memset(&srv_addr, 0, sizeof(srv_addr)); /* zero-fill srv_addr structure*/ memset(&cli_addr, 0, sizeof(cli_addr)); /* zero-fill cli_addr structure*/ srv_addr.sin_family = AF_INET; srv_addr.sin_addr.s_addr = htonl(INADDR_ANY);/*listen on all interfaces*/ srv_addr.sin_port = htons(SRV_PORT); if ( bind(listen_fd, (struct sockaddr*) &srv_addr, sizeof(srv_addr))< 0 ){ perror("bind error"); return -1; } if ( listen(listen_fd, LISTEN_ENQ) < 0 ) { perror("listen error"); return -1; } /* install signal handler */ signal (SIGCHLD, sig_chld); for(;;) /* run forever */

File: /home/mostafa/netprog/tcpsockex/tcpecho2_srv.c

Page 2 of 2

{ cli_len = sizeof(cli_addr); if ( (conn_fd = accept(listen_fd, (struct sockaddr*) &cli_addr, &cli_len) ) < 0 ) { perror("accept error"); continue; /* start over the for loop */ } /* fork a new child process */ if ( (child_pid = fork()) == 0 ) /* fork returns 0 for child */ { close (listen_fd); /* close child's copy of listen_fd */ str_echo(conn_fd); /* process request (echo string) */ exit(0); /* exit child process */ } close(conn_fd); /* close parent's copy of conn_fd */ } exit(0); } void str_echo(int sock_fd) { ssize_t rcvd_bytes; char recv_str[MAX_RECV_BUF]; while ( (rcvd_bytes = read(sock_fd, recv_str, MAX_RECV_BUF)) > 0 ) write(sock_fd, recv_str, rcvd_bytes); if (rcvd_bytes < 0) perror("read error"); } /* define signal hanlder */ void sig_chld(int signo) { pid_t pid; int stat; while ( (pid = waitpid(-1, &stat, WNOHANG)) > 0) printf("child %d terminated\n", pid); /* for debugging only, i/o not recommended here */ return; }

Вам также может понравиться