udp/tcp协议及三次四次握手

用户数据报协议(UDP

UDP是一个简单的传输层协议(RFC 768)。

进程往一个UDP套接字写入一个消息,该消息随后被封装(encapsulating)到一个UDP数据报,该UDP数据报进而又被封装到一个IP数据报,然后发送到目的地。

(1) UDP的几个不保证

[1] 不保证UDP数据报会到达其最终目的地;

[2] 不保证各个数据报的先后顺序跨网络后保持不变;

[3] 不保证每个数据报只到达一次;

……

总之,UDP不提供可靠性,其本身不提供确认、序列号、RTT估算、超时、重传、流量控制等机制。如果想要确保一个数据报达到其目的地,可以往应用程序中添置一大堆的特性:来自对端的确认、本端的超时与重传等。即,UDP应用必须处理所有这些情况

(2) UDP几个特点

[1] 每个UDP数据报都有一个长度,而TCP是一个字节流(byte-stream)协议,没有任何记录边界,这一点不同于UDP;

[2] UDP提供无连接的(connectionless)服务,因为UDP客户与服务器之间不必存在任何长期的联系。即,一个UDP客户可以创建一个套接字并发送一个数据报给一个给定的服务器,然后立即用同一个套接字发送另一个数据报给另一个服务器;同样,一个UDP服务器可以用同一个UDP套接字从若干个不同的客户接收数据报;

传输控制协议(TCP

由TCP向进程提供的服务不同于由UDP提供的服务。

(1) TCP提供客户与服务器之间的连接(connection)。TCP客户先与某个给定服务器建立一个连接,再跨该连接与那个服务器交换数据,然后终止这个连接。

(2) TCP还提供了可靠性(reliability)。当TCP向另一端发送数据时,它要求对端返回一个确认。如果没有收到确认,TCP就自动重传数据并等待更长时间,在数次重传失败后,TCP才放弃,如此在尝试发送数据上所花的总时间一般为4~10分钟(依赖于具体实现)。即,TCP的可靠性是指数据的可靠递送或故障的可靠通知

(3) TCP含有用于动态估算客户和服务器之间的往返时间(round-trip time, RTT)的算法,以便它知道等待一个确认需要多少时间。

(4) TCP通过给其中每个字节关联一个序列号,对所发送的数据进行排序(sequencing)。例如,假设一个应用写2048字节到一个TCP套接字,导致TCP发送2个分节:第一个分节所含数据的序列号为1~1024,第二个分节所含数据的序列号为1025~2048。(注意:分节是TCP传递给IP的数据单元。)如果这些分节非顺序到达,接收端TCP将先根据它们的序列号重新排序,再把结果数据传递给接收应用。如果接收端TCP接收到来自对端的重复数据(譬如说,对端认为一个分节已丢失并因此重传,而这个字节并没有真正丢失,只是网络通信过于拥挤),它可以根据序列号判定数据是重复的,从而丢弃重复数据。

(5) TCP提供流量控制(flowcontrol)。TCP总是告知对端在任何时刻它一次能够从对端接收多少字节的数据,这称为通告窗口(advertised window)。即,在任何时刻,该窗口指出接收缓冲区中当前可用的空间量,从而确保发送端发送的数据不会使接收缓冲区溢出。

该窗口时刻动态变化:当接收到来自发送端的数据时,窗口大小就减小;当接收端应用从缓冲区中读取数据时,窗口大小就增大。

通知窗口大小减小到0是有可能的:当TCP对应某个套接字的接收缓冲区已满,导致它必须等待应用从该缓冲区读取数据时,方能从对端再接收数据。

(6) TCP连接是全双工的(full-duplex)。即,在一个给定的连接上应用可以在任何时刻在进出两个方向上既发送数据又接收数据。因此,TCP必须为每个数据流方向跟踪诸如序列号和通知窗口大小等状态信息。

TCP连接的建立和终止

(1) TCP连接建立——三次握手

[1] 服务器必须准备好接收外来的连接,这通常通过调用socket、bind和listen这3个函数来完成,称之为“被动打开”(passive open);

[2] 客户调用connect发起“主动打开”(active open)。这导致客户TCP发送一个SYN(同步)分节,它告诉服务器客户将在(待建立的)连接中发送的数据的初始序列号。通常SYN分节不携带数据,其所在IP数据报只含有一个IP首部、一个TCP首部及可能有的TCP选项;

[3] 服务器必须确认(ACK)客户的SYN,同时自己也得发送一个SYN分节,它含有服务器将在同一连接中发送的数据的初始序号列。服务器在单个分节中发送SYN和对客户SYN的ACK(确认);

[4] 客户必须确认服务器的SYN;

这种交换至少需要3个分组,因此称之为TCP的三路握手(three-way handshake)。

(2) TCP选项

每一个SYN可以包含有多个TCP选项,一些常用的选项有:

[1] MSS选项

发送SYN的TCP一端使用本选项通告对端它的最大分节大小(maximum segmentsize, MSS),即,它在本连接的每个TCP分节中愿意接收的最大数据量。发送端TCP使用接收端的MSS值作为所发送分节的最大大小。TCP_MAXSEG

[2] 窗口规模选项

TCP连接任何一端能够通告对端的最大窗口大小是65535,因为在TCP首部中相应的字段占16位。但目前要求有更大的窗口以获得尽可能大的吞吐量,这个新选项指定TCP首部中的通告窗口必须扩大(即左移)的位数(0~14),因此所提供的最大窗口接近1GB(65535*2^14)。

在一个TCP连接上使用窗口规模的前提是它的两个端系统必须都支持这个选项。SO_RCVBUF

[3] 时间戳选项

这个选项对于高速网络连接是必要的,它可以防止由“失而复现的分组”可能造成的数据损坏。

PS: “失而复现的分组”不是超时重传的分组,而是由暂时的路由原因造成的迷途的分组,当路由稳定后,它们又会正常到达目的地,其前提是它们在此前尚未被路由器丢弃。高速网络中32位的序列号短时间内就可能循环一轮重新使用,若不用时间戳选项,失而复现的分组所承载的分节可能与再次使用相同序列号的真正分节发生混淆。

(3) TCP连接终止——四次握手(通常)

TCP终止一个连接则需4个分节。

[1] 某个应用进程首先调用close,称该端执行“主动关闭”(active close)。该端的TCP于是发送一个FIN分节,表示数据发送完毕。

[2] 接收到这个FIN的对端执行 “被动关闭”(passive close),这个FINTCP确认

注意:FIN的接收也作为一个文件结束符(end-of-file)传递给接收端应用进程,放在已排队等候该应用进程接收的任何其他数据之后,因为,FIN的接收意味着接收端应用进程在相应连接上再无额外数据可接收。

[3] 一段时间后,接收到这个文件结束符的应用进程将调用close关闭它的套接字。这导致它的TCP也发送一个FIN

[4] 接收这个最终FIN的原发送端TCP(即执行主动关闭的那一端)确认这个FIN

既然每个方向都需要一个FIN和一个ACK,因此通常需要4个分节。

注意:

[1]“通常”是指,某些情况下,步骤1的FIN随数据一起发送,另外,步骤2和步骤3发送的分节都出自执行被动关闭那一端,有可能被合并成一个分节。

[2] 在步骤2与步骤3之间,从执行被动关闭一端到执行主动关闭一端流动数据是可能的,这称为“半关闭”(half-close),可参考shutdown。

[3] 当一个Unix进程无论自愿地(调用exit或从main函数返回)还是非自愿地(收到一个终止本进程的信号)终止时,所有打开的描述符都被关闭,这也导致仍然打开的任何TCP连接上也发出一个FIN。

[4] 无论是客户还是服务器,任何一端都可以执行主动关闭。通常情况是,客户执行主动关闭,但是某些协议,例如,HTTP/1.0却由服务器执行主动关闭。

TCP状态转换图

TCP涉及连接建立和连接终止的操作可以用状态转换图(state transitiondiagram)来说明。这些状态可使用netstat工具显示,方便监视状态的变化。

TCP为一个连接定义了11种状态,并且TCP规则规定如何基于当前状态及在该状态下所接收的分节从一个状态转换到另一个状态

11种状态,含义如下:

状态


描述


(1) CLOSED


关闭状态,没有连接活动或正在进行


(2) LISTEN


监听状态,服务器正在等待连接进入


(3) SYN_RCVD


收到一个连接请求,尚未确认


(4) SYN_SENT


已经发送连接请求(SYN),等待确认


(5) ESTABLISHED


连接建立,正常数据传输状态


(6) FIN_WAIT_1


(主动关闭)已经发送关闭请求(FIN),等待确认


(7) FIN_WAIT_2


(主动关闭)收到对方关闭确认(ACK),等待对方关闭请求(FIN)


(8) TIME_WAIT


完成双向关闭,等待所有分组死掉(目的是防止主动关闭端最后发出的ACK丢失,接收端处于LAST_ACK超时重发FIN,因此主动关闭端会进入TIME_WAIT状态,在压力测试时,这种状态会大量存在,进程所占用的端口号不能被释放,导致后来的连接建立失败)


(9) CLOSING


双方同时尝试关闭,等待对方确认


(10) CLOSE_WAIT


(被动关闭)收到对方关闭请求,已经确认


(11) LAST_ACK


(被动关闭)等待最后一个关闭确认(ACK),等待所有分组死掉

(1) 连接建立——三次握手

当某个进程在CLOSED状态下执行主动打开时,TCP将发送一个SYN,且新的状态是SYN_SENT,如果这个TCP接着接收到一个带ACK的SYN,它将发送一个ACK,且新的状态是ESTABLISHED,这个最终状态是绝大多数数据传送发生的状态。

(2) 连接终止——四次握手

自ESTABLISHED状态引出的两个“方向”处理连接的终止。如果某个进程在接收到一个FIN之前调用close(主动关闭),那就转换到FIN_WAIT_1状态;但如果某个进程在ESTABLISHED状态期间接收到一个FIN(被动关闭),那就转换到CLOSE_WAIT状态。

注意:

[1] 客户端和服务器端都可以执行主动关闭和被动关闭

[2] 关于同时打开(simultaneous open),发生在两端几乎同时发送SYN并且这两个SYN在网络中交错的情形下;同时关闭(simultaneousclose),发生在两端几乎同时发送FIN的情形下。(在TCPv1的第18章有这两种情况的讨论)

分组交换

讨论一个完整的TCP连接所发生的实际分组交换情况,包括连接建立、数据传送和连接终止3个阶段,并且表明每个端点所历经的TCP状态。

(1) 客户通告一个值为536的MSS(最大分节大小),表明该客户只实现了最小重组缓冲区大小;服务器通告一个值为1460的MSS(以太网上IPv4的典型值)。不同方向上MSS值可以不同。

(2)  连接建立后,客户就构造一个请求并发送给服务器。这里假设该请求适合于单个TCP分节,即请求的大小小于服务器通告的值为1460字节的MSS;服务器处理完该请求并发送一个应答,假设该应答也适合于单个分节,即小于536字节。

注意:

[1] 服务器对客户请求的确认可以是伴随其应答一起发送的,即P+ACK,这种做法称为“捎带”(piggybacking),它通常在服务器处理请求并产生应答的时间少于200ms时发生。如果服务器耗用更长时间,譬如说1s,那么将看到先是确认后是应答。(参考TCPv1第19章和第20章的TCP数据流机理)

(3) 最后是终止连接的4个分节。执行主动关闭的一端,将进入TIME_WAIT状态。

TIME_WAIT状态

(1) 2MSL

执行主动关闭的那端会经历TIME_WAIT状态,该端点停留在这个状态的持续时间是:最长分节生命期的两倍(maximumsegment lifetime, MSL),即,2MSL

任何TCP实现都必须为MSL选择一个值。RFC 1122[Braden 1989]的建议值是2分钟,不过源自Berkeley的实现传统上改用30秒这个值。这意味着:TIME_WAIT状态的持续时间在1分钟到4分钟之间

MSL是任何IP数据报能够在因特网中存活的最长时间,这个时间是有限的,因为每个数据报含有一个称为跳限(hop limit)的8位字段,可见IPv4的TTL字段,它的最大值为255。注意:尽管这是一个跳数限制而不是真正的时间限制,我们仍然假设:具有最大跳限(255

的分组在网络中存在的时间不可能超过MSL

(2) TIME_WAIT状态存在的理由

有两个理由:

[1] 可靠地实现TCP全双工连接的终止。

[2] 允许老的重复分节在网络中消失。

理由1的解释

假设最终的ACK丢失了,服务器将重新发送它的最终那个FIN,因此客户必须维护状态信息,以允许它重新发送最终那个ACK。要是客户不维护状态信息,它将响应以一个RST(另外一种类型的TCP分节),该分节将被服务器解释成一个错误。

如果TCP打算执行所有必要的工作以彻底终止某个连接上两个方向的数据流,即全双工关闭,那么它必须正确处理连接终止序列4个分节中任何一个分节丢失的情况。

为什么执行主动关闭的那一端是处于TIME_WAIT状态的那一端:因为可能不得不重传最终那个ACK的就是主动关闭端。

理由2的解释

TCP必须防止来自某个连接的老的重复分组在该连接已终止后再现,从而被误解成属于同一连接的某个新的化身。既然TIME_WAIT状态的持续时间是2MSL,这就足以让某个方向上的分组最多存活MSL秒即被丢弃,另一个方向上的应答最多存活MSL秒也被丢弃。通过实施这个规则,就能保证每成功建立一个TCP连接时,来自该连接先前化身的老的重复分组都已在网络中消逝了。

关于TMIE_WAIT状态的进一步说明

在内核协议层通过设置以下两个参数来解决TIME_WAIT问题:

(1) TIME_WAIT状态可以重用,这样即使TIME_WAIT占满了所有端口,也不会拒绝新的请求;

echo 1 > /proc/sys/net/ipv4/tcp_tw_reuse

(2) 让TIME_WAIT尽快回收

echo 1 >/proc/sys/net/ipv4/tcp_tw_recycle

PS: According to Linux documentation

tcp_tw_recycle - BOOLEAN 460        Enable fast recycling TIME-WAIT sockets. Default value is 0. 461        It should not be changed without advice/request of technical 462        experts. 463 464tcp_tw_reuse - BOOLEAN 465        Allow to reuse TIME-WAIT sockets for new connections when it is 466        safe from protocol viewpoint. Default value is 0. 467        It should not be changed without advice/request of technical 468        experts.

As described here, The TCP_TW_RECYCLE could cause some problems when using load balancers...

好处:

其实只修改tcp_tw_recycle就可以解决问题,TIME_WAIT重用TCP协议本身是不建议打开的。tcp_tw_recycle打开后,能在很短的时间能将TIME_WAIT的端口回收,但是具体时间并未找到相应的资料,测试观察在1s左右。

问题:

打开加速回收或允许重用,也存在一定的问题。因为,TIME_WAIT状态需要等待2MSL的目的之一就是要保证老的重复分节在网络中死掉,而如果快速回收的话,例如,发送端在发出最后一个ACK后立即被回收,而此ACK丢失,接收端超时重发FIN,而由于快速回收,恰好此时发送端使用刚才的端口建立起新的连接,那新的连接将收到一个异常的FIN,从而可能引发新的连接被异常被动关闭。

TMIE_WAIT的解决方法

短连接最大的缺点是将占用大量的系统资源,例如:本地端口、socket句柄。导致这个问题的原因其实很简单:tcp协议层并没有长短连接的概念,因此不管长连接还是短连接,连接建立->数据传输->连接关闭的流程和处理都是一样的。
正常的TCP客户端连接在关闭后,会进入一个TIME_WAIT的状态,持续的时间一般在1~4分钟,对于连接数不高的场景,1~4分钟其实并不长,对系统也不会有什么影响,但如果短时间内(例如1s内)进行大量的短连接,则可能出现这样一种情况:客户端所在的操作系统的socket端口和句柄被用尽,系统无法再发起新的连接!

举例来说:假设每秒建立了1000个短连接(Web场景下是很常见的,例如每个请求都去访问memcached),假设TIME_WAIT的时间是1分钟,则1分钟内需要建立6W个短连接,由于TIME_WAIT时间是1分钟,这些短连接1分钟内都处于TIME_WAIT状态,都不会释放,而Linux默认的本地端口范围配置是:net.ipv4.ip_local_port_range = 32768    61000

不到3W,因此这种情况下新的请求由于没有本地端口就不能建立了。

可以通过如下方式来解决这个问题
1)可以改为长连接,但代价较大,长连接太多会导致服务器性能问题,而且PHP等脚本语言,需要通过proxy之类的软件才能实现长连接;
2)修改ipv4.ip_local_port_range,增大可用端口范围,但只能缓解问题,不能根本解决问题;
3)客户端程序中设置socket的SO_LINGER选项;
4)客户端机器打开tcp_tw_recycle和tcp_timestamps选项;
5)客户端机器打开tcp_tw_reuse和tcp_timestamps选项;
6)客户端机器设置tcp_max_tw_buckets为一个很小的值;

