⼀、 TCP协议详解
- 服务器端代码
1)创建套接字
l
socket函数:int sockfd = socket(AF_INET, SOCK_STREAM, 0);
o
AF_INET:IPv4地址族
o
SOCK_STREAM:TCP流式服务
o
返回值:⽂件描述符(与open返回值等价)
l
错误处理:若返回-1表示创建失败,需调⽤exit(1)终⽌程序
2)指定地址
l
l
地址初始化:必须使⽤memset(&serv_addr, 0, sizeof(serv_addr))清零
l
关键参数:
o
serv_addr.sin_family = AF_INET(IPv4协议)
o
serv_addr.sin_port = htons(6000)(端⼝号需转换为⽹络字节序)
o
serv_addr.sin_addr.s_addr = inet_addr("192.168.1.124")(点分⼗进制转
⽹络字节序)
3)绑定端⼝和IP地址
l
bind函数:bind(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr))
o
需将专⽤地址结构体强制转换为通⽤地址结构体
o
常⻅失败原因:n
端⼝被占⽤(需更换端⼝号)
n
IP地址错误(需确认本机实际IP)
l
测试IP选择:
o
127.0.0.1仅限本地测试
o
实际通信需使⽤本机真实IP(如192.168.1.124)
4)监听队列 14:28
l
l
listen函数:listen(sockfd, 5)
o
第⼆个参数5表示监听队列的最⼤⻓度
o
队列满时新连接请求会被拒绝
l
accept阻塞:
o
使⽤accept(sockfd, (struct sockaddr*)&cli_addr, &len)接受连接
o
返回新的⽂件描述符⽤于数据通信
l
数据收发:
o
recv()接收数据(会阻塞等待)
o
send()发送响应数据
5)三次握⼿建⽴TCP连接 l
TCP连接建⽴过程
o
o
SYN报⽂:携带SYN=1标志位和初始序号seq=x,表示请求建⽴连接
o
SYN-ACK报⽂:携带SYN=1、ACK=1标志位,seq=y和ack=x+1,表示确认连接请求
o
ACK报⽂:携带ACK=1标志位,seq=x+1和ack=y+1,完成连接建⽴
l
TCP报⽂结构
o
o
标志位:n
SYN:同步序号,⽤于建⽴连接
n
ACK:确认序号有效
n
FIN:发送端完成发送任务
o
序号机制:
n
32位序号字段标识字节流中数据的顺序
n
32位确认号字段表示期望收到的下⼀个字节序号
l
握⼿队列管理
o
未完成握⼿队列:存放SYN到达但未完成三次握⼿的连接
o
已完成握⼿队列:存放已完成三次握⼿等待accept的连接
o
队列⼤⼩:由listen()函数的backlog参数指定,默认为5
l
关键考点
o
握⼿过程:必须能够描述三次报⽂交换的详细过程
o
序号变化:需要掌握seq和ack值的变化规律
o
队列理解:区分未完成和已完成握⼿队列的功能差异
o
常⻅误区:
n
误认为backlog限制总连接数(实际限制的是已完成握⼿但未被accept的连接
数)
n
忽略SYN报⽂消耗序号的特点
l
实际应⽤
o
connect()函数:客户端调⽤后⾃动完成三次握⼿
o
accept()函数:从已完成握⼿队列中取出连接
o
连接标识:每个连接由客户端IP+端⼝和服务端IP+端⼝唯⼀确定
6)服务器端accept和recv的使⽤ 29:01
l
accept函数⼯作机制
o
o
队列机制:listen()会创建两个队列:未完成握⼿队列和已完成握⼿队列,队列⼤
⼩由listen()的第⼆个参数指定(示例中为5)
o
阻塞特性:当已完成握⼿队列为空时,accept()会阻塞等待,直到有新的连接完成
三次握⼿
o
参数说明:accept()第⼀个参数是监听套接字描述符sockfd,第⼆个参数⽤于接收
客户端地址信息caddr,第三个参数是地址结构体⻓度len
o
o
错误处理:accept返回值⼩于0时需要处理错误(示例中直接continue)o
连接标识:成功建⽴连接后返回的新套接字描述符c⽤于后续数据通信
l
recv函数使⽤要点
o
套接字选择:必须使⽤accept返回的新套接字c进⾏数据收发,⽽⾮监听套接字
sockfd
o
类⽐说明:sockfd相当于"⻔铃"只负责接待,c相当于"服务员"负责实际业务交互
o
参数配置:recv()第⼆个参数是缓冲区buff,第三个参数127表示最⼤接收字节数
(保留1字节给结束符)
o
替代函数:recv()可⽤read()替代,当flags参数为0时两者等效
o
o
返回值处理:返回接收到的字节数,-1表示出错
o
缓冲区初始化:示例中使⽤char buff[128] = {0}确保字符串终⽌符
7)服务器端send的使⽤ 33:10
l
响应机制实现
o
通信流程:完成recv接收后,使⽤send()通过同⼀个套接字c发送响应
o
消息内容:示例中发送固定响应"OK"(2个字符)
o
参数对应:send()参数结构与recv()⼀致,flags同样可以设为0
l
连接管理策略
o
o
单次交互:示例采⽤单次交互后⽴即close(c)的简单模式
o
扩展⽅案:实际可改为循环实现持续对话(类似QQ聊天)
o
⾯试考点:accept只从已完成握⼿队列获取连接,必须完成三次握⼿才能建⽴连
接
- 客户端代码 34:44
1)客户端代码编写与测试准备
ll
测试环境配置:建议使⽤⼿机热点创建局域⽹环境,让多台设备连接同⼀WIFI进⾏测
试,获取各⾃IP地址后即可进⾏通信测试
l
服务器IP设置:在客户端代码中需要指定服务器IP地址为"192.168.1.124",这是测试环
境中的固定服务器地址
2)服务器端代码编写与编译 35:45
l
l
编译验证:使⽤命令gcc ser.c -o ser编译服务器端程序,确保⽆语法错误
l
代码结构:服务器端包含socket创建、bind绑定、listen监听等基本TCP通信流程
3)客户端代码编写:创建套接字与连接服务器 36:28
l
l
套接字创建:使⽤socket(AF_INET,SOCK_STREAM,0)创建TCP套接字,与服务器端
保持⼀致
l
地址结构体:
o
服务器端⼝:必须指定服务器绑定的端⼝6000,表示连接⽬标端⼝
o
IP地址设置:inet_addr("192.168.1.124")指定要连接的服务器的IP地址
l
连接过程:使⽤connect()函数发起连接请求,完成TCP三次握⼿
l
错误处理:连接失败常⻅原因包括服务器未运⾏、⽹络问题、IP/端⼝错误等
4)客户端代码编写:数据发送与接收 41:44
l
l
数据输⼊:使⽤fgets(buff,128,stdin)从键盘获取⽤户输⼊数据
l
数据发送:send()函数发送数据,⻓度计算为strlen(buff)-1以去除换⾏符
l
数据接收:recv()接收服务器响应,缓冲区需要先使⽤memset清空
l
通信闭环:实现"发送请求-接收响应-打印结果"的基本通信流程5)客户端与服务器测试:⽹络设置与条件模式 44:03
l
⽹络模式:虚拟机必须设置为桥接模式(Bridged)才能直接连接物理⽹络
l
⽹络验证:通过ifconfig命令查看IP地址,确认前三个字段与服务器⼀致(192.168.1.x)
6)客户端与服务器测试:IP配置与通信验证 45:00
l
l
连通性测试:使⽤ping命令验证客户端与服务器之间的⽹络连通性
l
IP修改:客户端代码中的服务器IP必须修改为实际测试环境的服务器IP
7)客户端与服务器测试:数据传输与防⽕墙处理 46:17
l
防⽕墙问题:若通信失败可能需要处理防⽕墙设置,开放相应端⼝
l
测试验证:成功通信表现为服务器能接收客户端数据并返回"OK"响应
8)客户端与服务器测试:多线程与并发处理 47:33
l
单线程限制:当前服务器只能顺序处理客户端请求,⽆法并发
l
改进⽅向:使⽤多线程技术可实现同时处理多个客户端连接
9)云服务器与⽹络通信的实际应⽤ 48:00
l
公⽹通信:租⽤云服务器可获得公⽹IP,实现任意⽹络环境的通信
l
学⽣优惠:各⼤云平台提供学⽣认证优惠,可低价体验云服务
10)⽹络⼯程师的⼯作内容与职责 51:07
l
⼯作内容:包括⽹络规划、布线、设备配置、故障排查等实际运维⼯作
l
职业⽅向:⽹络专业毕业⽣主要发展⽅向为⽹络编程或⽹络⼯程实施
- 服务器端代码循环版 52:21
1)服务器端代码的初始问题
l
原始模式缺陷:原服务器代码在accept接受连接后,仅执⾏⼀次receive收数据和send
回复数据就⽴即关闭连接,⽆法维持持久通信。
l
单次交互限制:每个客户端连接只能完成"⼀发⼀收"的简单交互,需要频繁建⽴和断
开连接。
2)服务器端代码的修改思路 52:34
l
循环维持连接:通过添加while循环使服务器在单个连接中持续收发数据,保持连接不
⽴即关闭。
l
accept阻塞特性:当存在活跃连接时,外层accept调⽤会被阻塞,直到当前连接关闭才
会处理新连接请求。
l3)例题1:服务器端代码的循环实现 53:19
1 while(1) {
2 int len = sizeof(caddr);
3 int c = accept(sockfd,(struct sockaddr*)&caddr,&len); // 阻塞等待连接
4 if(c < 0) { continue; }
5 printf("accept c=%d\n",c);
6
7 char buff[128] = {0};
8 int n = recv(c,buff,127,0); // read()
9 printf("buff=%s\n",buff);
10 send(c,"ok",2,0); // write()
11 close(c);
12 }
4)例题2:服务器端代码的循环收发数据 53:56
1 while(1) {
2 char buff[128] = {0};
3 int n = recv(c,buff,127,0);
4 if(n <= 0) {
5 break; // 客户端关闭或出错时退出循环
6 }
7 printf("buff=%s\n",buff);
8 send(c,"ok",2,0);
9 }
5)判断对⽅是否关闭连接的条件 54:20
l
recv返回值含义:
o
n>0:正常接收数据,值为实际接收的字节数
o
n=0:对⽅已关闭连接(核⼼判断条件)
o
n<0:接收过程出现错误
l
电话类⽐:如同通话中对⽅挂断电话,运营商会⾃动终⽌连接。在TCP通信中,recv返
回0即表示对⽅已执⾏close()操作。
l
关键记忆点:recv返回值为零是判断对⽅关闭连接的唯⼀可靠标志,必须牢记该条件
⽤于循环控制。这是⽬前编写⽹络程序时判断连接关闭的最重要依据。
l
- TCP四次挥⼿过程详解 59:09
1)挥⼿基本流程
ll
FIN报⽂作⽤:当⼀端执⾏close()时,底层会发送FIN标志位有效的TCP报⽂,表示通知
对⽅要关闭连接
l
确认机制:接收⽅需回复ACK确认报⽂,确认号为收到的序号值+1(如收到seq=n,则
回复ack=n+1)
l
双向关闭:两端都需要独⽴完成"发送FIN+接收ACK"的过程,形成完整的四次交互
2)报⽂标志位解析
l
l
FIN标志:表示通知对⽅本端要关闭连接,携带此标志的报⽂称为结束报⽂段
l
ACK标志:确认号是否有效,每次收到FIN后必须回复ACK确认
l
序号机制:每次发送FIN需要携带独⽴序号(如seq=n、seq=m),确认号对应对⽅序
号+1
3)挥⼿过程示例
l
l
第⼀次挥⼿:A发送FIN(seq=n),B回复ACK(ack=n+1)
l
第⼆次挥⼿:B发送FIN(seq=m),A回复ACK(ack=m+1)
l
⽣活类⽐:类似电话结束时的对话流程("我要挂电话了"-"好的"-"我也要挂了"-"好
的")
4)三次挥⼿的可能性
l
l
合并条件:当第⼆次挥⼿的ACK和第三次挥⼿的FIN恰好同时发送时,可以合并为⼀次
交互
l
时间敏感性:需要接收⽅⽴即执⾏close()才会出现,若有延迟仍会保持四次挥⼿
l
⾯试重点:实际⼯程中多数为四次,但理论上存在三次挥⼿的可能性5)与三次握⼿对⽐
l
l
建⽴差异:握⼿需要同步初始序列号(SYN),⽽挥⼿是独⽴通知关闭(FIN)
l
状态转换:握⼿经历SYN-SENT/SYN-RCVD状态,挥⼿经历FIN-WAIT/CLOSE-WAIT状态
l
本质区别:握⼿是协商建⽴,挥⼿是通知终⽌(⾮协商性质)
⼆、 TCP头部格式
01:00:31
- TCP连接的建⽴和关闭 01:05:16
1)TCP连接的建⽴过程
l
l
SYN报⽂:
o
客户端发送SYN=1,seq=x的报⽂,进⼊SYN-SENT状态
o
服务器回复SYN=1,ACK=1,seq=y,ack=x+1的报⽂,进⼊SYN-RCVD状态
o
每个SYN报⽂即使不携带数据也要消耗⼀个序号
l
ACK报⽂:
o
客户端发送ACK=1,ack=y+1,seq=x+1的确认报⽂
o
ACK报⽂可以携带数据,若不携带则不消耗序号
o
此时客户端进⼊ESTABLISHED状态
l
三报⽂握⼿必要性:
o
防⽌失效连接请求导致资源浪费
o
示例:若第⼀个SYN报⽂滞留,B收到后会误认为新连接请求
o
通过第三次确认可避免B⻓时间等待⽆效连接
l
四报⽂握⼿变体:
o
可将服务器的SYN+ACK拆分为单独的ACK和SYN报⽂
o
效果与三报⽂握⼿相同,但实际使⽤较少
2)TCP连接释放过程中的状态说明 01:07:24l
l
主动关闭⽅流程:
o
发送FIN=1,seq=u的报⽂,进⼊FIN-WAIT-1状态
o
收到ACK后进⼊FIN-WAIT-2状态
o
最终收到FIN后发送ACK,进⼊TIME-WAIT状态
l
被动关闭⽅流程:
o
收到FIN后发送ACK=1,ack=u+1,进⼊CLOSE-WAIT状态
o
发送⾃⼰的FIN=1,ACK=1,seq=w,ack=u+1,进⼊LAST-ACK状态
o
收到最终ACK后关闭连接
l
序号确认规则:
o
确认号总是前⾯已传送数据的最后⼀个字节序号加1
o
FIN报⽂即使不携带数据也要消耗⼀个序号
o
示例:B的确认号ack=u+1,A的最终确认号ack=w+1
l
TIME-WAIT状态:
o
必须等待2MSL(最⻓报⽂段寿命)时间
o
RFC 793建议MSL=2分钟,实际实现可能更⼩
o
设计⽬的:确保最后⼀个ACK能到达对端
l
半关闭状态:
o
当A→B⽅向关闭⽽B→A⽅向仍开放时
o
A不再发送数据但仍能接收B的数据
o
可能持续较⻓时间直到B也发起关闭
- 测试应⽤程序运⾏ 01:12:00
1)例题1: 服务器代码修改与客户端关闭提示 01:12:02
l
l
客户端关闭检测:在while循环退出后添加打印语句"客户端close关闭了",⽤于明确客
户端连接状态
l
代码修改位置:在break语句后添加打印语句,避免⽆法判断客户端是否关闭的情况
l
编译执⾏:修改后需要重新编译服务器程序才能⽣效
2)例题2: 服务器启动与连接状态分析 01:12:24l
l
连接状态检查:使⽤netstat -natp命令查看⽹络连接状态
l
LISTEN状态:显示服务器正在监听指定端⼝等待连接
l
root权限需求:查看所有进程信息需要切换到root⽤户
3)例题3: 服务器阻塞与数据接收分析 01:13:15
l
l
accept返回值:accept返回值为4表示连接成功建⽴
l
阻塞位置:服务器在执⾏recv函数时阻塞等待客户端数据
l
执⾏流程:accept返回后⽴即进⼊recv等待数据状态
4)例题4: 服务器与客户端数据收发分析 01:14:32
l
l
通信过程:
o
SYN同步:客户端发送SYN seq=j
o
ACK确认:服务器回复SYN seq=k, ACK j+1
o
最终确认:客户端发送ACK k+1
l
关闭连接:需要四次挥⼿完成连接终⽌
5)例题5: 数据未读完的情况分析 01:14:57
l
缓冲区设置:将recv接收⻓度从127改为1,每次只接收1个字符
l
数据接收现象:
o
发送"hello"(5字符)应收到5个"OK"回复
o
发送"ABC"(3字符)可能只收到1个"OK"
l
原因分析:未接收完的数据会保留在接收缓冲区中
6)例题6: 缓冲区数据接收情况分析 01:18:23l
l
缓冲区查看:使⽤netstat -natp查看Recv-Q和Send-Q
l
缓冲区数据:
o
Recv-Q=4表示缓冲区有4个字符(2个"OK")
o
未接收的数据会暂存在缓冲区等待下次读取
l
完整接收:当所有数据到达缓冲区后可以⼀次性读取
l
l
测试现象:
o
发送"hello"后收到5个"OK"回复
o
每个字符对应⼀个"OK"回复
o
缓冲区中可能积压多个回复等待读取
l
缓冲区容量:5个"OK"共10个字符会全部放⼊缓冲区
三、流式服务的特点
01:20:48
- 绘制数据流动图 01:21:02
l
l
缓冲区结构:
o
发送端和接收端各⾃拥有发送缓冲区和接收缓冲区
o
数据流动路径:应⽤层 → 发送缓冲区 → ⽹络传输 → 接收缓冲区 → 应⽤层
l
send操作本质:
o
仅将数据写⼊本地发送缓冲区,不代表数据已送达对⽅
o
示例:执⾏send("hello")时,数据暂存于发送缓冲区等待传输
- 服务特点 01:28:53
1)TCP字节流服务 01:29:00l
l
数据边界模糊:
o
多次send的数据可能在接收缓冲区合并(如"hello"+"ABC"→"helloABC")
o
接收⽅⽆法区分原始发送次数,只能获取连续数据流
l
缓冲区查看命令:
o
使⽤netstat -natp查看Recv-Q(接收缓冲区)和Send-Q(发送缓冲区)
o
关键字段:Proto(协议)、Local/Foreign Address(IP:端⼝)、State(连接状
态)
2)流式服务特点 01:30:38
l
l
收发次数关系:
o
发送次数 ≠ 接收次数(如3次发送可能1次接收完成)
o
类⽐:送⽔⼯可分多次送完5桶⽔,接收⽅只关⼼总量
l
缓冲区阻塞机制:
o
当缓冲区满时:阻塞模式会等待,⾮阻塞模式返回-1
o
实际案例:发送128字节可能只成功写⼊80字节,需循环补发剩余数据
l
可靠性要点:
o
必须检查send返回值,确保所有数据成功写⼊缓冲区
o
极端情况:接收⽅不处理数据时,发送⽅缓冲区将积满导致阻塞
四、服务器与客户端通信案例
01:33:22
- 服务器端代码分析 01:35:22
ll
阻塞问题:当服务器在recv()处阻塞时,新的客户端连接⽆法被accept()处理,导致第
⼆个客户端连接建⽴但⽆法通信
l
原因分析:内层while循环不执⾏完(不关闭当前连接c),程序就⽆法回到外层循环
执⾏accept()
l
TCP握⼿原理:连接建⽴分为"未完成握⼿队列"和"已完成握⼿队列",accept()只负责
从已完成队列取出连接
l
l
缓冲区机制:即使未accept,连接建⽴时系统已分配发送/接收缓冲区,数据实际已到
达(类⽐快递到达驿站)
l
验证⽅法:断开第⼀个客户端连接后,服务器会⽴即处理第⼆个连接的数据
- 服务器端代码修改 01:39:09
l
l
解决⽅案:使⽤多线程处理并发连接
l
实现要点:
o
主线程循环accept()接收新连接
o
每个新连接创建独⽴线程处理通信
o
通过malloc传递连接描述符c(避免直接传地址导致值被覆盖)
l
线程函数设计:
l
注意事项:
o
必须为每个线程分配独⽴内存空间传递参数
o
线程结束后要及时释放分配的内存
o
适合客户端数量不多的情况(线程切换有开销)
- 服务器端代码编译运⾏ 01:43:34
ll
测试结果:多个客户端可以同时连接并通信
l
性能限制:线程数量不宜过多(难以⽀持百万级并发)
l
关闭顺序:客户端发送"end"关闭连接,服务器会打印"client close"
- 查找服务器程序的PID 01:45:25
l
l
命令:ps -ef | grep ser 查找服务器进程
l
线程查看:ps -eLf 显示所有线程信息
l
过滤技巧:
l
观察现象:每连接⼀个客户端,服务器会新增⼀个线程
- 命令优化 01:45:50
l
命令改进:通过多次grep -v过滤⽆关进程信息
l
调试⽤途:获取线程ID可⽤于gdb调试
- 客户端代码修改 01:49:33
l
l
内存泄漏修复:在线程函数中及时free分配的参数内存
l
参数传递原理:必须通过malloc传递值(不能直接传变量地址)
l
并发问题:主线程循环可能修改c的值,导致线程读取错误
五、 TCP连接状态
01:50:50
- TCP连接释放过程
l
l
CLOSE-WAIT状态:
o
当B收到连接释放报⽂段后,发送确认报⽂段(푎푐푘 = 푢 + 1,序号v),进⼊
CLOSE-WAIT状态o
此时TCP处于半关闭状态,A→B⽅向连接已释放,但B→A⽅向仍可传输数据
l
FIN-WAIT-2状态:
o
A收到B的确认后进⼊此状态,等待B的最终连接释放报⽂段
l
LAST-ACK状态:
o
当B没有更多数据发送时,发送FIN=1的报⽂段(序号w,确认号푎푐푘 = 푢 + 1),
进⼊此状态
l
TIME-WAIT状态:
o
A收到B的FIN后发送确认(퐴퐶퐾 = 1,푎푐푘 = 푤 + 1,푠푒푞 = 푢 + 1),进⼊此状态
o
需要等待2MSL时间后才完全关闭连接
- 运输层核⼼功能
l
l
核⼼定位:
o
⾯向通信部分的最⾼层,⽤户功能中的最低层
o
为应⽤层提供端到端的通信服务
l
与⽹络层区别:
o
⽹络层(IP协议)负责主机到主机的通信
o
运输层实现应⽤进程到应⽤进程的通信
l
典型场景:
o
主机A和主机B通过⼴域⽹通信时,必须使⽤运输层协议
o
路由器等⽹络核⼼设备只需使⽤下三层功能
- TCP连接建⽴过程
l
l
SYN-SENT状态:
o
客户端发送SYN=1的连接请求报⽂(初始序号x),进⼊此状态
o
SYN报⽂不携带数据但消耗⼀个序号
l
SYN-RCVD状态:
o
服务器收到SYN后回复SYN+ACK(푎푐푘 = 푥 + 1,初始序号y),进⼊此状态
l
连接建⽴完成:
o
客户端收到SYN+ACK后发送ACK(푎푐푘 = 푦 + 1),双⽅进⼊ESTABLISHED状态
- TCP状态转移图l
l
关键状态转移:
o
粗虚线表示典型服务器端状态转移路径
o
粗实线表示典型客户端状态转移路径
l
重要提示:
o
不同教材的状态图表现形式可能不同,但核⼼状态转换逻辑⼀致
o
需要重点掌握握⼿(SYN-SENT→SYN-RCVD→ESTABLISHED)和挥⼿(FIN-WAIT-
1→FIN-WAIT-2→TIME-WAIT)的主⼲流程
- 并发处理⽅案
l
多线程⽅案:
o
课程示例采⽤的并发处理⽅式
l
多进程替代性:
o
多进程同样可以实现TCP并发服务
o
选择取决于具体应⽤场景和性能需求
六、多进程版本服务器代码
01:52:21
- 客户端代码复⽤说明
l
l
代码复⽤原则:客户端代码将作为固定模板使⽤,后续开发中直接复制调⽤
l
实现细节:
o
使⽤socket()创建套接字:int sockfd = socket(AF_INET,SOCK_STREAM,0);
o
通过connect()建⽴连接:connect(sockfd,(struct
sockaddr*)&saddr,sizeof(saddr))
o
包含必要头⽂件:<stdio.h>,
<stdlib.h>,
<unistd.h>,
<string.h>,
<sys/socket.h>, <netinet/in.h>, <arpa/inet.h>
- 多线程服务器实现l
l
线程函数结构:
o
参数传递使⽤动态内存:int *p = (int*)malloc(sizeof(int))
o
循环接收数据:while(1)中使⽤recv()和send()
o
连接关闭判断:recv()返回值n<=0时跳出循环
l
关键实现:
- 多进程改造⽅案
l
改造原理:
o
使⽤fork()创建⼦进程替代pthread_create()
o
⼦进程继承⽗进程的⽂件描述符,可直接操作连接套接字
o
⽗⼦进程各⾃负责不同的连接处理
l
实现要点:
o
在accept()成功后调⽤fork()
o
⼦进程中关闭监听套接字,⽗进程中关闭连接套接字
o
注意处理僵⼫进程(通过signal(SIGCHLD, SIG_IGN))
- 并发实现多样性说明
l
实现⽅式:
o
多线程与多进程均可实现并发处理
o
具体实现形式不唯⼀,核⼼是保证并发能⼒
l
选择标准:
o
根据系统资源和需求选择合适⽅案
o
多线程资源共享更⽅便
o
多进程稳定性更⾼
七、内容总结
01:53:38
- TCP⽹络编程核⼼要点
l
l
协议特性:TCP是⾯向连接的、可靠的流式传输服务,位于OSI模型的传输层
l
关键机制:
o
三次握⼿:建⽴连接时的SYN/ACK报⽂交换过程
o
四次挥⼿:连接终⽌时的FIN/ACK交互流程
o
并发处理:通过多线程/多进程实现服务端并发连接o
缓冲区管理:数据收发时的缓冲机制
- 多线程服务器实现
l
l
线程函数:
l
关键操作:
o
参数传递:通过动态内存分配传递客户端socket描述符
o
循环接收:使⽤recv()持续读取客户端数据
o
连接检测:通过返回值判断连接状态(n<=0时终⽌)
- 多进程与多线程对⽐
l
l
稳定性差异:
o
进程隔离:单个进程崩溃不影响其他进程,适合服务稳定性要求⾼的场景
o
线程⻛险:线程共享地址空间,信号可能导致整个进程终⽌
l
实践⽅案:
o
管理进程+⼯作进程:主进程监控⼦进程状态,异常时快速重启
o
混合模型:进程内部可创建多线程处理请求
- ⽹络连接状态管