TCP协议(包括TCP的连接过程,数据分段,TCP有关服务器优化)

Transmission Control Protocol/Internet Protocol 传输控制协议/因特网互联协议

TCP/IP是一个Protocol Stack(协议栈),包括TCP、IP、UDP、ICMP、RIP、TELNET、FTP、SMTP、ARP等许多协议,最早发源于美国国防部(缩写为DoD)的因特网的前身ARPA网项目,1983年1月1日,TCP/IP取代了旧的网络控制协议NCP,成为今天的互联网和局域网的基石和标准,由互联网工程任务组负责维护。

TCP/IP共定义了四层和ISO参考模型的分层有对应关系

TCP/IP所对应的应用层的协议:

(应用层的我们这里不阐述了,主要说传输层的TCP协议)

传输层所对应的协议:

传输层主要有两个重要的协议,TCP和UDP协议。

TCP:可靠地面向连接的服务

TCP的特性:

工作在传输层
面向连接协议
全双工协议
半关闭
错误检查
将数据打包成段,排序
确认机制
数据恢复,重传
流量控制,滑动窗口
拥塞控制,慢启动和拥塞避免算法

TCP的首部:

TCP的首部由最少5个32bit组成,其中每32个bit为一组:

第一行  :前16bit为source port, 后16bit为destination port    ,自身发起的端口,和要到达端口(端口范围0-65535)
第二行  :32bit表示数据包的序号 Seq 即Seqence  ,其实的Sequnce是随机数并不固定(双方进行通讯所使用的Seq均为自己的,互不相干,请正确理解这句好,再通俗一点讲就是,自己算自己的序列编号。)
第三行  :32bit表示数据包确认的序号 Ack 即 Acknowledgment  ,该位是用来确认对方的Seq的编号,如果正确收到了对方信号,这位的值回事,对方发送到己方的Seq的值+1,主要的作用就是告诉对方,“你发的包,我收到了,请发下一个包”,所以Ack的值为对方Seq的值+1。
第四行:4bit数据偏移,用来表示整个TCP首部的长度(最少5行最多15行,每行4个字节);6bit的保留位,这里不阐述;6bit的状态标示位,分别是:URG、ACK、PSH、RST、SYN、FIN,其中每一位都只有0和1来表示,1表示有状态,0表示无状态。 窗口大小:表示现在允许对方发送的数据量,也就是告诉对方,从本报文段的确认号开始允许对方发送的数据包的数量。

URG:紧急指针位,表示本报文段中发送的数据是否包含紧急数据;当该位为1时,TCP首部的第5行,紧急指针位数据表示有效。
ACK:确认位,表示确认位生效,该ACK 和第三行的Ack不同,第三行为序号,这里的ACK是标志位。
PSH:我也不知道该怎么叫,暂且叫推送位吧,功能:提示接收端应用程序应该立即从TCP接收缓冲区中读走数据,为接收后续数据腾出空间。如果该位为1,在接收数据后,立即马上传送给应用程序,不会放在内核的buffer中。
RST:重置位,当应用程序出现异常,重新创建新的连接。
SYN:同步位,建立连接时使用,用来同步序号(序号)
FIN:终止位,通知对方要关闭连接

第五行:前16bit校验和后16bit紧急指针位;checksum 是个通用的计算机概念,做完整性校验之用,在很多协议(IP,UDP,ICMP)中都有应用,这个值由包的发送方去计算,之后由包的接收方取出来校验。Urgent pointer 为两个字节的偏移量,加上当前包的 sequence number,用来标记某一个范围内的 bytes 为特殊用途数据。

第六行以及以后:选项

选项部分:其最大长度可根据TCP首部长度进行推算。TCP首部长度用4位表示,选项部分最长为:(2^4-1)*4-20=40字节
常见选项:
最大报文段长度:Maxium Segment Size,MSS
指明自己期望对方发送TCP报文段时那个数据字段的长度。默认是536字节。数据字段的长度加上TCP首部的长度才等于整个TCP报文段的长度。MSS不宜设的太大也不宜设的太小。若选择太小,极端情况下,TCP报文段只含有1字节数据,在IP层传输的数据报的开销至少有40字节(包括TCP报文段的首部和IP数据报的首部)。这样,网络的利用率就不会超过1/41。若TCP报文段非常长,那么在IP层传输时就有可能要分解成多个短数据报片。在终点要把收到的各个短数据报片装配成原来的TCP报文段。当传输出错时还要进行重传,这些也都会使开销增大。因此MSS应尽可能大,只要在IP层传输时不需要再分片就行。在连接建立过程中,双方都把自己能够支持的MSS写入这一字段。 MSS只出现在SYN报文中。

