网络编程--TCP/IP协议(二)

目录

  • 前言
  • 一丶TCP协议格式
    • 端口号
    • 序列号
    • 确认号
    • 首部长度
    • 保留字段
    • 标志位字段
    • 窗口大小
    • 检验位
    • 紧急指针
    • 可选项字段
  • 二丶TCP协议的特性
    • <1>TCP协议的特点
    • <2>可靠传输机制
      • 1>确认应答机制
      • 2>超时重传机制
      • 3>连接管理机制
        • TCP三次握手
        • TCP四次挥手
      • 4>流量控制
      • 5>拥塞控制
    • <3>效率传输机制
      • 1>滑动窗口
      • 2>延迟应答
      • 3>捎带应答
    • <4>粘包问题
  • 三丶UDP协议
    • <1>UDP协议的格式
    • <2>关于UDP和TCP协议的区别

前言

这一篇博客。就是专门用来讲解TCP协议对应的知识。

一丶TCP协议格式

TCP协议是位于传输层的协议,传输层的功能是什么呢?是确保数据能安全稳定的从客户端传输到服务端。那在传输层传输的数据叫什么呢?叫段。
由此我们的TCP协议应运而生。TCP,全称Transmission Control Protocol,传输控制协议。就像名字一样,他就是专门对数据的传输进行一个详细的控制。

TCP协议的格式如下:
网络编程--TCP/IP协议(二)_第1张图片
TCP协议是二进制的传输协议,而HTTP是超文本传输协议(还是文本格式)。

端口号

源端口号:源主机对应应用程序的进程,16位
目的端口号:目的主机对应应用程序的进程,16位

序列号

TCP序列号:占32位,TCP对数据的每个字节都进行了编号,数据第一个字节的编号就是数据报的序列号,每个字节都有自己独一无二的编号,故序列号有唯一性。
序列号的作用:接收端为了区别重复的报文段(报文段也叫帧),那么这个时候就需要TCP协议就需要能够识别出那些是重复的的,并且把重复的丢掉,这个时候就需要使用序列号来实现去重的功能。

确认号

TCP确认号:占 32 位。它表示接收方期望收到发送方下一个报文段的第一个字节数据的编号。其值是接收数据报时序列号的连续最大下标+1.

首部长度

TCP首部长度:数据偏移是指数据段中的数据部分起始处距离TCP数据段起始部分的字节偏移量,占4个字节。这里的“数据偏移”也是在确认TCP数据段头部分的长度,告诉接收端的引用程序,数据从何处开始。

保留字段

保留字段:为TCP将来的发展预留空间,开始必须全部是0

标志位字段

名称 说明
URG 表示本报文段中发送的数据是否包含紧急数据:URG=1 时表示有紧急数据。当 URG=1 时,后面的紧急指针字段才有效
ACK 表示前面的确认号字段是否有效:ACK=1 时表示有效;只有当 ACK=1 时,前面的确认号字段才有效;TCP 规定,连接建立后,ACK 必须为 1
PSH 告诉对方收到该报文段后是否立即把数据推送给上层。如果值为 1,表示应当立即把数据提交给上层,而不是缓存起来
RST 表示是否重置连接:若 RST=1,说明 TCP 连接出现了严重错误(如主机崩溃),必须释放连接,然后再重新建立连接
SYN 在建立连接时使用,用来同步序号:当 SYN=1,ACK=0 时,表示这是一个请求建立连接的报文段;当 SYN=1,ACK=1 时,表示对方同意建立连接;ACK=1 时,说明这是一个请求建立连接或同意建立连接的报文;只有在前两次握手中 SYN 才为 1
FIN 标记数据是否发送完毕:若 FIN=1,表示数据已经发送完成,可以释放连接

窗口大小

TCP窗口:表示从Ack Number开始还可以接收多少字节的数据量,也表示当前接收端的接收窗口还有多少剩余空间,该字段可以用于TCP的流量控制。

检验位