附相关流程图片

图1   三次握手建立连接

图2   四次握手关闭连接

图3   TCP状态转换图

图4   TCP连接的分组交换

时间: 2024-10-14 14:46:16

udp/tcp协议及三次四次握手的相关文章

TCP协议的三次握手+四次断开

TCP协议的三次握手 1.TCP/IP协议概述 TCP/IP协议(Transmission Control Protocol/Internet Protocol)叫做传输控制/网际协议,又叫网络通讯协议,这个协议是Internet国际互联网络的基础.TCP/IP是网络中使用的基本的通信协议.虽然从名字上看TCP/IP包括两个协议,传输控制协议(TCP)和网际协议(IP),但TCP/IP实际上是一组协议,它包括上百个各种功能的协议,如:远程登录.文件传输和电子邮件等,而TCP协议和IP协议是保证数

TCP协议的三次握手与四次挥手过程图解

建立TCP需要三次握手才能建立,而断开连接则需要四次握手.整个过程如下图所示: 先来看看如何建立连接的. 首先Client端发送连接请求报文,Server段接受连接后回复ACK报文,并为这次连接分配资源.Client端接收到ACK报文后也向Server段发生ACK报文,并分配资源,这样TCP连接就建立了. 那如何断开连接呢?简单的过程如下: [注意]中断连接端可以是Client端,也可以是Server端. 假设Client端发起中断连接请求,也就是发送FIN报文.Server端接到FIN报文后,

