传输控制协议(Transmission Control Protocol, TCP)和用户数据报协议(User Datagram Protocol, UDP)是典型的传输层协议。

传输层协议基于网络层协议提供的主机间通信服务, 为主机上的应用进程提供端对端的通信服务。

TCP和UDP协议使用端口号标记主机上的不同进程,端口号只拥有本地意义在不同主机上讨论端口号没有意义。

TCP协议

TCP协议是面向连接的传输协议,可以在不可靠的网络协议(如IP协议)上提供可靠的通信服务。

TCP连接以TCP套接字(TCP Socket)作为连接的两端, 每个socket包含四个字段: 本机IP, 本机端口, 对方IP, 对方端口。

TCP端口使用16位编码标记, 端口号范围0~65535. 其中0~1023是保留端口分配给常用应用协议使用:

HTTP FTP DNS SSH
80 20,21 53 22

在Linux操作系统中, 只有root用户才有权限将进程绑定到保留端口上。

上图给出了TCP报头的数据结构, 其中的保留位一律置零。标志位标识了该报文特殊的功能:

  • URG: 为1表示高优先级数据包,紧急指针字段有效

  • ACK: 为1表示确认号字段有效

  • PSH: 为1表示是带有PUSH标志的数据,指示接收方应该尽快将这个报文段交给应用层而不用等待缓冲区装满

  • RST: 为1表示出现严重差错。可能需要重现创建TCP连接。还可以用于拒绝非法的报文段和拒绝连接请求。

  • SYN: 为1表示这是连接请求或是连接接受请求,用于创建连接和使顺序号同步
  • FIN: 为1表示发送方没有数据要传输了,要求释放连接

标志位在TCP中的功能将在下文介绍TCP协议时给出详细说明。

面向连接服务

连接是指双方开始发送数据前首先进行协商并预分配缓冲区等资源, 连接建立期间采用确认和重传,超时等机制, 通信结束后发送消息断开连接。

下图直观的描述了TCP通信过程:

TCP协议采用三次握手机制建立连接:

  1. 第一次握手: TCP客户端首先向服务端发送同步报文SYN, 其中包含一个序列号x.客户端进入SYN_SEND状态,等待服务端的确认

  2. 第二次握手: TCP服务端对客户端SYN报文发送确认报文ACK, 其中包含序列号x+1以证实序列号已同步。服务端同时发送SYN报文, 其中包含服务端的序列号y。通常情况下SYN和ACK在同一个数据段中发送, 发送后服务端进入SYN_RECV状态。

  3. 第三次握手: 客户端收到SYN+ACK后向服务端发送ACK报文包含序列号y+1, 证实序列号已同步。客户端进入ESTABLISHED状态, 收到ACK后服务端也进入ESTABLISHED状态。实际上,客户端可以将数据和ACK:y+1放入同一个段中发送。

在客户端第一次发送SYN之后客户端开始倒计时, 若在倒计时结束前没有收到来自服务端的ACK则认为连接建立失败。

同样,若客户端没有及时响应服务端SYN则服务端也会认为连接建立失败。

采用三次握手而非两次握手的一个原因在于, 若来自客户端的SYN因为网络拥塞而未及时到达, 客户端会认为连接建立失败再次发送SYN试图连接。当这个被客户端认为已经丢失的SYN到达服务端时,服务端会认为客户端尝试建立一个新的连接。

若采用二次握手机制, 服务端将发送ACK并进入ESTABLISHED状态, 客户端因为没有尝试建立连接而忽略ACK。 服务端等待很长时间后才会因为超时切断连接, 在等待的过程中白白消耗了很多服务端资源。

在连接建立后, 客户端和服务端就可以进行双向通信。双方都可以主动发送信息, 一方在收到对方发送的数据段后必须发送ACK进行确认, 若确认报文未及时抵达则会触发重传机制或中断连接。

因为数据段在网络上传输时可能后发先至导致乱序, 连接建立时协商的序列号可以让接收方收到乱序数据后重新排序。

