1 传输层概述
1 传输层的功能
传输层简述
- 传输层位于网络层之上,它为运行在不同主机上的进程之间提供了逻辑通信,而网络层提供主机之间的逻辑通信
- 两台主机使用网络进行端到端的通信时,只有主机的协议栈才有传输层和应用层,而路由器在转发分组时都只用到下三层的功能,即在通信子网中没有传输层,传输层只存在于通信子网以外的主机中。
传输层的功能
- 传输层提供应用程序之间的逻辑通信,即端到端的通信
- 复用和分用
- 复用是指发送方不同的应用进程都可使用同一个传输层协议传送数据
- 分用是指接收方的传输层在剥去传输层报文的首部后,能够把这些数据正确交付到目的应用进程
- 传输层要对收到的传输层报文进行差错检测,包括报文首部和数据部分
网络层只检查IP分组的首部,不检验数据部分是否出错
- 提供了两种不同的传输协议,面向连接的TCP和无连接的UDP
- 传输层向高层用户屏蔽了底层网络的细节,它使应用进程看见的是好像两个应用进程之间有一条端到端的逻辑通信信道。
- 当传输层采用面向连接的TCP时,尽管下面的网络是不可靠的,但这种逻辑通信信道就相当于一条全双工的可靠信道。
- 当传输层采用无连接的UDP时,这种逻辑通信信道仍然是一条不可靠信道。
2 传输层的端口
端口的作用
- 端口能够让应用层的各种应用进程将其数据通过端口向下交付给传输层,以及让传输层知道应当将其报文段中的数据向上通过端口交付给应用层相应的进程
- 端口在传输层的作用类似于IP地址在网络层的作用或MAC地址在数据链路层的作用,IP地址和MAC地址标识的是主机,端口标识的是主机中的应用进程
端口号
- 应用进程通过端口号进行标识
- 端口号长度为16bit,能够标识216个不同的端口号
- 端口号只在本主机有意义,即端口号只标志本计算机应用层的各进程,在因特网中不同计算机的相同端口号是没有联系的
端口号可以分为两类,分别是服务端使用的端口号和客户端使用的端口号
- 服务端使用的端口号
服务端口号通常是固定的,服务端使用的端口号又分为两类
- **熟知端口号**
熟知端口号的数值为0~1023,这些端口号被IANA(互联网地址指派机构)指派给了TCP/IP体系中最重要的一些应用程序,让所有用户都知道,常用的熟知端口号如下
- **登记端口号**
登记端口号的数值为1024~49151,这些端口号是供没有熟知端口号的应用程序使用的,使用这类端口号必须在IANA登记,以防止重复
- 客户端使用的端口号
客户端使用的端口号数值为49152~65535,由于这类端口号仅在客户进程运行时才动态选择,因此又称临时端口。通信结束后,刚用过的客户端口号就不复存在,从而这个端口号就可供其他客户进程使用
3 面向连接与面向无连接
TCP是面向连接的,UDP是面向无连接的。
什么叫面向连接,什么叫无连接呢?在互通之前,面向连接的协议会先建立连接。例如,TCP 会三次握手,而 UDP 不会。为什么要建立连接呢?你 TCP 三次握手,我 UDP 也可以发三个包玩玩,有什么区别吗?
所谓的建立连接,是为了在客户端和服务端维护连接,而建立一定的数据结构来维护双方交互的状态,用这样的数据结构来保证所谓的面向连接的特性。
- TCP/UDP建立连接的本质就是在客户端和服务端各自维护一定的数据结构(一种状态机),来记录和维护这个“连接”的状态 。并不是真的会在这两个端之间有一条类似“网络专线”这么一个东西。
3 UDP协议
1 UDP协议简介
- UDP协议概述
- UDP提供无连接的非可靠传输层协议
- UDP在IP之上仅提供两个附加服务:复用分用、对数据的校验
- 网络层只对IP分组的首部进行错误检查
- UDP不保证可靠交付,因此维护传输可靠性的工作需要在应用层完成
- UDP和IP一样,是基于数据报的,一个一个地发,一个一个地收
- 发送方UDP对应用层交下来的报文,在添加首部后就向下交付给IP层,既不合并,也不拆分,而是保留这些报文的边界
- 接收方UDP对IP层交上来的UDP用户数据报,在去除首部后就原封不动地交付给上传应用进程,一次交付一个完整的报文
- 报文(应用层交给UDP的数据)不可分割,是UDP数据报处理的最小单位
- UDP的优点
TCP提供可靠的服务,UDP提供不可靠的服务,但是仍然有很多应用更适合用UDP,因为其有以下优点
- UDP无须建立连接,不会引入建立连接的时延
- 不需要维护连接状态,一般能支持更多的活动客户机
- UDP分组的首部开销小。UDP首部为8B,而TCP首部为20B
- 应用层能够更好地控制要发送的数据和发送时间
- UDP没有拥塞控制,因此网络中的拥塞不会影响主机的发送效率
- 某些实时应用要求以稳定的速度发送,能容忍一些数据的丢失,但不允许有较大的时延,UDP就可以满足这些应用的需求
- UDP协议的应用
- UDP常用于一次性传输较少数据的网络应用且对于丢包不敏感,如DNS、DHCP等
对于这些应用,若采用TCP,则将为连接创建、维护和拆除带来不小的开销
- 可靠的数据传输对很多应用来说并不是最重要的,但TCP的拥塞控制会导致数据出现较大的时延,这是很多应用不能容忍的
- 因此UDP也常用于多媒体应用,如IP电视、实时视频会议、流媒体、直播等
TCP 的严格顺序传输要保证前一个收到了,下一个才能确认,如果前一个收不到,下一个就算包已经收到了,在缓存里面,也需要等着。对于直播来讲,这显然是不合适的,因为老的视频帧丢了其实也就丢了,就算再传过来用户也不在意了,他们要看新的了,如果老是没来就等着,卡顿了,新的也看不了,那就会丢失客户,所以直播,实时性比较比较重要,宁可丢包,也不要卡顿的。
- **实时游戏基本上都使用UDP协议**
如果使用TCP协议,实时游戏中客户端和服务端要建立长连接,来保证实时传输。但是游戏玩家很多,服务器却不多。由于维护 TCP 连接需要在内核维护一些数据结构,因而一台机器能够支撑的 TCP 连接数目是有限的,然后 UDP 由于是没有连接的,在异步 IO 机制引入之前,常常是应对海量客户端连接的策略。
- 基于UDP的应用层协议包括
- TFTP(小文件传送协议)
- DNS
- DHCP
- SNMP
- RTP/RTMP
2 UDP报文段

