UNP - 第五章 TCP客户/服务器示例 - 学习笔记
2017-08-31 15:25
441 查看
1 - 前言
本章在第四章的理论知识基础上,实现一个TCP/IP客户服务器的原型程序。这个原型程序是执行以下步骤的一个回射服务器。(1)客户从标准输入读入一行文本,并写给服务器
(2)服务器从网络输入读取这行文本,并回射给客户
(3)客户从网络输入读入这行回射文本,并显示在标注输入上
该程序的模型图:
该程序时后续我们研究套接字通信的基础模型,其他的比如I/O复用,多进程服务器,多线程服务器等均基于该程序作了相应的改动。所以十分重要。
除了这个基础的程序之外,还会分析多种特殊边界情况。例如:
1,客户和服务器启动时发生什么?
2,客户正常终止时发生什么?
3,若服务器进程在客户之前终止,则客户发生什么?
4,若服务器主机崩溃,则客户发生什么?
通过这些情况的分析,弄清楚网络层次发生了什么,以及对应套接字的API是如何处理的?
2 - tcp回射服务器程序
#include "unp.h" #include "apue.h" void str_echo(int sockfd){ ssize_t n; char buf[MAXLINE]; again: while((n == read(sockfd,buf,MAXLINE)) > 0){ write(sockfd,buf,n); } if(n < 0 && errno == EINTR){ goto again; } else if(n < 0) err_sys("str_echo : read error"); } int main(int argc,char **argv){ int listenfd,connfd; pid_t childpid; socklen_t clilen; struct sockaddr_in cliaddr,servaddr; if((listenfd = socket(AF_INET,SOCK_STREAM,0) )< 0){ err_quit("socket create error"); } bzero(&servaddr,sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY); servaddr.sin_port = htons(SERV_PORT); if(bind(listenfd,(SA *)&servaddr,sizeof(servaddr)) < 0){ err_quit("bind error"); } if(listen(listenfd,LISTENQ) < 0){ err_quit("listen error"); } for(;;){ clilen = sizeof(cliaddr); if((connfd = accept(listenfd,(SA* )&cliaddr,&clilen)) < 0){ err_sys("accept error"); }else{ if((childpid = fork()) == 0){ //child process close(listenfd); //close listening socket str_echo(connfd); //process the request exit(0); } close(connfd); //parent close conneted socket } } }
分析:
服务器进程,首先创建套接字,然后绑定端口号和地址,然后调用listen系统调用,进入监听状态。然后调用accept系统调用,等待已完成的tcp连接。
在str_echo回射处理函数中,调用read系统调用从网络输入中读取数据。然后在调用write函数,将其发送给客户端。
3 - TCP回射客户程序
4 - 几种边界情况分析
4 - 1 客户和服务器启动时发生什么? ?
对于服务器来说,启动服务器后,它调用socket,bind,listen和accept,并阻塞于accept调用。在启动客户端之前,服务器套接字处于LISTEN状态。当客户端调用socket和connect,后者引起tcp的三次握手过程。当三次握手过程完成后,客户中的connect和服务器的accept均返回、连接建立。此时双方的套接字均为established状态。
接这发生如下步骤:
1,客户调用str_cli函数,该函数阻塞于fgets调用。直到输入内容
2,当服务器中的accept返回时,服务器调用fork,在由子进程调用str_echo,该函数调用readline,readline调用read。而read在等待客户送入一行文本期间阻塞。
3,服务器父进程再次调用accept并阻塞。等待下一个客户连接。
4 - 2 客户正常终止时发生什么?
正常情况的步骤如下:1,当我们键入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,服务器子进程中国开发的所有描述符随之关闭。由子进程来关闭已经连接套接字会引起终止序列的最后两个分节:一个从服务器的FIN和一个从客户到服务器的ACK。至此,连接完全终止,客户套接字进入TIME_WAIT状态。
7,进程终止的另一部分内容是:在服务器进程终止时,给父进程一个SIGCHLD信号。在本例中,该信号产生了,但是我们在代码并没有捕捉该信号。而该信号的默认行为时被忽略。既然父进程未处理。则子进程处于僵尸状态。
4 - 3 若服务器进程在客户之前终止,则客户发生什么?
4 - 4 若服务器主机崩溃,则客户发生什么?
相关文章推荐
- UNIX网络编程卷一 笔记 第五章 TCP客户/服务器程序示例
- UNP-UNIX网络编程 第五章:TCP客户/服务器程序示例
- UNIX网络编程笔记 第五章 TCP客户/服务器程序示例
- UNIX网络编程卷一 第五章 TCP客户/服务器程序示例
- UNP——Chapter 5:TCP客户/服务器程序示例
- Unix网络编程学习笔记之第5章 TCP客户端/服务器程序示例
- UNIX网络编程笔记(4)—TCP客户/服务器程序示例
- UNP函数笔记三: TCP客户/服务器程序示例
- 《UNIX网络编程 卷1》 笔记: TCP 客户/服务器程序示例
- UNP卷一学习笔记:TCP状态
- UNP卷1:第五章(TCP客户/服务器程序示例)
- UNPV3第五章TCP客户/服务器程序示例
- TCP-IP协议学习笔记
- Learning Spark 学习笔记 第五章 加载或保存数据
- 数据结构与算法分析学习笔记--第五章--排序
- OpenGL学习笔记-2015.3.24——transform feedback缓存&粒子系统示例分析
- 学习笔记-jQuery扩展示例
- TCP-IP学习笔记七:Netty使用--简单通信编程3
- Ferris教程学习笔记:js示例5.7 自定义右键菜单,请在页面点击右键查看效果。
- Android 官方示例:android-architecture 学习笔记(四)之todo-databinding