服务端和客户端使用各自的序列号而非共用序列号。若共用序列号, 则双方发送数据前均不知道是否存在对方已发送而己方未收到的数据段, 而这些未知数据段可能占用了共用的下一个序列号。

在连接建立后, 双方都可以主动中断连接,上图以客户端触发中断为例。TCP采用四次挥手机制断开连接:

  1. 第一次挥手: 主机A向主机B发送FIN报文, 并进入FIN_WAIT_1状态。这表示主机A没有数据要发送给主机B了.

  2. 第二次挥手: 主机B向主机A回复ACK报文, 表示收到FIN请求, 随后进入CLOSE_WAIT状态。主机A收到ACK后进入FIN_WAIT_2状态。此时主机B仍然可以向主机A发送数据。

  3. 第三次挥手: 主机B向主机A发送FIN报文, 随后进入LAST_ACK状态。

  4. 第四次挥手: 主机A向主机B回复ACK,然后进入TIME_WAIT状态。主机B收到ACK后断开连接。主机A进入TIME_WAIT状态后保持连接开启2MSL(Maximum Segment Lifetime)以等待仍然在网络传输的数据段。

与建立连接时相比断开连接时被动方可能仍有数据未发送,所以FIN报文不能与ACK报文一同发送故而需要四次挥手。

在建立连接时, 服务端的SYN可以和ACK一起发送, 所以只需要三次握手。

因为数据段在网络上传输时可能乱序, 所以主机A在发送最后一个ACK后仍然保持连接打开等待仍然在网络传输的数据。

流量控制

当发送方发送数据过快以至于可能导致接收方缓冲溢出时,就需要采用流量控制抑制发送。

TCP协议提供了滑动窗口机制提供流量控制功能,收到TCP数据段的一方可以在回复的ACK报文中设置允许接收的最大字节数, 这个最大字节数被称为接收窗口。

发送方每次发送数据就会使接收窗口缩小对应的字节数,当接收窗口为0时就会停止发送数据。接收方返回ACK报文时可以重设接收窗口大小,用以控制发送方发送数据的速率。

当接收方缓冲区已满时即可将接收窗口设为0, 阻止发送方继续发送数据。当接收窗口为0时, 发送方会定时发送数据段只有一个字节的窗口探测报文,接收方可以在ACK报文中重新打开接收窗口。

若接收窗口在连接最大生存期结束前仍未打开,则连接会超时断开。

拥塞控制

当对网络资源请求总和超出网络所能提供的限度则会出现拥塞(congestion)问题。当网络发生拥塞时数据丢失会导致重传增加进一步加剧拥塞, 此时必须进行拥塞控制减少网络资源需求使网络有机会恢复。

拥塞控制是全局性过程,涉及网络中的许多节点和主机。在面向连接的网络(如ATM或电路交换网)中,拥塞控制由网络层和数据链路层的路由器和交换机等设备完成。然而现在的网络大多数是无连接的, 这就要求端系统进行拥塞控制。

最初由V. Jacobson在1988年的论文中提出的TCP的拥塞控制由“慢启动(Slow start)”和“拥塞避免(Congestion avoidance)”组成。

后来TCP Reno版本中又针对性的加入了“快速重传(Fast retransmit)”、“快速恢复(Fast Recovery)”算法。再后来在TCP NewReno中又对“快速恢复”算法进行了改进。

近些年又出现了选择性应答( selective acknowledgement,SACK)算法,还有其他方面的大大小小的改进,成为网络研究的一个热点。

TCP拥塞控制的基本策略是发送端通过跟踪传输数据的丢失现象和往返时延的变化确定网络的传输能力,并以此来调整发送数据率。

发送方会维护一个拥塞窗口(cwnd)定义为可以发送的最大字节数,其值根据网络状态进行调整。发送方传输数据同时受到接收窗口和拥塞窗口的控制,不允许超过它们中最小的那个。

