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。也能相应提高系统应对短连接的速度

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

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

    TCP协议是一种面向连接的.可靠的流协议. 流即不间断的数据结构.这样能够保证接收到数据顺序与发送相同.但是犹如数据间没有间隔,因此在TCP通信中,发送端应用可以在自己所要发送的消息中设置一个标示长度 ...

  2. TCP协议:三次握手过程详解

    本文通过图来梳理TCP-IP协议相关知识.TCP通信过程包括三个步骤:建立TCP连接通道,传输数据,断开TCP连接通道.如图1所示,给出了TCP通信过程的示意图. 上图主要包括三部分:建立连接.传输数 ...

  3. 深入浅出TCP协议的三次握手过程

    TCP是主机对主机层的传输控制协议,提供可靠的连接服务,采用三次握手确认建立一个连接: 每一次TCP连接都需要三个阶段:连接建立.数据传送和连接释放.“三次握手”就发生在连接建立阶段. 1.三次握手( ...

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

    转载:http://blog.csdn.net/fw0124/article/details/7452695 TCP连接的状态图 TCP建立连接的三次握手过程,以及关闭连接的四次握手过程 贴一个tel ...

  5. Loadrunner socket协议lrs_receive函数接收到返回数据包 仍然等待服务器返回--解决

    前段时间在使用loadrunner socket协议发送数据包到到服务器,使用lrs_receive接收服务器应答数据包,已经接收到数据包,但LR仍然在等待服务器端返回,而且日志打印显示每次接收返回都 ...

  6. TCP协议滑动窗口(一)——控制大批量数据传输速率

    窗口大小:TCP头中一个16位的域,表示当前可用接受缓冲区大小.在每个TCP对等段连接初始化时,告诉对方自己的窗口大小(不一定是满额,假如满额65201字节,可能暂时通告5840字节).若客户端接受数 ...

  7. 【Java】学习路径60-利用TCP协议接收多个客户端的数据

    import java.io.IOException; import java.net.*; public class TCP_Server { public static void main(Str ...

  8. 基于TCP协议 I/O多路转接(select) 的高性能回显服务器客户端模型

    服务端代码: myselect.c #include <stdio.h> #include <netinet/in.h> #include <arpa/inet.h> ...

  9. 计算机网络:TCP协议建立连接的过程为什么是三次握手而不是两次?【对于网上的两种说法我的思考】

    网上关于这个问题吵得很凶,但是仔细看过之后我更偏向认为两种说的是一样的. 首先我们来看看 TCP 协议的三次握手过程 如上图所示: 解释一下里面的英文: 里面起到作用的一些标志位就是TCP报文首部里的 ...

随机推荐

  1. layui 第三方组件 eleTree 树组件 树形选择器

    使用 JS位置 ,layui/lay/modules/eleTree.js:CSS位置 ,layui/css/modules/eleTree/eleTree.css: ## 下面应用即可页面css引用 ...

  2. Nginx的负载均衡和项目部署

    nginx的作用 Nginx是一款自由的.开源的.高性能的HTTP服务器和反向代理服务器:同时也是一个IMAP.POP3.SMTP代理服务器:Nginx可以作为一个HTTP服务器进行网站的发布处理,另 ...

  3. 使用zookeeper作为分布式锁以及设计一种通知监听模式

    1.创建实例/** * 初始化单例的便捷方法 */ public static void init() { getInstance(); } /** * 获取单例 * @return */ publi ...

  4. Springboot使用launch.script打包后解压缩

    今天拿到一个SpringBoot的jar需要反编译看一下.直接用工具试了下提示报错. 于是用文本工具打开看了下,发现此JAR包在打包时候引入了启动脚本.如下图: 为了反编译,可以直接将所有启动脚本相关 ...

  5. Linux下nginx配置https协议访问的方法

    一.配置nginx支持https协议访问,需要在编译安装nginx的时候添加相应的模块--with-http_ssl_module 查看nginx编译参数:/usr/local/nginx/sbin/ ...

  6. 03 Python基础

    1.输出和输入 (1)print打印 Python 提供print方法来打印信息 输入: print ("hello python") 调用print方法,用户双引号(" ...

  7. python入门小结

    以下划线开头的标识符是有特殊意义的.以单下划线开头(_foo)的代表不能直接访问的类属性,需通过类提供的接口进行访问,不能用"from xxx import *"而导入: 以双下划 ...

  8. PAT A1016 Phone Bills (25)

    题目描述 A long-distance telephone company charges its customers by the following rules: Making a long-d ...

  9. 02docker核心概念

    1:docker三大核心概念 核心概念 描述 镜像 Docker镜像类似于虚拟机镜像,可以将它理解为一个只读的模板. 容器 Docker容器类似于一个轻量级的沙箱,Docker利用容器来运行和隔离应用 ...

  10. PLSQL Developer 12 汉化包下载

    下载地址: https://www.allroundautomations.com/plsqldevlang/120/index.html