窗口扩大:Windows Scaling
为了扩大窗口,由于TCP首部的窗口大小字段长度是16位,所以其表示的最大数是65535。但是随着时延和带宽比较大的通信产生(如卫星通信),需要更大的窗口来满足性能和吞吐率,所以产生了这个窗口扩大选项

时间戳: Timestamps
可以用来计算RTT(往返时间),发送方发送TCP报文时,把当前的时间值放入时间戳字段,接收方收到后发送确认报文时,把这个时间戳字段的值复制到确认报文中,当发送方收到确认报文后即可计算出RTT。也可以用来防止回绕序号PAWS,也可以说可以用来区分相同序列号的不同报文。因为序列号用32为表示,每2^32个序列号就会产生回绕,那么使用时间戳字段就很容易区分相同序列号的不同报文。

TCP首部图片:

建立TCP连接

先看图:

咱们来描述一下上图:

一般发起TCP连接的都是client端
1、首先client端和server端都是处于关闭状态,之后,服务器端打开端口,并绑定IP和端口,使其端口处于LISTEN状态(阻塞)。
2、client端打开端口,像服务器端发出建立tcp连接请求,TCP报文头SYN标记位为1,第二行序号为一个初始随机数x,client端连接状态从CLOSED改变为SYN-SENT
3、server端收到报文后,回应client端报文 SYN,ACK=1确认收到请求,请client端放松下一条信息,TCP第二行seq为自己生成的初始随机数y,TCP首第三行Ack为client端发送报文中seq的值+1,即x+1,server端修改自身状态为SYN-RCVD
4、client端收到server端回馈的信息,再次发送ACK=1表示收到server端信息,根据历史发送的信息,更改seq为之前+1,而TCP首部第三行ack则为server端的seq信号+1,即y+1,修改自身状态为ESTABLISHED
5、server端收到client端的ACK确认TCP连接成立,并修改自身连接状态为ESTABLISHED

上图就是经典的TCP3次握手建立连接的过程。

TCP四次挥手

先看图:

4次挥手就是断开TCP连接的过程,要发起断开TCP连接,无论client端发起还是server端发起,都是可以的。
1、A要求断开TCP,会向B机器发送FIN信号,并发送序列seq=u(继承之前生成的序号+1),自己进入FIN-WAIT-1状态
2、B收到要断开的请求之后回应A一个ACK,并发送序列seq=v(继承之前生成的序号+1),自身进入CLOSE-WAIT状态(处理未处理完的数据),在A收到这条信息后,A的状态改变为FIN-WAIT-2
3、当B处理完未完成的数据后,再次向A发出信号,FIN=1,ACK=1确认关闭连接,自身状态变为LAST-ACK状态
4、A收到B发来的FIN和ACK后,再次回应ACK,自身进入TIME-WAIT状态并等待2倍MSL时间关闭连接(msl为报文段生存时间)
5、B收到A的ack后连接就关闭了。

客户端从FIN_WAIT_1状态可能直接进入TIME_WAIT状态(不经过FIN_WAIT_2状态),前提是处于FIN_WAIT_1状态的服务器直接收到带确认信息的结束报文段(而不是先收到确认报文段,再收到结束报文段)

所有状态的描述:

CLOSED 没有任何连接状态
LISTEN 侦听状态,等待来自远方TCP端口的连接请求
SYN-SENT 在发送连接请求后,等待对方确认
SYN-RECEIVED 在收到和发送一个连接请求后,等待对方确认
ESTABLISHED 代表传输连接建立,双方进入数据传送状态
FIN-WAIT-1 主动关闭,主机已发送关闭连接请求,等待对方确认
FIN-WAIT-2 主动关闭,主机已收到对方关闭传输连接确认,等待对方发送关闭传输连接请求(服务器需要优化的项目)
TIME-WAIT 完成双向传输连接关闭,等待所有分组消失(高并发时,服务器需要优化的项目)
CLOSE-WAIT 被动关闭,收到对方发来的关闭连接请求,并已确认
LAST-ACK 被动关闭,等待最后一个关闭传输连接确认,并等待所有分组消失
CLOSING 双方同时尝试关闭传输连接,等待对方确认(断开连接时不会产生4次握手,直接断开,双方同时发送FIN请求关闭)

TCP连接优化:

处于FIN_WAIT_2状态的客户端需要等待服务器发送结束报文段,才能转移至TIME_WAIT状态,否则它将一直停留在这个状态。如果不是为了在半关闭状态下继续接收数据,连接长时间地停留在FIN_WAIT_2状态并无益处。连接停留在FIN_WAIT_2状态的情况可能发生在:客户端执行半关闭后,未等服务器关闭连接就强行退出了。此时客户端连接由内核来接管,可称之为孤儿连接(和孤儿进程类似)

