第3讲TCP客户端服务器程序示例FTP服务器和客户机.doc
《第3讲TCP客户端服务器程序示例FTP服务器和客户机.doc》由会员分享,可在线阅读,更多相关《第3讲TCP客户端服务器程序示例FTP服务器和客户机.doc(8页珍藏版)》请在冰豆网上搜索。
![第3讲TCP客户端服务器程序示例FTP服务器和客户机.doc](https://file1.bdocx.com/fileroot1/2022-10/9/27c72298-3ef5-4df4-aceb-77220f61350c/27c72298-3ef5-4df4-aceb-77220f61350c1.gif)
Ch3TCP客户端-服务器程序示例(FTP服务器和客户机)
1概述
1.1相对完整的客户端-服务器程序,展示编写网络程序的基本过程
1.2分析客户端-服务器程序的各种运行状况
2客户端-服务器通信协议
2.1通信协议-客户端和应用程序对交互信息的格式约定
2.2示例中使用的通信协议
客户端和服务器数据包示例:
3公用函数分析
3.1地址转换函数addr_conv
3.2读取命令头函数read_line
3.3读取指定字节函数read_all
3.4发送指定字节函数write_all
4服务器程序分析
4.1程序流程(见右图)
4.2主要模块分析
l初始化模块
getservbyname
l读取客户端请求模块
read_line函数
read_all函数
l处理客户端请求
l返回服务器响应
write_all函数
5客户端程序分析
5.1程序流程(见右图)
5.2主要模块分析
l初始化模块
命令行参数(服务器IP,端口)
l读取用户输入
ftp命令及命令参数获取(gets函数)
l发送请求给服务器
分别发送命令长度和命令及参数
write_all函数
l读取服务器响应
read_line函数、read_all函数
6程序运行状况分析(使用netstat命令查看socket状态,采用一些程序调试手段)
6.1正常运行状况
l在一个终端启动服务器程序(命令行:
./ftpserver)
显示提示信息,服务器在函数调用accept处阻塞,服务器socket状态为LISTEN
l在另一终端启动客户端程序(命令行:
./ftpclient127.0.0.121)
显示提示信息,服务器socket状态为LISTEN,新生成的连接socket状态为ESTABLISHED,客户端socket状态为ESTABLISHED
l客户端和服务器进行一次通信,过程如下
(1)客户端调用函数gets从控制台读取用户输入
(2)客户端调用write_all函数发送命令长度
(3)客户端调用write_all函数发送命令内容
(4)服务器调用read_line函数读取命令长度
(5)服务器调用read_all函数读取命令内容
(6)服务器处理客户端请求得到响应结果
(7)服务器调用write_all函数发送响应长度
(8)服务器调用write_all函数发送响应内容
(9)客户端调用read_line函数读取响应长度
(10)客户端调用read_all函数读取响应内容
通信过程中的这10个步骤是并行的,没有严格的顺序
l结束通信过程(客户端主动关闭)
(1)客户端通过控制台键入CTRL+D,使gets函数返回NULL,结束cli_requ函数调用,客户端主函数调用close关闭客户端socket,进入FIN_WAIT1状态
(2)服务器的socket在接收完数据后返回对客户端的FIN字段的确认,进入CLOSE_WAIT状态,客户端进入FIN_WAIT2状态,为了查看这两个状态需要使服务器在调用close函数前暂停(加入getchar函数)
(3)服务器收到客户端的FIN字段时正阻塞在read_line函数的调用过程中,read_line函数将返回0,使得read_requ函数结束,serv_resp函数结束
(4)函数serv_resp结束后,服务器主程序调用函数close关闭socket,服务器发送FIN字段进入LAST_ACK状态,(当网络速度较慢时可以查看到这个状态)客户端TCP协议收到服务器FIN字段之后进入TIME_WAIT状态,并返回对FIN字段的确认,超时后删除客户端socket
(5)服务器继续侦听其他连接请求,处于LISTEN状态
6.2服务器主动关闭连接
为了模拟服务器主动关闭连接,我们在服务器read_requ函数之后加入return语句,函数serv_resp立即返回主程序,调用close函数关闭socket,TCP协议向客户端发送FIN数据段,客户端TCP协议收到FIN数据段后返回确认,进入CLOSE_WAIT状态,服务器进入FIN_WAIT2状态。
客户端在发送完请求后阻塞在函数read_resp中,收到FIN字段将返回主函数,调用函数close关闭socket,TCP协议向服务器发送FIN数据段,服务器确认该数据段进入TIME_WAIT状态。
6.3服务器进程终止
ps–a 得到服务器的进程id
killid 终止服务器进程
l终止服务器进程时没有客户端连接
终止进程,关闭socket
l终止服务器进程时有未完成的客户端连接
服务器终止进程,关闭socket
(1)如果客户端已经收到SYNACK,connect函数成功,接下来向socket写数据时将失败
(2)服务器尚未确认客户端SYN,或SYNACK丢失,connect函数失败
l终止服务器进程时已有客户端建立连接
服务器进程终止,TCP协议向客户端发送FIN数据段,为了模拟客户端在不同时刻收到FIN数据段,在客户端程序3个地方加入getchar暂停程序
(1)客户端在调用第一个write_all函数前收到FIN数据段,认为服务器不再发送数据,但write_all函数成功,数据到达服务器后,服务器将向客户端发送RST数据段,客户端在调用第二个write_all函数时将被SIGPIPE信号中断,显示BrokenPipe
(2)客户端在调用第二个write_all函数前收到FIN数据段,认为服务器不再发送数据,但write_all函数成功,数据到达服务器后,服务器将向客户端发送RST数据段,此时如果在RSt字段没有到达客户端之前调用函数read_resp,由于已经收到FIN字段,read_resp函数将返回0;如果客户端已经收到RST数据段,则返回CONNREST
(3)客户端在调用read_resp函数前收到FIN数据段,read_resp函数返回0
6.4服务器主机崩溃
由于服务器主机复位,或断线会造成这种情况,主机崩溃和进程终止不同,系统不会关闭进程拥有的socket
l客户端在等待服务器数据时服务器主机崩溃
调用read_resp函数过程中服务器主机崩溃,客户端将永远阻塞,除非设置了读超时选项
l客户端向服务器发送数据时服务器主机崩溃
(1)write_all函数成功执行(拷贝到系统缓冲区),read_all函数阻塞,直到TCP协议重发数据达到限制次数后,返回错误ETIMEOUT
(2)当发送数据需要经过路由器时,路由器会发现服务器主机不可达,向客户端返回ICMP消息,函数调用read_all返回错误EHOSTUNREACH。
6.5客户端主机崩溃(类似于服务器主机崩溃)
l服务器接收客户端请求时客户端主机崩溃
服务器的read_requ函数将永远阻塞,由于服务器是循环服务器,因此服务器永远阻塞,导致服务失效,可以采用并发服务器避免
l服务器向客户端返回响应时客户端主机崩溃
write_all函数成功执行(拷贝到系统缓冲区),read_all函数阻塞,直到TCP协议重发数据达到限制次数后,返回错误ETIMEOUT
补充知识:
多源文件程序编译
1.分别编译各个源文件,利用生成的中间文件(后缀为.o)生成可执行程序
gcc–cftpclient.c
gcc–ccomm_func.c
gcc–oftpclientftpclient.ocomm_func.o
2.生成makefile,利用make整体编译
make命令:
make–fmakefile
makefile中最重要的是描述文件的依赖关系,一般格式为
target:
componets 依赖关系
TABrule 规则(TAB不能省略)
l第一种makefile(内容较多,容易理解)
#ftpclientmakefile 注释
ftpclient:
ftpclient.ocomm_func.o
gcc-oftpclientftpclient.ocomm_func.o
#以下为各个组成元素的子元素及生成方法
ftpclient.o:
ftpclient.ccomm_func.h
gcc-cftpclient.c
comm_func.o:
comm_func.ccomm_func.h
gcc-ccomm_func.c
l第二种makefile
$@--目标文件,$^--所有的依赖文件,$<--第一个依赖文件
#ftpclientmakefile
ftpclient:
ftpclient.ocomm_func.o
gcc-o$@$^
ftpclient.o:
ftpclient.ccomm_func.h
gcc-c$<
comm_func.o:
comm_func.ccomm_func.h
gcc-c$<
l第三种makefile
.c.o规则,表示所有的.o文件依赖于对应的.c文件(文件名相同)
#ftpclientmakefile
ftpclient:
ftpclient.ocomm_func.o
gcc-o$@$^
.c.o:
gcc-c$<