TCP检验位:用于确认传输的数据是否有损坏,发送端基于数据内容校验数据内容生成一个数值,接收端根据接收的数据校验生成一个值。两个值必须一样,才能证明数据是有效的。如果两个值不同,就丢掉这个数据包。这里的校验位是根据伪头部 + TCP头部 + TCP数据三部分组成。

TCP伪头部:包含TCP1+TCP+选项长度+数据长度4部分组成,如果没有选项和数据刚好12+20=32个字节,tcp发送时需要对12+20+选项长度+数据长度这些字节进行16位校验,伪头部只是在校验时用到,数据收发不用伪头部,因为这只是IP报头的一部分而已

紧急指针

紧急指针字段:当且仅当前面的URG控制位为1的时候才有意义。他指出本数据段中为紧急数据的字节数,占16位。当紧急数据处理完之后,TCP就会告诉应用程序恢复到正常操作。所以即便是窗口大小为0,也是可以发送紧急数据的,因为紧急数据无需缓存。

可选项字段

选项:长度不定,但是长度必须是32bits的整数倍,选项中的内容不确定,因此就必须使用首部长度来区分选项具体的长度。

二丶TCP协议的特性

<1>TCP协议的特点

特点 含义
有连接 应用程序每次使用TCP协议之前,都要建立TCP连接。
可靠传输 网络数据的传输过程,是一跳一跳的经过所有途中的网络设备。就可能发生数据丢失。TCP提供可靠交付的服务。通过 TCP 连接传送的数据,无差错、不丢失、不重复,并且按序到达。
面向字节流 在连接没有关闭的时候,可以多次的接收和发送数据
有接收缓冲区和发送缓冲区 接收程序的时候,先由接收缓存区接收数据,然后再交给应用程序。发送数据的时候,先写到缓存区再发送。后面我们讲的确认应答机制和超时重传机制都会用到这两个缓存区。
大小不限 因为可以多次收发数据,且每次收发都可以很大,所以对于传输数据大小不限。

<2>可靠传输机制

1>确认应答机制

当接收端接收到一条报文的时候,就要向发送端发送一条确认ACK:我(接收端)已经成功的接收到了消息,我希望收到你(发送端)的下一条报文的序列号。

网络编程--TCP/IP协议(二)_第2张图片
那确认应答机制存在的意义是什么呢?

之前我们说了,TCP的特性有一个特性叫做可靠传输,TCP连接建立之后,发送的每一个数据都有可能丢失,所以这个时候就需要确认应答机制,以此来确保数据的完整性。

那么确认应答机制的作用是什么呢?

1.保证接收端收到了数据
2.可以知道收到的是那一条数据

那确认应答机制是怎么实现的呢?

我们TCP协议格式报头中里面有一个“32位序列号”字段,数据报文里会携带一个数据,这个数据我们假定是1000个字节(参照上图),TCP会对每个字节进行序列号排序,以此来保证报文的顺序性。然后注意了,初始的序列号是随机生成的。
接收端接收到数据报文之后,会读取数据。然后生成返回报文,序列号是接收端随机生成的一个值,而确认号是接收到的报文的连续序号的最大值+1,也就是1001。这里表示的是,序列号在1001之前的数据报我已经全部接收了,请给我发送序列号在1001之后的数据。同时这里还会把标志位字段ACK设置为1。所以总体大致总结一下:返回ACK标志位+确认号1001+随机生成的序列号的值。
这就是一次完整的确认应答机制。

2>超时重传机制

问题一:什么是超时重传机制?

在发送端发送数据报的时候,会对这个数据包设置一次计时器,如果说计时器记录的时间到了,但是还没有收到来自接收端的响应,那么就会重新发一个相同的报文到接收端。
PS:超时重传机制是系统在实现TCP协议栈的时候实现的,而TCP是基于内核实现,所以超时重传机制是基于内核实现。

有时候可能网络延迟什么的,或者说拥堵什么问题的,导致数据无法导致接收端。这个时候发送端就会重新发送数据报,如果接收端收到了重复报文,这个时候就是我们的序列号起作用的时候了,根据序列号去重。

问题二:超时的时间怎么设置?

