linux高性能服务器编程学习总结(二)
第三章 TCP详解
TCP的连接是一对一的,所以基于多播和广播的应用程序不能使用TCP服务,而UDP非常适合广播和多播。发送端应用连续执行多次写操作,TCP模块将数据放入TCP缓冲区。TRP模块真正开始发送数据时,缓冲区的数据可能被封装成一个或多个TCP报文段发出。
接收端应用程序可以一次性将TCP接收缓冲区的数据全部读出,也可以分多次读出,这取决于用户指定的应用程序读缓冲区的大小。这就是字节流的概念:应用程序对数据的发送和接收没有字节限制
而UDP发送端每执行一次写操作,UDP模块就将其封装成一个UDP数据报并发送,接收端必须及时针对每个UDP数据报执行读操作(recvfrom系统调用),否则就会丢包。并且,如果用户没有指定足够的应用程序缓冲区来读取UDP数据,则UDP数据将被截断。
TCP可靠的原因:1)发送端必须接收到应答,才认为TCP报文段传输成功;2)超时重传机制,发送端发出一个TCP报文端后启动定时器;3)TCP报文段是以IP数据报发送,而IP数据报到达接收端可能乱序、重复,而TCP接收端会将收到的TCP报文段重排、整理、再交付给应用层。
3.2 TCP固定头部结构
16位端口号:告知主机报文段是来自哪里以及传给哪个上层协议程序。
32位序号:ISN,某个TCP报文段传送的数据是字节流中的第1025~2048字节,那么该字段的序号值是ISN+1025。
32位确认号:用作另一方发送来的TCP报文段的响应。
4位头部长度:标识TCP头部有多少个32bit字(4字节),因为4位最大能表示15,所以TCP头部最长是60字节
6位标志位:
1)URG标志:表示紧急指针是否有效
2)ACK标志:表示确认号是否有效。我们称携带ACK标志的TCP报文段为确认报文段
3)PSH标志:提示接收端应用程序应该立即从TCP接收缓冲区中读走数据,为接收后续数据腾出空间
4)RST标志:表示要求对方重新建立连接。我们称携带RST标志的TCP报文端为复位报文段
5)SYN标志:表示请求建立一个连接。称此报文为同步报文段
6)FIN标志:表示通知对方端要关闭连接。称为结束报文段。
16位窗口大小:是TCP流量控制的一手字段。指的是接收通告窗口RWND。它告诉对方本端的TCP接收缓冲区能容纳多少个字节的数据,这样对方就可以控制发送数据的速度。
16位检验和(TCP checksum):发送端填充,接收端对TCP报文段执行CRC算法以检验TCP报文段在传输过程中是否损坏。此处的校验不仅包括TCP头部,也包括数据部分。这也是TCP可靠传输的一个重要保障。
16位紧急指针:正的偏移量。它和序号字段的值相加表示最后一个紧急数据的下一个字节的序号。也称为紧急偏移。
TCP头部的最后一个选项字段是可变长的可选信息。这部分最多包含40字节
常见的7种TCP选项
kind=0:选项表结束选项
kind=1:空操作选项,用于将tcp总长度填充为4字节的整数倍
kind=2最大报文段长度选项。TCP连接初始化时,通信双方使用该选项来协商最大报文段长度(Max Segment Size,MSS).TCP的MSS通常设置为(MTU-40)字节(减掉的40字节包括20字节的TCP头部和IP字节的头部)。对以太网而言,MSS直是1460(1500-40)字节
kind=3:窗口扩大因子选项,TCP头部中接收通告窗口大小是用16位表示的,故最大为65535字节。假设TCP头部中的接收通告窗口大小是N,窗口的扩大因子(移位数)是M,那TCP的实际接收通告窗口大小是N*2^M。
和MSS选项一样,窗口扩大因子选项只能出现在同步报文段,否则将被忽略。
kind=4:选择性确认(SACK),使TCP模块只重新发送丢失的TCP报文段
kind=5:SACK实际工作的选项
kind=8:时间戳选项,较为准确的计算通信双方的回路时间,从而为TCP流量控制提供重要信息。
3.3 TCP连接的建立和关闭
三次握手
3.3.2 半关闭
TCP连接是全双工,允许两个方向的数据传输被独立关闭。通信的一端可以发送结束报文段给对方,本端已经完成了数据传输,但允许继续接收来自对方的数据,直到对方发送完数据以关闭连接,TCP的这种连接状态为半关闭状态。
服务端和客户端应用程序判断对方是否已经关闭连接的方法是:read系统调用返回0,socket网络编程接口通过shutdown函数提供了对半关闭的连接,使用半关闭的应用程序很少见
3.3.3 连接超时
iptables-I INPUT-p tcp–syn-i eth0-j DROP 过滤数据包,丢弃所有接收到的连接请求。分别以1s、2s、4s、8s、16s、32s进行重连。TCP模块一共执行5次重连操作,这是由/proc/sys/net/ipv4/tcp_syn_retries内核变量所定义的,每次重连的超时时间都增加一倍,在5次重连均失败的情况下,TCP模块放弃连接并通知应用程序
3.4 TCP状态转移
TCP连接一端在任一时刻都处于某种状态,当前状态可以通过netstat命令查看,
客户端通过connect系统调用主动与服务器建立连接,此时客户端的状态转移到SYN_SENT状态。而connect系统调用可能由于:1)连接的服务端端口不存在,或该端口任处于TIME_WAIT状态,则服务器将给客户端发送一个复位报文段,connect调用失败
2)目标端口存在,但connect在超时时间呢未收到服务器的确认报文段,则connect调用失败。
connect调用失败将使连接立即返回到初始的CLOSED状态,如果客户端成功收到服务端的同步报文和确认,则调用成功,连接转移至ESTABLISHED状态。
当客户端执行主动关闭时,将向服务端发送一个结束报文段,同时连接进入FIN_WAIT_1状态。客户端收到确认报文段后,则连接转移至FIN_WAIT_2状态,此时的服务端处于CLOSE_WAIT状态。若此时服务器也关闭连接(发送结束报文段),则客户端将给予确认并进入TIME_WAIT状态。
TIME_WAIT状态存在的原因有两点:
1.可靠地终止TCP连接
2.保证让迟来的TCP报文段有足够的时间被识别并丢弃
有时候希望能避免TIME_WAIT状态,指定端口通信重启时,会无法重启,可以通过socket选项SO_REUSEADDR来强制使用。
3.5 复位报文段
TCP连接的一端会向另一端发送携带RST标志的报文段即复位报文段
3.5.2 异常终止连接
TCP提供了异常终止一个连接的方法,即给对方发送一个复位报文段,一旦发送了复位报文段,发送端所有排队等待发送的数据都将被丢弃。应该程序可使用socket选项SO_LINGER来发送复位报文段。
3.5.3 处理半打开连接
如果客户端(或服务器)往处于半打开状态的连接写入数据,则对方将回应一个复位报文段
3.7 TCP成块数据流
3.8 带外数据
有些传输协议具有带外(out of band,OOB),用于迅速通告对方本端发生的重要事件。因此,带外数据比普通数据有更高的优先级,实际应用中仅有telnet,ftp.
UDP没有实现带外数据,TCP也没有真正的带外数据,但是利用TCP头部的紧急标志和紧急指针两个字段,给应用程序提供了一种紧急方式。
发送端一次发送的多字节的带外数据中只有最后一字节被当作带外数据。并且发送的报文段标志位将被置为URG。
TCP接收端只有在接收到紧急指针标志时才检查紧急指针,然后根据紧急指针所指的位置确定带外数据的位置,并将它读入一个特殊的缓存中。这个缓存只有1字节,称为带外缓存。如果上层应用程序没有及时将带外数据从带外缓存中读出,则后续的带外数据(如果有的话)将覆盖它。
3.9超时重传
iperf是一个测量网络状况的工具,-s表示将其作为服务器运行。由此可见,TCP一共执行5次重传,每次重传超时时间都增加一倍(因此,和TCP超时重连的策略相似)。在5次重传均失败的情况下,底层的IP和ARP开始接管,直到telnet客户端放弃连接为止。
Linux有两个重要的内核参数与TCP超时重传相关:/proc/sys/net/ipv4/tcp_retries1
和/proc/sys/net/ipv4/tcp_retries2。前者指定在底层IP接管之前TCP最少执行的重传次数,默认值是3。后者指定连接放弃前TCP最多可以执行的重传次数,默认值是15(一般对应13~30 min)。在我们的实例中,TCP
超时重传发生了5次,连接坚持的时间是15 min(可以用date命令来测量)。
3.10拥塞控制
TCP还有一个重要的任务,提高网络利用率,降低丢包率,并保证网络资源对每条数据流的公平性。
拥塞控制的四个部分:
1)慢启动(slow start)
2) 拥塞避免(congestion avoidance)
3) 快速重传(fast retransmit)
4)快速恢复(fast recovery)
拥塞控制的输入和输出
CWND
SWND CWND SWND 网络 RWND
RWND
cwnd:拥塞窗口;rwnd: 接收通知窗口;swnd:发送窗口;
实际上的swnd是由cwnd和rwnd取小的值,拥塞控制的输入是cwnd,swnd;输出是cwnd
3.10.2慢启动和拥塞避免
TCP建立连接后,CWND将被设置成初始值IW(initial window),大小是2~4个SMSS。此时发送端最多只能发送IW字节的数据,此后发送端每收到接收端的一个确认,其CWND就会增长:
CWND+=min(N,SMSS)
其中N是此次确认中包含的之前未被确认的字节数,CWND的值会指数增长,TCP模块刚发送数据时不知道网络的状态,因此需要用一种试探的方式平滑的增加CWND
但是若不施加其他手段,慢启动必然使得CWND快速膨胀并可能最终导致网络拥塞,因此TCP拥塞控制中定义了另一个重要的状态变量:慢启动门限(slow start threshold size,ssthresh)。当CWND超过这个值,TCP拥塞控制将进入拥塞避免,这样使得CWND按照线性方式增加。RFC5681提到了两种实现方式:
1)每个RTT时间内按照上面提到的公式计算CWND,而不论该RTT时间内发送端收到多少个确认
2)每收到一个新数据的确认报文段,就按照下面的公式进行更新
CWND+=SMSS*SMSS/CWND
上面都是介绍未检测到拥塞时所采用的积极避免拥塞的方法,下面时拥塞发生时的处理方法。
发送端判断拥塞发生的依据有:1.传输超时,或者TCP重传定时器溢出 2.接收到重复的确认报文段。
针对1的解决方法:慢启动和拥塞避免;针对2的解决方法:快速重传和快速恢复。第二种情况如发生在重传定时器溢出之后,则也被拥塞控制当成第一种情况来对待
如果发送端检测到传输超时,拥塞控制再次进入慢启动阶段
3.10.3快速重传和快速恢复
快速重传首先要求每收到一个乱序的报文段就立即发出重复确认,只要超过三次就立即重发,而不需要等待设置的重传计数器时间到
在很多情况下,发送端都可能接收到重复的确认报文段,比如TCP报文段丢失,或者接收端收到乱序TCP报文段并重排之。当发送端连续收到3个重复的确认报文段,就认为是拥塞发生。然后启用快速重传和快速恢复算法,过程如下:
1)当收到第3个重复的确认报文段,计算ssthresh=max(FlightSize/2,2*SMSS)其中FlightSize是已经发送但未收到确认的字节数,然后立即重传丢失的报文,并按照CWND=ssthresh+3SMSS来设置
2)每收到一个重复的确实时,设置CWND=CWND+SMSS.此时发送端可以发送新的报文
3) 当收到新数据的确认时,设置CWND=ssthresh(ssthresh是新的慢启动门限值,由第一步计算得到)
linux高性能服务器编程学习总结(二)相关推荐
- 《Linux高性能服务器编程》学习笔记
<Linux高性能服务器编程>学习笔记 Linux高性能服务器编程 TCP/IP协议族 TCP/IP协议族体系结构以及主要协议 数据链路层 网络层 传输层 应用层 封装 分用 测试网络 A ...
- Linux高性能服务器编程——书籍阅读笔记
目录 前言 正文 第一章 1. 零拷贝函数 2. TCP/IP协议族 3. OSPF 4. ARP协议 5. RARP 6. ICMP协议 7. TCP协议 8. UDP协议 9. 封装 第四章 TC ...
- 《Linux高性能服务器编程》——导读
前 言 为什么要写这本书 目前国内计算机书籍的一个明显弊病就是内容宽泛而空洞.很多书籍长篇大论,恨不得囊括所有最新的技术,但连一个最基本的技术细节也无法解释清楚.有些书籍给读者展现的是网络上随处可见的 ...
- Linux 高性能服务器编程——多线程编程
问题聚焦: 在简单地介绍线程的基本知识之后,主要讨论三个方面的内容: 1 创建线程和结束线程: 2 读取和设置线程属性: 3 线程同步方式:POSIX信号量,互斥锁和条 ...
- 【Todo】【读书笔记】Linux高性能服务器编程
在读 /Users/baidu/Documents/Data/Interview/服务器-检索端/<Linux高性能服务器编程.pdf> 其实之前读过,要面试了,需要温习. P260 So ...
- linux高性能服务器编程书本总结
目录 目录分析 第一篇从 1-4章节主要是介绍 计算机网络基础知识和 TCP/IP模型 第二篇 核心篇 5 章到 15 章节 5-6章节 主要介绍 套接字编程API的使用和介绍 7章 是linux 服 ...
- linux高性能服务器编程第八章(高性能服务器程序框架)
C/S模型 传统C/S,一端作为客户端,一端作为服务器,这里不做多介绍. P2P模型 peer 2 peer ,每台机器使用服务的同时也提供服务,通俗的讲,没有绝对客户端和服务端的概念,当下云计算的模 ...
- 《Linux高性能服务器编程》学习总结(四)——TCP/IP通信案例:访问Internet上的Web服务器...
第四章 TCP/IP通信案例:访问Internet上的Web服务器 HTTP协议是工作在应用层上的协议,其应用十分广泛,而在进行通信的过程中,经常使用HTTP代理服务器.HTTP代理服务器主 ...
- 《Linux高性能服务器编程》阅读笔记 之(二)IP 协议详解
目录 IP服务的特点 IPv4 头部结构 介绍 使用 tcpdump 观察 IPv4 头部结构 IP 分片 介绍 使用 tcpdump 观察 IP 分片 IP路由 IP 模块工作流程 路由机制 IP转 ...
最新文章
- 解决mysqlAccess denied for user'root'@'IP地址'问题
- python foreach用法_C# 中 foreach 遍历的用法
- boost::rotate_copy相关的测试程序
- extmail如何登陆mysql_linux下ExtMail邮件使用及管理平台
- 非主流照片制作软件 Picasa有哪些主要的功能
- 电子科学与技术跨考计算机,关于跨考计算机的纠结
- 装多系统的U盘启动盘的制作
- iOS多线程的初步研究(三)-- NSRunLoop
- 制作stlink(烧录部分)
- 基于知识图谱的智能问答方案
- linux中nobody添加所有权限,LINUX用户权限问题(nobody用户删除文件)
- 程序员能力提升——7-2-1法则,让知识转化为职业竞争力
- 思维改变生活:亲身经历了就一定能明白吗?
- 一个轻巧高效的多线程c++stream风格异步日志(二)
- 新库上线 | CnOpenDataA股上市公司董监高信息数据
- 上海为什么更需要“自贸区”?
- 笔记本的维修实例(转)
- IT人看《国富论》系列:第一篇之第四章:论货币的起源及其效用。UML是软件行业的货币...
- Python考试题,大学生必看
- 沉睡者IT - 十月之后「牛市」还是「熊市」