3 UDP与TCP的区别

4 TCP协议
1 TCP协议简介
- TCP协议概述
TCP协议是在不可靠的IP层之上实现的可靠的数据传输协议
TCP协议的特点
- TCP是面向连接的传输层协议,每条TCP连接只能是一对一的
- TCP提供可靠的交付服务,保证传送的数据无差错、不丢失、不重复、有序
- TCP提供全双工通信,允许通信双方在任何时候都能发送数据
- TCP是面向字节流的,虽然应用层和TCP的交互是一次一个大小不等的数据块,但TCP把应用层交下来的数据视为一连串的无结构的字节流
TCP的发送缓存和接收缓存
- TCP为了支持全双工通信,在发送端和接收端都设有缓存,用来临时存放双向通信的数据
- 发送缓存用来存放以下数据
- 发送应用程序准备发送的数据
- TCP已发送但尚未收到确认的数据
- 接收缓存用来存放以下数据
- 按序到达但尚未被接收应用程序读取的数据
- 不按序到达的数据
- TCP的应用
- TCP提供面向连接的服务,在传送数据之前必须先建立连接,数据传送结束后要释放连接,不提供广播或组播服务。
- 由于TCP提供面向连接的可靠服务,因此不可避免地增加了许多开销,如确认、流量控制、计时器、连接管理等。这不仅使协议数据单元的头部增大很多,还要占用许多的处理机资源
- TCP主要适用于可靠性更重要的场合,如
- 文件传输协议FTP
- 超文本传输协议HTTP
- 远程登录TELNET
2 TCP报文段
- TCP报文段概述
- TCP传送的数据单元称为报文段
- 一个TCP报文段分为TCP首部和TCP数据两部分
- 整个TCP报文段作为IP数据报的数据部分封装在IP数据报中
- TCP首部的前20B是固定的,后面是根据需要而增加的选项
- TCP报文段既可以用来运载数据,又可以用来建立连接、释放连接、应答
TCP报文段首部
- 源端口和目的端口(2B)
- 各占2个字节,分别写入源端口和目的端口,运输层的复用和分用功能都要通过端口实现
- 序号/seq(4B)
- TCP连接中传送的字节流中每个字节都按顺序编号,序号的值指的是本报文段所发送数据的第一个字节的序号
例如,一段报文的序号字段值是301 ,而携带的数据共有100字段,显然下一个报文段(如果还有的话)的数据序号应该从401开始;
- TCP两端的序列号之间没有任何关系,可以各自在建立TCP连接时定义初始序号
- 确认号/ack(4B)
- 确认号是期望收到对方下一个报文的第一个数据字节的序号。
- 若确认号为N,则表明序号N-1为止的所有数据都已正确收到
- 数据偏移(4bit)
数据偏移指首部长度,即指出TCP报文的数据距离TCP报文段的起始处有多远;
- 保留(6bit)
保留今后使用,但目前应都位0;
- 标志位(6bit)
标志位共占6位,每一位都有不同的含义
- 确认位/ACK
- 仅当ACK=1时,确认号字段才有效
- TCP规定在连接建立后所有报文的传输都必须把ACK置1,在建立连接阶段ACK可能是1也可能是0
- 同步位/SYN
- SYN=1表示这是一个连接请求或连接接收报文
- 当SYN=1、ACK=0,表明是连接请求报文,若对方同意连接,则响应报文中应该使SYN=1、ACK=1
- SYN=1的报文不能携带数据
- 终止位/FIN
- 终止位用来释放连接
- 当FIN=1,表明此报文的发送方数据已经发送完毕,并且要求释放连接
- 紧急位URG
- 当URG=1,表明紧急指针字段有效。告诉系统此报文段中有紧急数据,应尽快传送
- 紧急标志位应和紧急指针配合使用,数据从第一个字节到紧急指针所指字节就是紧急数据
- 推送位PSH
接收TCP在收到PSH=1的报文段时,就尽快地交付给接收应用进程而不再等到整个接收缓存都填满后再向上交付
- 复位位RST
当RST=1,表明TCP连接中出现严重差错,必须释放连接然后再重新建立连接;
- 窗口(2B)
接收方的数据缓存空间是有限的,故用窗口值作为接收方让发送方设置其发送窗口的依据,单位为字节
- 检验和(2B)
校验首部和数据这两部分
- 紧急指针(2B)
指出本报文段中的紧急数据的字节数;
- 选项
长度可变,定义一些其他的可选的参数。
3 TCP连接管理
- TCP连接概述
- TCP是面向连接的协议,因此每个TCP连接都有三个阶段:连接建立、数据传送、连接释放
- TCP连接的建立与释放采用C/S方式
- 主动发起连接建立的进程称为客户机,被动等待连接建立的应用称为服务器
- 主动发起连接释放的进程称为客户机,被动等待连接释放的应用称为服务器
参与TCP连接的两个进程中的任何一个都能发起TCP连接释放请求
1 TCP连接的建立——三次握手

