「客户端」学习网络编程,不了解TCP协议?难怪面试被刷下去,还不来学习!( 四 )

由于 UDP 面向无连接 , 它可以随时发送数据 , 再加上UDP本身的处理既简单又高效 , 因此经常用于:

  • 包总量较少的通信 , 如 DNS 、SNMP 等
  • 视频、音频等多媒体通信
  • 广播通信
为什么 UDP 头部没有「首部长度」字段 , 而 TCP 头部有「首部长度」字段呢?
原因是 TCP 有可变长的「选项」字段 , 而 UDP 头部长度则是不会变化的 , 无需多一个字段去记录 UDP 的首部长度 。
为什么 UDP 头部有「包长度」字段 , 而 TCP 头部则没有「包长度」字段呢?
先说说 TCP 是如何计算负载数据长度:
其中 IP 总长度 和 IP 首部长度 , 在 IP 首部格式是已知的 。 TCP 首部长度 , 则是在 TCP 首部格式已知的 , 所以就可以求得 TCP 数据的长度 。
大家这时就奇怪了问:“ UDP 也是基于 IP 层的呀 , 那 UDP 的数据长度也可以通过这个公式计算呀?为何还要有「包长度」呢?”
这么一问 , 确实感觉 UDP 「包长度」是冗余的 。
因为为了网络设备硬件设计和处理方便 , 首部长度需要是 4字节的整数倍 。
如果去掉 UDP 「包长度」字段 , 那 UDP 首部长度就不是 4 字节的整数倍了 , 所以小林觉得这可能是为了补全 UDP 首部长度是 4 字节的整数倍 , 才补充了「包长度」字段 。
02 TCP 连接建立TCP 三次握手过程和状态变迁
TCP 是面向连接的协议 , 所以使用 TCP 前必须先建立连接 , 而建立连接是通过三次握手而进行的 。
TCP 三次握手

  • 一开始 , 客户端和服务端都处于 CLOSED 状态 。 先是服务端主动监听某个端口 , 处于 LISTEN 状态

第一个报文—— SYN 报文

  • 客户端会随机初始化序号(client_isn) , 将此序号置于 TCP 首部的「序号」字段中 , 同时把 SYN 标志位置为 1, 表示 SYN 报文 。 接着把第一个 SYN 报文发送给服务端 , 表示向服务端发起连接 , 该报文不包含应用层数据 , 之后客户端处于 SYN-SENT 状态 。

第二个报文 —— SYN + ACK 报文

  • 服务端收到客户端的 SYN 报文后 , 首先服务端也随机初始化自己的序号(server_isn) , 将此序号填入 TCP 首部的「序号」字段中 , 其次把 TCP 首部的「确认应答号」字段填入 client_isn + 1 接着把 SYN 和 ACK 标志位置为 1 。 最后把该报文发给客户端 , 该报文也不包含应用层数据 , 之后服务端处于 SYN-RCVD 状态 。

第三个报文 —— ACK 报文

  • 客户端收到服务端报文后 , 还要向服务端回应最后一个应答报文 , 首先该应答报文 TCP 首部 ACK 标志位置为 1, 其次「确认应答号」字段填入 server_isn + 1, 最后把报文发送给服务端 , 这次报文可以携带客户到服务器的数据 , 之后客户端处于 ESTABLISHED 状态 。
  • 服务器收到客户端的应答报文后 , 也进入 ESTABLISHED 状态 。
从上面的过程可以发现第三次握手是可以携带数据的 , 前两次握手是不可以携带数据的 , 这也是面试常问的题 。
一旦完成三次握手 , 双方都处于 ESTABLISHED 状态 , 此致连接就已建立完成 , 客户端和服务端就可以相互发送数据了 。
如何在 Linux 系统中查看 TCP 状态?
TCP 的连接状态查看 , 在 Linux 可以通过 


推荐阅读