TCP的拥塞窗口由慢启动(Slow Start)和拥塞避免(Congestion Avoidance)两种策略控制:

  • 慢启动: 发送方首先以很小的数据量发送数据,若在超时之前收到确认报文则在下一次发送时加倍数据率。

  • 拥塞避免: 不同于慢启动时发送数据速率的成倍增长,采用每次增加一个最大报文长度MSS(Maximum Segment Size)的递增方式,直到检测到数据丢失。

一般情况下,发送方首先使用慢启动策略当数据率达到门限值ssthresh后采用拥塞避免策略。

为了保证数据可靠交付TCP采用了超时重传机制, 这个等待过程中发送方不会继续发送数据。快重传机制允许在超时之前检测到数据丢失并进行重传,从而提高了通信效率:

如果接收方接收到一个序列号错误的数据段,它会立即给发送方回复一个重复确认。如果发送机接收到三个重复确认,它会认为确认之后的数据段丢失了,并立即重传这些丢失的数据段。

在快重传之后采用快速恢复策略进行拥塞控制, 避免重新进行慢启动导致的通信速率下降。快速恢复的设计思想是"数据包守恒", 即当一个数据包离开网络后才能发送新的数据包。

快速恢复的具体流程如下:

1.当收到3个重复ACK时,把ssthresh设置为拥塞窗口的一半,把拥塞窗口设置为ssthresh的值加3。加3的原因是因为收到3个重复的ACK,表明有3个“老”的数据包离开了网络。

2.再收到重复的ACK时,拥塞窗口增加1,原因同上。

3.当收到新的数据包的ACK时,把拥塞窗口设置为第一步中的ssthresh的值。因为此时该恢复过程已经结束,可以回到恢复之前的状态,也即再次进入拥塞避免状态。

UDP协议

用户数据报协议(User Datagram Protocol, UDP)是无连接的不保证可靠交付的面向报文的协议。

UDP支持一对一或一对多的通信, 因此可以用于多播。

UDP无需建立连接,没有重传和拥塞控制其开销远小于TCP协议。因为UDP开销较小可以用于传输很小且可以容忍丢失的报文DNS,RIP,DHCP等协议均使用UDP传输。

UDP也适用于对数据丢失不敏感的应用,如流媒体和IP电话。在使用UDP协议时请注意UDP协议没有拥塞控制,流媒体产生的大量的UDP数据包容易导致拥塞。

UDP不会对应用层交付的数据进行拆分, 数据大小必须由应用程序控制。

UDP的首部非常简单只有8个字节,四个字段依次是: 源端口, 目标端口, 报文长度和校验和。每个字段占2个字节。