- 最开始的时候客户端和服务器都是处于CLOSED状态。
主动打开连接的为客户端,被动打开连接的是服务器
服务器进程先创建传输控制块TCB,时刻准备接受客户进程的连接请求,此时服务器就进入了LISTEN(监听)状态;
第一次握手(客户端→服务器)
- 客户端进程也是先创建传输控制块TCB,然后向服务器发出连接请求报文
连接请求报文首部中的**SYN=1**,同时确定一个初始序列号**seq=x**
- 此时,客户端进程进入了SYN-SENT(同步已发送状态)状态
- TCP协议规定,SYN报文段(
**SYN=1**的报文段)不能携带数据(因为连接还没建立),但需要消耗掉一个序号
- 第二次握手(服务器→客户端)
- 服务器收到请求报文后,如果同意连接,则发出确认报文
确认报文的首部中**ACK=1**、**SYN=1**,确认号**ack=x+1**,同时也要确定一个初始序列号**seq=y**
因为SYN=1,因此确认报文也不能携带数据,但同样要消耗一个序号
- 此时,TCP服务器进程进入了SYN-RCVD(同步收到)状态,在该状态时服务器还会为该TCP连接分配需要的资源
- 第三次握手(客户端→服务器)
- TCP客户进程收到确认后,还要向服务器给出确认,发出确认报文。
确认报文的**ACK=1**、**ack=y+1**,序列号**seq=x+1**
- 此时,TCP连接建立,客户端进入ESTABLISHED(已建立连接)状态,在该状态时客户端还会为该TCP连接分配需要的资源
- TCP协议规定,ACK报文段(ACK=1的报文段)可以携带数据,但是如果不携带数据则不消耗序号
- 当服务器收到客户端的确认后也进入ESTABLISHED状态,此后双方就可以开始通信了。
- 为什么TCP客户端最后还要发送一次确认呢?
- 第三次握手主要防止已经失效的连接请求报文突然又传送到了服务器,从而产生错误。
- 如果使用的是两次握手建立连接,假设有这样一种场景:
客户端发送了第一个请求连接报文,该报文并没有丢失,只是滞留在网络结点中。一段时间后,由于客户端没有收到确认报文,以为服务器没有收到第一个请求连接报文,所以将向服务器发送第二个请求连接报文。第二个请求连接报文正常到达服务器,经过两次握手,服务器与客户端建立连接,传输数据,然后关闭连接。然后此前滞留的第一个请求连接报文在网络通畅后到达了服务器,服务器发出确认报文,虽然这个请求连接报文本该是失效的,但是两次握手的机制将会让服务器认为TCP连接已经建立,并一直等待客户端传输数据,而此时客户端并无连接需求,因此不予理睬,这就造成了服务器的资源浪费
- 上述场景中,如果采用的是三次握手建立连接,就算第一个请求连接报文传送到服务器,服务端回复了确认报文,但是客户端不会再次发出确认。服务器一段时间后收不到确认,也就不会连接了。
- 分配资源的时机
服务端的资源是在完成第二次握手时分配的,而客户端的资源是在完成第三次握手时分配的,因此服务器易于受到SYN泛洪攻击
2 TCP连接的释放——四次挥手