最理想的情况下,找到一个最小的时间,保证“确认应答一定能在这个时间内
返回”,但是这个时间的长短,会随着网络环境的不同,会有差异,如果超时时间
设置的太长,会影响整体的重传效率,但是如果设置的太短,有可能会频繁的发送
重复的包。TCP为了保证无论在任何环境下都能比较高性能的通信,会动态的计算这个
最大超时时间,所以超时时间不是确定的,是TCP动态的计算的

这个超时时间是以500ms为一个单位控制,每次判定超时重发的超时时间是500ms的整数倍,也就是每次在原先的基础上乘2,第二次是 1000ms,第三次是2000ms…
累积到一定的次数,TCP会认为网络或者接收端主机出现了异常,就会强制关闭连接。

3>连接管理机制

TCP三次握手

什么是三次握手?

所谓三次握手,指的是在TCP连接的过程中,发送端和接收端一共发送了三个包(第二次发送的时候是二包合一)。三次握手的主要目的就是确认一下,我发送端和你接收端的接收能力和发送能力都是正常的,同时指定自己的初始化序列号为后面的可靠性传输做准备。实际上也就是发送端连接接收端的指定的进程,建立TCP连接,并且同步双方的序列号和确认号,交换TCP窗口大小的信息。
那么现在正式开始我们的三次握手环节的讲解。先上图
网络编程--TCP/IP协议(二)_第3张图片
初始我们的客户端是Closed状态,服务端是Listen状态。

第一次握手

第一次握手,客户端调用connect()方法,发送SYN报文。并且设置好客户端的初始序列号ISN,这个时候客户端处于SYN_SENT状态,也就是阻塞等待服务器响应。报文中标志位字段SYN=1,ACK=0,序列号位设置为x(也就是ISN的值)。这里提一下,SYN=1这个报文是不可以携带数据的,但是要消耗一个序号用来进行应答。同时因为不能携带数据,所以初始序列号ISN就是连续最大的序列号。

第二次握手

第二次握手,此时因为服务端是Listen状态,也就是监听状态。当监听到连接请求(收到发送端发来的报文),就会把该连接放入内核等待队列中。然后以自己的SYN报文作为应答,并且指定自己的序列号ISN(这里是接收端的序列号),并且把发送端的序列号+1作为自己的ack(确认号)的值(因为没有携带数据,所以序列号就是连续最大的序列号),返回给客户端(也可以叫发送端),表示自己接受到了你的请求,这个时候服务端(也可以叫接收端)进入SYN_REVD的状态。返回的报文中,序列号是服务端自己生成的ISN,确认号是发送端的序列号+1,标志位字段SYN = 1,SYN = 1。为了方便后续讲解,就把这里的确认号叫做y吧,y = x+1

PS:这里特意说明一下,这里其实应该是两个请求报文的,SYN(请求连接) + ACK(确认应答),但是因为TCP的效率机制–捎带应答,所以就合二为一了。

第三次握手

第三次握手,是客户端在收到SYN数据报文的时候,会发送一个ACK报文,表示已经收到了服务端的连接请求。这个时候ACK报文的的标志位字段ACK=1,同时会把第二次握手发送的报文中的序列号+1作为序列号。但是这个时候注意了!!!!!
第三次握手的时候就可以携带数据了,这意味着什么,意味着我们如果要携带数据,那么就可以把序列号设置值为x+1(因为我初始就是x呀,这是第二个报文啦,我第一个报文虽然没有携带数据但是消耗了一个序列号了)
这里注意了:调用Connect()之后,发送端就会进入ESTABLISHED状态开始读写数据。当接收端收到发送端发来的ACK包之后也会进入ESTABLISHED状态开始读写数据。

关于三次握手中的一些问题

三 次 握 手 可 不 可 以 只 改 成 两 次 \color{red}{三次握手可不可以只改成两次}