TCP与UDP协议的更多相关文章

  1. TCP和UDP协议的比较

    通信协议 网络通信是两台计算机上的两个进程之间的通信. 网络通信需要通信协议.网络协议有很多种,就像我们平常交流说话,也有多种语言.. 最常见的协议是TCP/IP协议.UDP协议. TCP:TCP 是 ...

  2. 网络编程协议(TCP和UDP协议,黏包问题)以及socketserver模块

    网络编程协议 1.osi七层模型 应用层  表示层  会话层  传输层  网络层  数据链路层  物理层 2.套接字 socket 有两类,一种基于文件类型,一种基于网络类型 3.Tcp和udp协议 ...

  3. TCP 和 UDP 协议

    TCP 和 UDP 协议 一.socket层 Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口.在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐 ...

  4. 运输层协议--TCP及UDP协议

    TCP及UDP协议 按照网络的五层分级结构来看,TCP及UDP位于运输层,故TCP及UDP是运输层协议.TCP协议--传输控制协议UDP协议--用户数据报协议 多路复用及多路分解 图多路复用及多路分解 ...

  5. TCP和UDP 协议发送数据包的大小

    在进行UDP编程的时候,我们最容易想到的问题就是,一次发送多少bytes好? 当然,这个没有唯一答案,相对于不同的系统,不同的要求,其得到的答案是不一样的,这里仅对像ICQ一类的发送聊天消息的情况作分 ...

  6. TCP/IP/UDP 协议

    互连网早期的时候,主机间的互连使用的是NCP协议.这种协议本身有很多缺陷,如:不能互连不同的主机,不能互连不同的操作系统,没有纠错功能.为了改善这种缺点,大牛弄出了TCP/IP协议.现在几乎所有的操作 ...

  7. 网络编程协议(TCP和UDP协议,粘包问题)以及socketserver模块

    网络编程协议 1.osi七层模型 应用层  表示层  会话层  传输层  网络层  数据链路层  物理层 2.套接字 socket 有两类,一种基于文件类型,一种基于网络类型 3.Tcp和udp协议 ...

  8. UNP(一):网络编程角度下的TCP、UDP协议

    此博文是学习UNP(UNIX Network Programming)后的读书笔记,供以后自己翻阅回想知识. TCP.UDP概述 在前面<计算机网络与TCP/IP>栏目下已经介绍过一些关于 ...

  9. 深入浅出TCP与UDP协议

    深入浅出TCP与UDP协议 网络协议是每个前端工程师的必修课,TCP/IP协议族是一系列网络协议的总和,而其中两个具有代表性的传输层协议,分别是TCP与UDP,本文将介绍这两者以及他们之间的区别. 一 ...

随机推荐

  1. “RazorEngine.Templating.TemplateCompilationException”类型的异常在 RazorEngine.NET4.0.dll 中发生,但未在用户代码中进行处理

    错误信息: "RazorEngine.Templating.TemplateCompilationException"类型的异常在 RazorEngine.NET4.0.dll 中 ...

  2. jquery获取checkbox的值并post提交

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...

  3. Failed to load the JNI shared library &quot;XXXXXXX&quot;

    今天启动Eclipse的时候出现了这个问题,经过查找, 一般来说这种问题都是因为eclipse 和Java 的兼容性不一致所导致的. 1) 查看Eclipse 和Java 版本 那么我们需要分别查看下 ...

  4. Windows下免安装版mysql5.7的初始密码

    MySQL5.7之后,初始密码不在默认为空,而是随机生成的密码. 在mysql/data目录下,生成了一个.err文件(等同linux下的log日志文件,此文件会被mysql服务占用). 使用记事本可 ...

  5. spring boot整合shiro

    安全框架Shiro和Spring Security比较,本文主要围绕Shiro进行学习 一 Shiro 是一个强大而灵活的开源安全框架,能够清晰的处理认证 授权 管理会话以及,密码加密 01 .认证与 ...

  6. Kafka监控系统Kafka Eagle:支持kerberos认证

    在线文档:https://ke.smartloli.org/ 作者博客:https://www.cnblogs.com/smartloli/p/9371904.html 源码地址:https://gi ...

  7. DockerSwarm获取Token与常用命令

    一.Token相关 Join tokens是允许一个节点加入集群的密钥.有两种可用的不同的join tokens,一个是用作worker角色,另一个是用作manager角色.在执行swarm join ...

  8. 洛谷试炼场 - 关卡2-1 - 简单的模拟 - (Done)

    最近这段时间感冒外加一些乱七八糟的事情,导致脑子严重僵化……只好刷刷基础(水)题巩固巩固基础(混混题数). 目录 P1003 铺地毯 P1067 多项式输出 P1540 机器翻译 P1056 排座椅 ...

  9. Linux命令列内容

    命令列内容: 一般模式 移动光标 [ctrl]+[f] 屏幕[向前]移动一页 [ctrl]+[b] 屏幕[向后]移动一页 0 这是数字0:移动到这一行的最前面字符处 $ 移动到这一行的最后面字符处 G ...

  10. scala-泛型

    //实例化之后使用get方法必须传入相同类型的参数 class A[T](x: T) { def get(x: T) { print(x) } } var a1 = new A(1) a1.get(1 ...