- 最开始的时候,客户端和服务器都是处于ESTABLISHED状态。
客户端主动关闭连接,服务器被动关闭连接。
- 第一次握手
- 当客户端不需要发送数据时,发出连接释放报文,并且停止发送数据
连接释放数据报文首部中**FIN=1**,**seq=u**(u等于前面已经发送过的数据的最后一个字节的序号加1)
- 此时,客户端进入FIN-WAIT-1(终止等待1)状态。
- TCP协议规定,FIN报文段可以携带数据(因为连接还没断开),但即使不携带数据也要消耗一个序号
- 第二次握手
- 服务器收到连接释放报文,发出确认报文
确认报文的首部中**ACK=1**,**ack=u+1**,**seq=v**
- 服务端进入了CLOSE-WAIT(关闭等待)状态
此时,客户端已经没有数据要发送了,但是服务器可以继续发送数据,客户端依然接受
- 客户端收到服务器的确认请求后,进入FIN-WAIT-2(终止等待2)状态,接受服务器发送的数据
第三次握手
- 服务器将最后的数据发送完毕后,就向客户端发送连接释放报文
- 连接释放报文的首部中
**FIN=1**,**ack=u+1**,服务器之前很可能又发送了一些数据,可以假定此时的序列号为**seq=w** - 此时,服务器就进入了LAST-ACK(最后确认)状态,等待客户端的确认
第四次握手
- 客户端收到服务器的连接释放报文后,发出确认报文
确认报文的首部中**ACK=1**,**ack=w+1**,序列号为**seq=u+1**或**seq=u+1+x**,其中x为第一次握手时携带的字节数量
- 此时,客户端就进入了TIME-WAIT(时间等待)状态。
- 注意第四次握手后TCP连接还没有释放,必须经过2×MSL(Maximum Segment Lifetime最长报文段寿命)的时间后,客户端才撤销TCB并进入CLOSED状态
- 服务器只要收到了客户端发出的确认报文,就撤销TCB,立即进入CLOSED状态
因此服务器结束TCP连接的时间要比客户端早一些
- 为什么客户端最后还要等待2MSL?
- 保证客户端发送的最后一个ACK报文能够到达服务器,因为客户端最后一个ACK报文可能丢失
- 站在服务器的角度看来,我已经发送了连接释放报文请求断开连接了,但客户端还没有给我回应,应该是没有收到我发送的连接释放报文,于是服务器又会重新发送一次。而客户端就能在这2MSL时间段内收到这个重传的报文,接着给出回应报文,并且会重启2MSL计时器。
- 如果客户端在发送第四次握手后不等待2MSL而直接进入CLOSED状态,若客户端的第四次握手丢失,则服务器不能进入正常关闭状态(以为客户端没收到第三次握手,所以重复发送第三次握手),而此时客户端已经关闭,也不可能再重传
- 防止类似与“三次握手”中提到了的“已经失效的连接请求报文段”出现在本连接中
- 保证客户端发送的最后一个ACK报文能够到达服务器,因为客户端最后一个ACK报文可能丢失
客户端发送完最后一个确认报文后,在这个2MSL时间中,就可以使本连接持续的时间内所产生的所有报文段都从网络中消失,这样新的连接中不会出现旧连接的报文
- 为什么建立连接是三次握手,关闭连接确是四次挥手?
- 建立连接的时候, 服务器在LISTEN状态下,收到建立连接请求的SYN报文后,把ACK和SYN放在一个报文里发送给客户端。
- 关闭连接时,服务器收到客户端的FIN报文时,仅仅表示客户端不再发送数据了但是还能接收数据,而服务器未必全部数据都发送给客户端了,所以服务器可以立即关闭,也可以发送一些数据给客户端后,再发送FIN报文给对方来表示同意现在关闭连接。
因此,服务器ACK和FIN一般都会分开发送,从而导致多了一次握手。
三次握手和四次握手与现实中的信息交互方式类似 三次握手类似于打电话时的情况:1、听得到吗?2、听得到,你呢?3、我也听到了。然后才开始真正对话 四次挥手类似于下课时的情况:1、老师,下课了。2、好,我知道了,我说完这点。3、好了,说完了,下课吧。4、谢谢老师,老师再见
- 如果已经建立了连接,但是客户端突然出现故障了怎么办?
- 显然,客户端如果出现故障,服务器不能一直等下去,白白浪费资源。
- 服务端设有一个保活计时器,服务器每收到一次客户端的请求后都会重新复位保活计时器,时间通常是设置为两个小时
- 若两小时后还没有收到客户端的任何数据,服务器就会发送一个探测报文段,并且每隔75秒就发送一次。若一连发送10个探测报文后客户端仍然没反应,服务器就认为客户端出了故障,接着就关闭连接
4 TCP的可靠传输
- TCP如何实现可靠传输
- TCP的任务是在不可靠的IP层的基础上建立一种可靠数据传输服务
- TCP提供的可靠数据传输服务保证接收方进程从缓冲区读出的字节流与发送方发出的字节流完全一样
- TCP使用了以下机制来实现可靠传输
- 数据校验
- 序号
- 确认机制
- 重传机制
1 数据校验
- TCP的数据校验机制与UDP的数据校验机制一样,都使用二进制反码运算求和再取反
2 序号
- TCP首部的序号/seq用来保证数据能有序提交给应用层
- TCP把数据视为一个无结构但有序的字节流,序号建立在传送的字节流之上,而不建立在报文段之上
3 确认机制
- TCP首部的确认号/ack是期望收到对方的下一个报文段的数据的第一个字节的序号
发送方缓冲区会存储那些已发送但未收到确认的报文段,以便在需要时重传
TCP默认使用累计确认,即TCP只确认数据流中至第一个丢失字节为止的字
延迟ACK机制
如果TCP对每个数据包都发送一个ACK确认,那么只是一个单独的数据包为了发送一个ACK代价比较高,所以TCP会延迟一段时间
- 如果这段时间内有数据发送到对端,则捎带发送ACK
- 如果在延迟ACK定时器触发时候,发现ACK尚未发送,则立即单独发送;
延迟ACK好处:
- 避免糊涂窗口综合症;
- 发送数据的时候将ACK捎带发送,不必单独发送ACK;
- 如果延迟时间内有多个数据段到达,那么允许协议栈发送一个ACK确认多个报文段(累计确认);
4 重传机制
有两种事件会导致TCP对报文段进行重传:超时和冗余确认
- 超时触发重传
- TCP每发送一个报文段,就对这个报文段设置一次计时器
- 计时器设置的重传时间到期但还未收到确认时,就要重传这一报文段
- 计时器所设置的重传时间是动态调整的
- 冗余确认触发重传/快速重传算法
- 超时触发重传存在的一个问题是超时周期往往太长,而冗余确认机制可以解决这一问题
- 冗余确认就是再次确认某个字节,而发送方先前已经收到过该字节的确认
- TCP规定,每当比期望序号大的报文段到达时,就发送一个冗余确认,再次指明期望的序号
- TCP规定,当发送方收到对同一个序号的三个冗余确认时,就可以认为跟在被确认序号之后的报文段已经丢失,需要立即重传,而不必等待重传计时器超时
- 快重传并非取消重传计时器,而是在某些情况下可更早地重传丢失的报文段
5 TCP的流量控制
TCP提供流量控制来消除发送方使接收方缓存区溢出的可能性,即平衡了发送方发送速率和接收方接收速率的差异。
TCP提供一种基于滑动窗口协议的流量控制机制
- 在通信过程中,接收方根据自己接收缓存的大小,动态地调整发送方的发送窗口大小,这称为接收窗口
- 具体来说就是调整TCP报文段首部中的窗口字段值,来限制发送方向网络注入报文的速率
6 TCP的拥塞控制
拥塞窗口与发送窗口
- 发送方根据其对当前网络拥塞程度的估计而确认的窗口值,这称为拥塞窗口
- 发送方最终的发送窗口的大小取接收窗口和拥塞窗口的最小值
拥塞控制概述
- 拥塞控制是指防止过多的数据注入网络,以使网络中的路由器或链路不致过载
- 对通信连接的端点来说,拥塞往往表现为通信时延的增加
拥塞控制与流量控制
相同点
- 拥塞控制和流量控制都是通过控制发送方发送数据的速率来达到控制效果
不同点
- 拥塞控制是让网络能够承受现有的网络负荷,是一个全局性的过程,涉及所有主机、路由器
- 流量控制是指点对点的通信量的控制
- 拥塞控制算法
因特网建议标准定义了以下四种算法来更好地对传输层进行拥塞控制
- 慢开始
- 拥塞避免
- 快重传
- 快恢复
当发送方检测到超时的时候,就采用慢开始和拥塞避免算法,当发送方接收到三个冗余确认时,就采用快重传和快恢复算法
1 慢开始算法和拥塞避免算法
慢开始算法
- 在TCP刚刚连接好并开始发送TCP报文段时,先令拥塞窗口=1,这里的1指的是一个最大报文段长度(Maximum Segment Size, MSS)
- 每收到一个对新报文段的确认后,将拥塞窗口加1,即增大一个MSS
- 使用慢开始算法后,每经过一个传输轮次(即一个往返时延RTT),拥塞窗口就会加倍
- 慢开始算法一直把拥塞窗口增大到规定的慢开始门限(阈值),然后开始使用拥塞避免算法
拥塞避免算法
- 发送端的拥塞窗口每经过一个RTT,拥塞窗口增加一个MSS
网络拥塞的处理
- 当出现一次超时事件(网络拥塞,重传计时器超时)时,无论是处于慢开始算法阶段还是拥塞避免算法阶段,都令慢开始门限等于当前拥塞窗口的一半(但是不小于2),然后把拥塞窗口设置为1,执行慢开始算法
- 这样做的目的是快速减少主机发送到网络中的分组数
2 快重传算法和快恢复算法
快重传算法和快恢复算法是对慢开始算法和拥塞避免算法的改进
快重传算法
- 在TCP的可靠传输中已经提到了快重传算法
- 当发送方收到三个冗余确认时,说明发生了丢包(同样意味着网络出现拥塞),立即重传紧跟冗余确认的序号之后的报文段
快恢复算法/乘法减小算法
- 发送端收到连续三个冗余确认时,把慢开始门限设置为发送窗口的一半,同时将发送窗口设置为慢开始门限改变之后的值,然后执行拥塞避免算法
- 由于跳过了发送窗口从1开始的慢开始过程,所以被称为快恢复算法
5 应用层使用TCP
1 工作流程
Socket(套接字)概述
- 套接字 =(主机IP地址,端口号)
- 在网络中采用Socket来唯一地标识网络中的一台主机和其上的一个进程
- Socket的英文原义是孔或插座,作为BSD UNIX的进程通信机制,取后一种意思,通常也称作”套接字”。
- Socket用于描述IP地址和端口,是一个通信链的句柄,可以用来实现不同计算机之间的通信
- 在Internet上的主机一般运行了多个服务软件,同时提供几种服务,每种服务都打开一个Socket,并绑定到一个端口上,不同的端口对应于不同的服务。
应用层使用TCP Socket的流程