:不行,如果改成了两次,你无法知道发送端的接收能力是否正常。TCP三次握手目的之一就是为了确定双方接收和发送数据报的能力是否正常。
第一次握手:客户端发,服务端收
得到结果:客户端可以发送,服务端可以接收
第二次握手:服务端发,客户端收
得到结果:服务端可以发送,客户端可以接收。但是问题在这里,我客户端是知道我们双方的接收和发送数据报的能力是正常的,但是你服务端是不知道的。
第三次握手:客户端发,服务端收
得到结果:客户端发,服务端收。这个时候我服务端收到了你的ACK包,我就知道你的接收能力是正常的了。

什 么 是 半 连 接 队 列 \color{red}{什么是半连接队列}

:在服务单首次监听到客户端发来的SYN数据报的时候,就会处于SYN_REVD状态,这个时候双方还没有完全建立连接。服务器会把这个状态下的连接请求放在一个队列当中,这就是我们的半连接队列,也可以叫做内核等待序列。
当然也有一个全连接队列,就是在完成三次握手之后,请求就会放在全连接队列当中。这个时候如果队满了就会出现丢包现象,这个我们后面再讲。

I S N 是 固 定 的 吗 ? \color{red}{ISN是固定的吗?} ISN

:ISN,也叫序列号,由客户端随机生成,标识数据的第一个字节序号。ISN随着时间而变化,每个连接都有着不同的ISN,ISN每4ms加一,这样做的好处就是可以防止在网络中延迟的分组在以后又被传送,而导致连接的某一方对他做出错误的解释。而且如果ISN是静态的话,也很容易让攻击者猜出后续的确认号。

三 次 握 手 过 程 中 可 以 携 带 数 据 吗 ? \color{red}{三次握手过程中可以携带数据吗?}

:前面两次是不行的,因为这个时候还没有完全建立连接,如果这个时候有人攻击服务器,他可能会往你的数据报中放入大量数据,毕竟攻击者不会管你服务器和客户端的接收能力和处理如何,是否能正常运转。这会导致服务端花费大量的空间和时间来接收这些报文。
但是第三次是可以的了,这个时候双方都进入了ESTABLISHED状态,连接起了正常的链接,所以这个时候就可以携带数据了。

TCP四次挥手

还是老规矩,先上图
网络编程--TCP/IP协议(二)_第4张图片
这里可以发现,如果单单就发送数据包来说,三次握手和四次挥手的区别就是第二次握手的时候,挥手这里是把AKC报和FIN报分开发送了,但是握手是合在一起发送的。为什么会有这种情况出现呢?这是因为TCP的半关闭(half-close)造成的。所谓半关闭,就是连接的一端在结束它的发送之后还能接收来自另外一端数据的能力。
在正式讲解四次挥手之前,有一点需要注意,就是我们的发送端和接收端都是可以发起关闭连接的请求。这里我们假设是接收端发起的关闭连接请求。

第一次挥手

首先,发送端和接收端此时的状态都是established。然后发送端此时调用closed()方法,并且向接收端发送结束报文FIN,此时会在报文中指定一个序列号seq = u,指定标志位字段FIN = 1,并且停止发送数据,主动关闭TCP连接。发送完了之后就会进入FIN_WAIT_1状态,等待服务端的确认。

第二次挥手

此时服务端收到了客户端发来的FIN数据报,就会回发一个ACK数据报,把第一次握手中的序列号u加上1作为确认号,把标志位字段ACK设置为1同时随机生成一个序列号v之后把这个响应报文发回给客户端。注意了,这里的这个响应报文是TCP自带的功能,也就是说是TCP协议栈自带的功能,不需要我们手动的设置程序去回复。状态转变的话,这里接收到了客户端的请求结束连接报文之后就会进入CLOSE_WAIT状态,表明已经接收到了客户端的报文。

这个时候的TCP就是处于一种半关闭状态,而当客户端收到服务端发来的ACK响应之后就会进入FIN_WAIT_2状态(终止等待状态2),等待服务端发来的释放连接请求。

第三次挥手

这个时候服务端想断开连接了,就和第一次挥手的客户端一样,此时给客户端发送一个FIN报文,发送完之后,服务端就处于LAST_ACK状态。这个时候服务端没有要向客户端发送的数据了,发送的报文段中序列号是自己随机生成的w确认号是第一次挥手报文中的序列号+1,也就是u+1标志位字段FIN=1,ACK=1。然后就会等待服务端的响应

