刚开始尝试使用java等后端语言写IO流,或用套接字(socket)实现简单C/S通讯的同窗们,经常会接触到的一个概念:就是所谓的“三次握手”,socket做为一个API接口,封装了TCP/IP通讯的细节,使咱们只须要调用简单的接口而无需关心具体的实现,那么java
三次握手的过程实际上就是相互抛/接(3次)包的过程算法
创建链接后客户端即可从服务器接收数据包进行通讯后端
注意:三次握手时抛/接的包和链接创建后收发的数据包是不一样的!前者是只携带有TCP报文和IP报文头部的包,不携带具体的数据内容,而后者除了TCP和IP报文头部还携带了具体的数据服务器
l 发送端 --> 数据包 --> 接收端网络
l 接收端 --> ACK确认应答 --> 发送端socket
这里的发送端/接收端能够是客户端/服务器,也能够是服务器/客户端,由于TCP通讯是全双工通讯,因此创建链接后能够同时进行如下两个过程:性能
A. 客户端 --> 数据包 --> 服务器 --> ACK应答 --> 客户端spa
B. 服务器 --> 数据包 --> 客户端 --> ACK应答 --> 服务器3d
以下图三次握手时交换包的具体组成:TCP首部+IP首部(无具体数据内容!)blog
TCP通讯以段为单位,段由TCP数据和TCP首部组成
若是再将网络层的IP协议考虑进去的话,TCP/IP通讯以IP分组为单位
IP分组=TCP段+IP首部=(TCP数据+TCP首部)+IP首部
注:TCP首部也算是IP数据包的一部分
创建链接后,最简单的TCP通行是串行进行的,单次通讯发送端只能发送一个段。只有在接收到接收端发来的ACK应答包前,才能将第二个段发出去,这段时间内发送端只能空等待
很显然,串行通讯效率很低,因此咱们想,能不能在第一个段发送出去后,无需等待ACK应答的返回就发送第二个段呢?这样效率不就提升了吗?基于这个理念人们提出了窗口的概念:
窗口:无需等待ACK应答的返回就能够连续发送的段的数量的最大值
上图中,窗口大小为4,段的发送就好像管道通常,窗口大小就比如是“管道”的流量
HTTP做为一种应用层协议,其事务处理要依赖于传输层的TCP协议机制的运做,因此HTTP事务处理的性能瓶颈很大程度上来源于TCP链接,体如今下面几点:
解决方法:采用HTTP持久链接技术消除屡次链接的时延
TCP慢启动机制体如今两方面:
a.限制初次启动时发送的段的数量:
上面提到了TCP窗口的概念,但TCP能不能一开始就发送窗口上限的段呢?答案是不能的,由于这会形成网络拥塞,为了不这个问题,TCP采用了慢启动机制,一开始发送的段数为1,抛接完成后将段数上升为2,而后是4,再而后是8,段数将以指数形式递增,直到窗口大小的上限
b.设置慢启动阀值
由上图能够看到,当达到拥堵窗口的大小时,将致使超时重发,这时初次发送的段数又从1开始指数递增,不一样的地方是:这时候设置了慢启动阀值(拥堵窗口的一半),发送的段数达到慢启动阀值时,将再也不以指数形式上升,而是按必定的比例缓慢得直线上升
解决方法:正是由于单次TCP链接的时延和TCP的慢启动机制,HTTP的持久链接才显得尤其重要
TCP协议自己并无有规定发送单个段的数据包大小的最小值,那让咱们想一想,若是咱们试图在单个段中发送几个字节的数据包会怎样呢?若是这样,TCP将经过Nagle算法的机制来提升网络利用率,很显然,将包含数据量极小的段都单独发出去将会极大下降网络利用率,因此经过Nagle算法,不直接派发小数据量的段,而是选择将它们绑定在一块儿,当达到要求尺寸后才派发出去,这形成了时间上的延迟。Nagle算法是一把双刃剑,它提升了网络利用率,但同时形成了TCP的时延
解决方法:Nagle是能够选择关闭的,固然,前提是你得在TCP通讯中写入大块的数据
《HTTP权威指南》做者古尔利
《图解TCP/IP》做者竹下隆史