- 上述方法都是操作系统提供的系统调用
2 TCP的粘包问题
1 粘包现象
- 什么是粘包?
- 粘包问题是指发送方发送的若干包数据到达接收方时粘成了一包
- 从接收缓冲区来看,后一包数据的头紧接着前一包数据的尾

- 造成粘包的原因
核心原因
- TCP是面向流的,而不是面向报文的,并不关心负载的边界
发送端原因
- 用户数据被TCP发出去的时候,存在多个小尺寸数据被封装在一个TCP报文中发出去的可能性,这是由于Nagle算法的存在,在发送的时候把多次send的数据粘在一个TCP报文里面发出去了
- Nagle算法通过减少必须发送包的个数来增加网络软件系统的效率
- 先被send的数据可能需要等待一段时间,才能跟后面被send的数据一起组成报文发出去
接收端原因
- TCP接收到数据包时,并不会马上交到应用层进行处理或者说应用层并不会立即处理
- TCP将接收到的数据包保存在接收缓存里,然后应用程序主动从缓存读取收到的分组。这样一来,如果TCP接收数据包到缓存的速度大于应用程序从缓存中读取数据包的速度,多个包就会被缓存,应用程序就有可能读取到多个首尾相接粘到一起的包。
2 解决粘包问题的方案
- 发送端给每个数据包添加包首部,首部中应该至少包含数据包的长度,这样接收端在接收到数据后,通过读取包首部的长度字段,便知道每一个数据包的实际长度了

- 发送端将每个数据包封装为固定长度(不够的可以通过补0填充),这样接收端每次从接收缓冲区中读取固定长度的数据就自然而然的把每个数据包拆分开来

- 在数据包之间设置边界,如添加特殊符号,这样接收端通过这个边界就可以将不同的数据包拆分开

