分析TCP回射服务+客户程序:
启动服务器程序后,netstat -a,后终端出现:
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 *:9877 *:* LISTEN
其中本地端口为9877正是我们启动的服务器应用
启动我们的客户/服务器程序对,
通过三次握手,连接建立。接着发生的步骤:
1.客户端调用str_cli 函数,该函数将阻塞于fgets调用。因为我们还没键入一行文本
2.当服务器中的accept返回时,服务器调用fork,再由子进程调用str_echo。str_echo调用readline,readline调用read,
read在等待客户送入一行文本期间阻塞
3.另一方面,服务器父进程再次调用accept并阻塞,等待下一个客户连接
终端netstat -a后,终端显示:
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 *:9877 *:* LISTEN
tcp 0 0 localhost.localdoma:ipp *:* LISTEN
tcp 0 0 *:daytime *:* LISTEN
tcp 0 0 localhost.localdo:55817 localhost.localdom:9877 ESTABLISHED
tcp 0 0 localhost.localdom:9877 localhost.localdo:55817 ESTABLISHED
tcp6 0 0 ubuntu:ipp [::]:* LISTEN
udp 0 0 *:52444 *:*
第二个ESTABLISHED的本地端口号为9877,可判断出其对应服务器子进程的套接口;第一个ESTABLISHED的本地端口号是55817,
可判断出其对应客户进程的套接口。
zhouzhou@ubuntu:~/Desktop$ ps -a -o pid,ppid,stat,args,wchan
PID PPID STAT COMMAND WCHAN
8780 8779 S+ sh -c LD_LIBRARY_PATH=$LD_L wait
8781 8780 S+ /home/fupeng/Desktop/codebl inet_csk_wait_for_connect
8993 8992 S+ sh -c LD_LIBRARY_PATH=$LD_L wait
8994 8993 S+ /home/fupeng/Desktop/codebl n_tty_read
8995 8781 S+ /home/fupeng/Desktop/codebl sk_wait_data
9194 4449 R+ ps -a -o pid,ppid,stat,args -
简略:
PID PPID STAT COMMAND WCHAN
8781 8780 S+ /home/fupeng/Desktop/codebl inet_csk_wait_for_connect 判断为父进程
8994 8993 S+ /home/fupeng/Desktop/codebl n_tty_read 判断为客户程序
8995 8781 S+ /home/fupeng/Desktop/codebl sk_wait_data 判断为子进程
服务器和客户程序都启动时:
zhouzhou@ubuntu:~/Desktop$ netstat -a | grep 9877
tcp 0 0 *:9877 *:* LISTEN
tcp 0 0 localhost.localdom:9877 localhost.localdo:54491 ESTABLISHED
tcp 0 0 localhost.localdo:54491 localhost.localdom:9877 ESTABLISHED
客户端(ctrl+d结束后,),会经历如下:客户端会经历一个TIME_WAIT 状态。
zhouzhou@ubuntu:~/Desktop$ netstat -a | grep 9877
tcp 0 0 *:9877 *:* LISTEN
tcp 0 0 localhost.localdo:54491 localhost.localdom:9877 TIME_WAIT
zhouzhou@ubuntu:~/Desktop$ netstat -a | grep 9877
tcp 0 0 *:9877 *:* LISTEN
当前连接的客户端(本地端口号)进入了TIME_WAIT状态,而监听服务器仍在等待另一个客户连接。
正常终止客户和服务器的步骤:
1.当我们键入<Ctr-D>EOF字符时,fgets返回一个空指针,str_cli函数返回。
2.当str_cli返回到客户的main函数时,main通过exit终止。
3.进程终止时的一部分操作是关闭所有打开的描述字,客户打开的描述字由内核关闭。这导致客户tcp发送一个FIN给服务器,服务器TCP则以ACK响应,这是TCP连接终止的前半部操作。至此,服务器接口处于CLOSE_WAIT状态,客户套接口处于FIN_WAIT_2状态。
4.当服务器TCP接受FIN时,服务器子进程阻塞于readline调用,于是readline返回0.这导致str_echo函数返回服务器子进程的main函数
5.服务器子进程通过调用exit来终止。
6.服务器子进程打开的所有描述字随之关闭。由子进程关闭已连接套接口引发TCP连接终止序列最后两个分节:一个是从服务器到客户的FIN;另一个是从客户到服务器的ACK。至此,连接完全终止,客户套接口进入TIME_WAIT状态
7.进程终止处理的另一部分内容是:在服务器子进程终止时,会给父进程发送一个SIGCHLD信号。该信号的缺省行为被忽略。
这时,我们查看进程,子进程进入僵尸状态。
zhouzhou@ubuntu:~/Desktop$ ps -a -o pid,ppid,stat,args,wchan
PID PPID STAT COMMAND WCHAN
8780 8779 S+ sh -c LD_LIBRARY_PATH=$LD_L wait
8781 8780 S+ /home/fupeng/Desktop/codebl inet_csk_wait_for_connect
8995 8781 Z+ [unp2] <defunct> exit
9355 8781 Z+ [unp2] <defunct> exit
9581 4449 R+ ps -a -o pid,ppid,stat,args -
后续,我们将学习去清理僵死进程。