Linux为了防止孤儿连接长时间存留在内核中,定义了两个内核参数:
/proc/sys/net/ipv4/tcp_max_orphans 指定内核能接管的孤儿连接数目(centos7 默认4096,centos6默认65536)
/proc/sys/net/ipv4/tcp_fin_timeout 指定孤儿连接在内核中生存的时间(默认为60秒)

Linux中Time-Wait值过高优化参数:

本方法只对拥有大量TIME_WAIT状态的连接导致系统资源消耗有效,不是这个原因的情况下,效果可能不明显。使用netstat命令。查看当前TCP/IP连接的状态和对应的个数:
# netstat -an | awk ‘/^tcp/ {++s[$NF]} END {for(a in s) print a, s[a]}’

假如这个命令会显示出类似下面的结果:
TIME_WAIT 63648
FIN_WAIT1 3
FIN_WAIT2 4
ESTABLISHED 184
LISTEN 17

我们只用关心TIME_WAIT的个数,在这里可以看到,有6w多个TIME_WAIT,这样就占用了6w多个端口。要知道端口的数量只有65535个,占用一个少一个,会严重的影响到后继的新连接。这种情况下,我们就有必要调整下Linux的TCP/IP内核参数,让系统更快的释放 TIME_WAIT连接。
/proc/sys/net/ipv4/tcp_syncookies = 1  #表示开启SYN Cookies。当出现SYN等待队列溢出时,启用cookies来处理,可防范少量SYN攻击,默认为0,表示关闭
/proc/sys/net/ipv4/tcp_tw_reuse = 1  #表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0,表示关闭
/proc/sys/net/ipv4/tcp_tw_recycle = 1  #表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭
/proc/sys/net/ipv4/tcp_fin_timeout = 5  # 指定孤儿连接在内核中生存的时间为5秒
如果你的连接数本身就很多,我们可以再优化一下TCP/IP的可使用端口范围,进一步提升服务器的并发能力。加入下面这些配置:
/proc/sys/net/ipv4/tcp_keepalive_time = 1200  #表示当keepalive起用的时候,TCP发送keepalive消息的频度。缺省是2小时,改为20分钟
/proc/sys/net/ipv4/ip_local_port_range = 10000 65000  #表示用于向外连接的端口范围。缺省情况下很小:32768到61000,改为10000到65000
/proc/sys/net/ipv4/tcp_max_syn_backlog = 8192  #表示SYN队列的长度,默认为1024,加大队列长度为8192,可以容纳更多等待连接的网络连接数
/proc/sys/net/ipv4/tcp_max_tw_buckets = 5000  #表示系统同时保持TIME_WAIT的最大数量,如果超过这个数字,TIME_WAIT将立刻被清除并打印警告信息。默认为180000,改为5000。对于Apache、Nginx等服务器,上几行的参数可以很好地减少TIME_WAIT套接字数量,但是对于 Squid,效果却不大。此项参数可以控制TIME_WAIT的最大数量,避免Squid服务器被大量的TIME_WAIT拖死。

经过这样的配置之后,你的服务器的TCP/IP并发能力又会上一个新台阶。

但是当服务器收到大量的短连接时,Linux的TCP栈一般还是会生成大量的 TIME_WAIT 状态的socket。tcp_fin_timeout参数并不能缩短timewait的时间,在linux内核中真正管用的是一个宏定义,在 $KERNEL/include/net/tcp.h里面,有下面的行:
#define TCP_TIMEWAIT_LEN (60*HZ)
而这个宏是真正控制 TCP TIME_WAIT 状态的超时时间的。如果我们希望减少 TIME_WAIT 状态的数目(从而节省一点点内核操作时间),那么可以把这个数值设置低一些,把上面的修改为:
#define TCP_TIMEWAIT_LEN (10*HZ)

  然后重新编译内核,重启系统即可发现短连接造成的TIME_WAIT状态大大减少,一般情况都可以至少减少2/3。也能相应提高系统应对短连接的速度

原文地址:https://www.cnblogs.com/momenglin/p/8485956.html

时间: 2024-10-09 15:39:13

TCP协议(包括TCP的连接过程,数据分段,TCP有关服务器优化)的相关文章

TCP协议学习笔记(一)首部以及TCP的三次握手连接四次挥手断开

TCP协议是一种面向连接的.可靠的流协议. 流即不间断的数据结构.这样能够保证接收到数据顺序与发送相同.但是犹如数据间没有间隔,因此在TCP通信中,发送端应用可以在自己所要发送的消息中设置一个标示长度或间隔的字段信息. 由于TCP为应用提供可靠传输,所以需要对数据传输时数据破坏.丢包.重复以及乱序问题有充分的控制能力.同时TCP协议作为面向连接的协议,只有确认对端存在才会发送数据. TCP通过检验和.序列号.确认应答.重发控制.连接管理.窗口控制等实现可靠传输. 当传输层采用TCP协议进行通信时

TCP协议三次握手连接四次握手断开和DOS攻击