第四次挥手

此时的客户端收到了服务端发来的FIN数据报,就会回一个ACK数据报,并且进入TIME_WAIT状态,等过一段时间之后,才会进入CLOSED状态。而服务端一旦收到来自客户端的ACK报文,就会立马进入CLOSED状态。
此时的客户端发的ACK数据报会把第三次握手发来的FIN数据报的序列号作为确认号,也就是w+1,此刻ACK数据报的序列号是第三次握手中的确认号,也就是u+1,标志位字段ACK = 1。
当服务端收到这个ACK数据报之后,就会进入CLOSED状态。

关于四次挥手中的一些问题

挥 手 为 什 么 是 四 次 ? \color{red}{挥手为什么是四次?}

上面说了,四次挥手相比起三次握手有一个很大的的特点就是在第二次挥手的时候把FIN和ACK分开发了,但是三次握手的时候第二次握手把ACK和SYN是分开发的。所以为了探究这个问题,我们就要明白每个数据报的含义。三次握手能在一起发的原因是因为ACK用来应答,而SYN是用来同步的。但是关闭连接的时候,当我收到客户端的FIN请求数据报时候,这个时候服务端正在处理数据或者说正在发送一些数据报,服务端就只能先进行ACK应答:OK,你的请求我收到了。然后等到自己的数据处理完后,再给客户端发送一个FIN数据报:好了,我现在准备好了,我来和你断开连接了。

2 M S L 等 待 状 态 \color{red}{2MSL等待状态} 2MSL

:这个等待状态是什么?就是客户端的TIME_WAIT状态,也就是在收到服务端发来的FIN数据报之后的状态,他为什么要叫2MSL等待状态呢?
:(1)那先从头开始,什么叫做MSL?MSL是说TCP实现时候要选择一个报文的最大生存时间MSL,它是任何一个报文被彻底废弃前在网络内的最大停留时间。为什么会有这个最大停留时间?因为TCP是基于IP数据报在网络内传输,而IP协议有一个限制其生存时间的TTL字段。
(2)那么设置2MSL等待状态意义在哪里呢?当客户端在响应完第二个FIN数据报之后就必须在TIME_WAIT状态等待2MSL,防止响应的ACK数据报丢失。如果丢失了的话,服务端没有在规定的时间内收到ACK应答报就会再次发送FIN数据报,然后客户端就会再次发送ACK应答报。如果没有设置这个2MSL,那么当客户端对第二次FIN响应的ACK包丢失之后,这个时候客户端关闭了,服务端就会一直处于无法关闭的状态。

4>流量控制

接收端处理数据的能力是有现的,如果一致发,而且发送数据报的速度很快,就会导致接收端的缓存区被沾满,然后后续的数据报就有很大的丢包风险。
所以TCP就会依据接收端的处理能力,来限制发送端的发送速度,这个机制就是流量控制。

1.接收端将自己可以接收的缓冲区大小放入 TCP 首部中的 “窗口大小” 字段,通过ACK端通知发送端;
2.窗口大小字段越大,说明网络的吞吐量越高;
3.接收端一旦发现自己的缓冲区快满了,就会将窗口大小设置成一个更小的值通知给发送端;
4.发送端接受到这个窗口之后,就会减慢自己的发送速度;
5.如果接收端缓冲区满了,就会将窗口置为0;这时发送方不再发送数据,但是需要定期发送一个窗口探测数据段,使接收端把窗口大小告诉发送端

问题来了,就是我们的窗口大小是16个比特位,最大接收是65535字节,那么窗口最大就是65535?不是的,我们的TCP首部还有一个窗口扩大因子M,实际上窗口大小应该是窗口字段的值往左移动M位。滑动窗口的大小,就是发送数据的大小,是以流量窗口大小为其中一个依据。

5>拥塞控制

虽然TCP已经有了滑动窗口机制,但是如果刚开始一次性发送大量数据还是会出现问题。因为网络上很多的计算机,可能当前的网络状态就是很拥塞的了,再发数据不是处理不过来了?这个时候就需要用到我们的拥塞控制机制