通俗大白话来理解TCP协议的三次握手和四次分手

通俗理解: 但是为什么一定要进行三次握手来保证连接是双工的呢,一次不行么?两次不行么?我们举一个现实生活中两个人进行语言沟通的例子来模拟三次握手. 引用网上的一些通俗易懂的例子,虽然不太正确,后面会指出,但是不妨碍我们理解,大体就是这么个理解法. 第一次对话: 老婆让甲出去打酱油,半路碰到一个朋友乙,甲问了一句:哥们你吃饭了么? 结果乙带着耳机听歌呢,根本没听到,没反应.甲心里想:跟你说话也没个音,不跟你说了,沟通失败.说明乙接受不到甲传过来的信息的情况下沟通肯定是失败的. 如果乙听到了甲说的话

传输层协议介绍、重要的TCP三次/四次握手(理论部分,敲黑板!)

本次我和小伙伴分享的是网络七层中的传输层,我将会分成以下几步为大家进行分解说明:1.TCP协议介绍2.TCP报文格式3.TCP三次握手4.TCP四次握手5.UDP协议介绍6.常见协议及其端口 一.TCP和UDP协议1.TCP是面向连接的.可靠的进程到进程通信的协议2.TCP提供全双工服务,即数据可在同一时间双向传输3.TCP报文段(不超过1500字节,1.5kb) TCP将若干个字节构成一个分组,叫报文段(Segment) TCP报文封装在IP数据报中TCP报文段:1.源端口号(16)2.目标端