转载:http://blog.csdn.net/fw0124/article/details/7452695 TCP连接的状态图 TCP建立连接的三次握手过程,以及关闭连接的四次握手过程 贴一个telnet建立连接,断开连接的使用wireshark捕获的packet截图. 1.建立连接协议(三次握手)(1)客户 端发送一个带SYN标志的TCP报文到服务器.这是三次握手过程中的报文1.(2) 服务器端回应客户端的,这是三次握手中的第2个报文,这个报文同时带ACK标志和SYN标志.因此它表示对刚才客

数据通讯与网络 第五版第24章 传输层协议-TCP协议部分要点

上一博客记录了UDP协议的关键要点,这部分记录TCP协议的关键要点. 24.3 传输控制协议(TRANSMISSION CONTROL PROTOCOL) TCP(Transmission Control Procotol )协议是一个面向连接,可靠的协议.TCP为了提供面向连接的服务,专门定义了连接创建,数据传输.连接终止阶段.TCP使用GBN和SR协议来提供可靠性.为了实现可靠性这个目标,TCP使用检验和来进行误差控制.重传来处理数据包丢失和冲突.同时还利用了应答和计数机制.在本节,首先讨论

socket使用TCP协议时,send、recv函数解析以及TCP连接关闭的问题

Tcp协议本身是可靠的,并不等于应用程序用tcp发送数据就一定是可靠的.不管是否阻塞,send发送的大小,并不代表对端recv到多少的数据. 在阻塞模式下, send函数的过程是将应用程序请求发送的数据拷贝到发送缓存中发送并得到确认后再返回.但由于发送缓存的存在,表现为:如果发送缓存大小比请求发送的大小要大,那么send函数立即返回,同时向网络中发送数据;否则,send向网络发送缓存中不能容纳的那部分数据,并等待对端确认后再返回(接收端只要将数据收到接收缓存中,就会确认,并不一定要等待应用程序调

简析TCP的三次握手与四次分手(TCP协议头部的格式,数据从应用层发下来,会在每一层都会加上头部信息,进行封装,然后再发送到数据接收端)good

2014-10-30 分类:理论基础 / 网络开发 阅读(4127) 评论(29) TCP是什么? 具体的关于TCP是什么,我不打算详细的说了:当你看到这篇文章时,我想你也知道TCP的概念了,想要更深入的了解TCP的工作,我们就继续.它只是一个超级麻烦的协议,而它又是互联网的基础,也是每个程序员必备的基本功.首先来看看OSI的七层模型: 我们需要知道TCP工作在网络OSI的七层模型中的第四层——Transport层,IP在第三层——Network层,ARP在第二层——Data Link层:在第二

TCP/IP 协议详解和运作过程

一.TCP/IP协议族 TCP/IP协议族体系结构及主要协议.png 1.数据链路层 ARP协议和RARP协议,它们实现了IP地址和机器物理地址之间的相互转化 ARP协议(Address Resolve Protocol,地址解析协议) RARP协议(Reverse Address Resolve Protocol,逆地址解析协议) 作用:网络层是用IP地址寻址一台机器,而数据链路层是用物理地址寻址一台机器,因此网络层必须先将目标机器的IP地址转化成其物理地址,这就是ARP协议的用途.RARP协

tcp建立连接过程

TCP协议建立连接的过程:在TCP/IP协议中,TCP协议提供可靠的连接服务,采用三次握手建立一个连接. 第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认: 第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态: 第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户

[转]socket使用TCP协议时,send、recv函数解析以及TCP连接关闭的问题

Tcp协议本身是可靠的,并不等于应用程序用tcp发送数据就一定是可靠的.不管是否阻塞,send发送的大小,并不代表对端recv到多少的数据. 在阻塞模式下, send函数的过程是将应用程序请求发送的数据拷贝到发送缓存中发送并得到确认后再返回.但由于发送缓存的存在,表现为:如果发送缓存大小比请求发送的大小要大,那么send函数立即返回,同时向网络中发送数据;否则,send向网络发送缓存中不能容纳的那部分数据,并等待对端确认后再返回(接收端只要将数据收到接收缓存中,就会确认,并不一定要等待应用程序调

TCP/IP协议的三次握手过程及Socket套接字

socket 套接字:为了使得多主机多进程通信时,不至于发生混乱情况,必须把端口号和主机的IP地址结合起来使用, 称为插口或套接字. 由于主机的IP地址是唯一的,这样目的主机就可以区分收到的数据报的源端机了. 套接字包括IP地址(32位)和端口号(16位),共48位. 例如(124.33.13.55,200)和(126.45.21.51.25)就是一对套接字,再整个Internet中,再传输层上进行   通信的一对套接字都必须是唯一的. TCP连接的建立 第一次握手:客户端TCP首先给服务器端T