也就是“慢启动”机制,刚开始我先发送一点点数据探探路,然后再慢慢增多,增长的速度是2^n,这里引入一个概念叫做“慢启动阈值”,如果超过这个阈值那么就不能再是指数增长,而是线性增长。当如果出现了少量的丢包状况,那超时重传机制就可以处理,但是如果出现了大量丢包,那就是网络拥堵。这个时候我们就需要从头开始,也就是重新“慢启动”,但是这个时候的阈值就是造成网络堵塞时候拥塞窗口的一半。

<3>效率传输机制

1>滑动窗口

首先来看一下,如果说没有滑动窗口,那么接收端和发送端之间,是怎样收发数据的
网络编程--TCP/IP协议(二)_第5张图片
没错,就只能一个收,一个发,但是无疑,这样会很浪费时间。那既然一收一发的效率很低,那么我们就可以一次性发送多个,接收多个数据。
:那么什么是滑动窗口?

就是一次性收发大量数据

:那窗口大小怎么说?

滑动窗口大小就是无需等待就可以发送数据的最大值,我们的滑动窗口大小主要取决于两个因素:流量窗口大小(流量控制),拥塞窗口大小(拥塞控制),取这两个的较小的哪一个。

问: 那么窗口怎么滑动?

每收到一个ACK,那么就把窗口滑到ACK的确认号对应的位置。

问: 如果中途发生了丢包问题怎么处理?

答:分成以下两种情况:

网络编程--TCP/IP协议(二)_第6张图片

<1>如果是返回数据的途中丢包了,那么这种情况下丢包其实不要紧,因为可以根据后续返回的ACK来确定当前序号之前的数据我都收到了。

网络编程--TCP/IP协议(二)_第7张图片

<2>如果是客户端发送数据的途中丢失了数据报,这种情况下,服务端因为没有收到1001~2000的数据包,所以后续数据包的确认号都是1001。这种情况下当发送端连续接收到三个以上的响应报中确认号是1001的时候,就会重新发送1001 ~ 2000的这个数据报。这个接收端返回的ACK确认号就是7001了,因为之前2000 ~ 7000的这些之前就已经接收到了,只是被放到了接收端的缓冲区当中。

这种机制也叫“高速重发机制”,也叫快重传。

2>延迟应答

如果说当接收端主机接收到数据包后立刻进行ACK应答,这个时候窗口可能有点小。什么意思呢?

假设接收端缓冲区为1M。一次收到了500K的数据;如果立刻应答,返回的窗口就是500K;但实际上可能处理端处理的速度很快,10ms之内就把500K数据从缓冲区消费掉了;在这种情况下,接收端处理还远没有达到自己的极限,即使窗口再放大一些,也能处理过来;如果接收端稍微等一会再应答,比如等待200ms再应答,那么这个时候返回的窗口大小就是1M;

流量窗口越大,那么网络吞吐量就越大,传输效率就越高,在保证网络不堵塞的情况下,我们努力提高这个窗口大小就行了。
当然,延时是为了提高吞吐量,但是也不能无限延迟,要根据以下两个因素来设置延迟应答

数量限制:每隔N个包就应答一次;
时间限制:超过最大延迟时间就应答一次;

3>捎带应答

在延迟应答的基础上,我们发现,很多情况下,客户端服务器在应用层也是 “一发一收” 的。意味着客户端给服务器说了 “在吗老弟?”,服务器也会给客户端回一个 “在呢老哥。”;那么这个时候ACK就可以搭顺风车,和服务器回应的 “在呢老哥” 一起回给客户端。典型的例子就是三次握手中的二次握手。

<4>粘包问题

这个问题的话,我从哪里说起呢?

什 么 是 粘 包 问 题 ? \color{red}{什么是粘包问题?}

首先,粘包粘包,你首先要知道他是个“包”’,然后才知道他是咋粘的。那么就从包说起。这里的包指的是什么包?
其实仔细想一想,我们好像突然真的可以发现数据包还真找不到一个具体的概念,因为TCP/IP五层模型中每一层对于数据包都有自己的称呼