TCP协议的三次握手和四次挥手

暂时需要的信息有: ACK : TCP协议规定,只有ACK=1时有效,也规定连接建立后所有发送的报文的ACK必须为1 SYN(SYNchronization) : 在连接建立时用来同步序号.当SYN=1而ACK=0时,表明这是一个连接请求报文.对方若同意建立连接,则应在响应报文中使SYN=1和ACK=1. 因此,  SYN置1就表示这是一个连接请求或连接接受报文. FIN (finis)即完,终结的意思, 用来释放一个连接.当 FIN = 1 时,表明此报文段的发送方的数据已经发送完毕,并要求释

网络编程UDP/TCP协议

一.网络编程三要素 IP:网络中设备的标识,不易记忆,可用主机名 端口号:用于标识进程的逻辑地址,不同进程的标识 传输协议:通讯的规则常见协议:TCP,UDP UDP 把数据打成一个数据包 , 不需要建立连接 数据包的大小有限制不能超过64k 因为无连接,所以属于不可靠协议(可能丢失数据) 因为无连接 ,所以效率高 TCP 需要建立连接,形成连接通道 数据可以使用连接通道直接进行传输,无大小限制 因为有链接,所以属于可靠协议 因为有链接,所以效率低 二.IP以及端口号 1.InetAddress