传输层叫做数据段
网络层叫做数据报
数据链路层叫做数据帧

所以可以发现这里的包其实只是一个抽象概念,所以粘包问题不仅仅是传输层才有的现象,它在数据链路层和传输层和网络层都是存在的。但是由于日常的网络开发都是在传输层,而UDP协议又有消息保护边界,所以粘包问题大都针对于TCP协议讨论。

然后,我们来说说“粘”,为什么会发生粘这个现象?关于这一点我想从TCP协议的定义往里面入手

TCP是一个面向连接过程的,可靠的流式传输协议

那么这是什么意思呢?

面向过程:指的就是两个应用程序之间要提前建立点对点的相互连接,这个连接的过程指的就是我们的“三次握手”
可靠的:这里指的就是我们TCP的可靠传输机制,确认应答机制+超时重传机制+连接管理机制+流量控制+拥塞控制
流式传输:TCP是二进制的传输协议,它是以字节流的方式进行传输。

那么流式传输最大的特点是什么呢?就是没有边界。

如果我们站在传输层来看,TCP就是一个一个报文过来的,按照序号排列在我们的缓存区中。但是如果说我们站在应用层来看,TCP就是一连串的字节数据。当应用层看到这一连串的字节数据的时候,就不知道从哪里开始,从哪里结束算是一个完整的应用层数据包。

怎 么 解 决 ? \color{red}{怎么解决?}

1.对于定长的包,保证每次都按照固定大小读取即可。
2.对于长度变化的包,可以在包头的位置,设置一个关于包的总长度的字段,从而就可以知道包的结束位置。
3.对于长度变化的包,在包和包之间使用明确的分隔符(应用层协议,由程序员自己决定,保证不影响正文即可)。

三丶UDP协议

<1>UDP协议的格式

网络编程--TCP/IP协议(二)_第8张图片

源端口号: 这个字段占据UDP报文的前16位,通常包含发送数据报的应用程序所使用的UDP端口。接收端的应用程序利用这个字段的值作为发送端响应的目的地址。这个字段是可选的,所以发送端的应用程序不一定会把自己的端口号写入该字段当中。如果不写入端口号,这个字段的值设置为0就好,这样的话接收端的应用程序就不能发送响应了。
目的端口号:接收端计算机上UDP软件使用的端口,占据16位。
UDP长度:占据16位,表示UDP数据报的长度,包含UDP报文头和UDP数据长度。UDP的报文头长度是8个字节,所以这个UDP长度最小为8
UDP检验和:用来校验数据在传输过程中数据是否有损坏。
数据:就是携带的数据。

<2>关于UDP和TCP协议的区别

回答这个问题,还是应该从TCP和UDP协议的特点来说。首先说一下UDP协议的特点

特点 含义
无连接 在使用UDP协议之前不需要建立稳定的连接
不可靠 没有可靠传输机制
面向数据报 一次性的发送所有数据,一次性的接收所有数据
有接收缓冲区,没有发送缓冲区 发送缓冲区:因为发送端不关心接收端是否接收到了信息,所以就不需要发送缓冲区来记录数据编号(超时重传机制才可以用到)。接收缓冲区:接收端此时还是可以接收到多组数据,接收端处理速度可能比发送端的发送速度要慢,所以就需要用接收缓冲区来保存数据
大小受限 最多64K

(PS:所以这个问题要结合UDP和TCP协议的特点来进行对比)

还要两个问题需要我们在这里提一下:

  1. UDP本身是无连接,不可靠,面向数据报的协议,如果要基于传输层UDP协议,来实现一个可靠传输,应该如何设计?
  2. UDP大小是受限的,如果要基于传输层UDP协议,传输超过64K的数据,应该如何设计?

首先我们要明白,UDP协议被指定后传输层只能使用UDP协议,所以为了解决上述问题,我们可以在应用层自定义协议来去实现上述功能,具体的话参考TCP协议的功能实现原理。

你可能感兴趣的:(网络编程,网络协议,tcp/ip)