c# UDP/TCP协议简单实现(简单聊天工具)

长时间没有摸这两个协议,写个代码温习下 下面是界面 [服务器界面] [登陆界面] [好友列表界面(我登陆了2个)] [聊天界面] 下面大致讲解下用到的内容 1.用户登陆于服务器通信用到的tcp协议,服务器接收到用户登陆信息(包括ip,端口,用户名等)后,返回已经登陆的用户列表信息(包括ip,端口,用户名等)给这个用户,同时服务器使用Udp协议向已经登陆的用户发送最新用户列表(包括ip,端口,用户名等)用于更新用户列表 2.用户登陆成功后展示好友列表,并启动udp协议的监听(叫监听似乎不太合适,暂

TCP协议的三次握手

TCP协议是面向连接的通信协议,即在传输数据前先在发送端和接收端建立逻辑连接,然后再传输数据,它提供了两台计算机之间可靠无差错的数据传输. l  IP地址:用来唯一表示我们自己的电脑的,是一个网络标示 l  端口号: 用来区别当前电脑中的应用程序的 l  UDP: 传送速度快,但是容易丢数据,如视频聊天,语音聊天 l  TCP: 传送稳定,不会丢失数据,如文件的上传.下载 l  UDP程序交互的流程 原文地址:https://www.cnblogs.com/ivan5277/p/10120566

深入理解TCP协议的三次握手,分析源码并跟踪握手过程

1.TCP三次握手建立连接 在TCP中,面向连接的传输需要经过三个阶段:连接建立.数据传输和连接终止. 三次握手建立连接 在我们的例子中,一个称为客户的应用程序希望使用TCP作为运输层协议来和另一个称为服务器的应用程序建立连接. 这个过程从服务器开始.服务器程序告诉它的TCP自己已准备好接受连接.这个请求称为被动打开请求.虽然服务器的TCP已准备好接受来自世界上任何一个机器的连接,但是它自己并不能完成这个连接. 客户程序发出的请求称为主动打开.打算与某个开放的服务器进行连接的客户告诉它的TCP,