免费数据库网站,互联网推广与营销,aso优化软件,网页代码模板源码UDP 协议
UDP 协议端格式 16 位 UDP 长度, 表示整个数据报(UDP 首部UDP 数据)的最大长度如果校验和出错, 就会直接丢弃
UDP 的特点 UDP 传输的过程类似于寄信 . 无连接: 知道对端的 IP 和端口号就直接进行传输, 不需要建立连接不可靠: 没有确认机制, 没有重传机制; 如果因…UDP 协议
UDP 协议端格式 16 位 UDP 长度, 表示整个数据报(UDP 首部UDP 数据)的最大长度如果校验和出错, 就会直接丢弃
UDP 的特点 UDP 传输的过程类似于寄信 . 无连接: 知道对端的 IP 和端口号就直接进行传输, 不需要建立连接不可靠: 没有确认机制, 没有重传机制; 如果因为网络故障该段无法发到对方UDP 协议层也不会给应用层返回任何错误信息面向数据报: 不能够灵活的控制读写数据的次数和数量即应用层交给 UDP 多长的报文UDP原样发送既不会拆分也不会合并
UDP 的缓冲区 UDP 没有真正意义上的 发送缓冲区 调用 sendto 会直接交给内核 由内核将数据传给网络层协议进行后续的传输动作。UDP 具有接收缓冲区. 但是这个接收缓冲区不能保证收到的 UDP 报的顺序和发送 UDP 报的顺序一致 如果缓冲区满了 , 再到达的 UDP 数据就会被丢弃。 UDP 的 socket 既能读 , 也能写 , 这个概念叫做 全双工。 UDP 使用注意事项 我们注意到 UDP 协议首部中有一个 16 位的最大长度 也就是说一个 UDP 能传输的数据最大长度是 64K( 包含 UDP 首部 )。然而 64K 在当今的互联网环境下 , 是一个非常小的数字 如果我们需要传输的数据超过 64K 就需要在应用层手动的分包 多次发送 并在接收端手动拼装。 TCP 协议 TCP 协议段格式 源端口16位标识发送方的端口号范围是0到65535。目的端口16位标识接收方的端口号范围是0到65535。序列号32位用于标识每个报文段使目的主机可确认已收到指定报文段中的数据。在SYN标志未置位时该字段指示了用户数据区中第一个字节的序号在SYN标志置位时该字段指示的是初始发送的序列号。确认号32位目的主机返回确认号使源主机知道某个或几个报文段已被接收。如果ACK控制位被设置为1则该字段有效。确认号等于顺序接收到的最后一个报文段的序号加1这也是目的主机希望下次接收的报文段的序号值。数据偏移首部长度4位指出TCP报文段的数据起始处距离TCP报文段的起始处有多远即首部长度。由于TCP报头的长度随TCP选项字段内容的不同而变化因此报头中包含一个指定报头字段的字段。该字段以32比特为单位所以报头长度一定是32比特的整数倍有时需要在报头末尾补0。如果报头没有TCP选项字段则报头长度值为5表示报头一个有160比特即20字节。保留位6位由跟在数据偏移字段后的6位构成全部为0。控制位6位 URG紧急比特1位当URG1时表明紧急指针字段有效它告诉系统此报文段中有紧急数据应尽快传送。ACK确认比特1位仅当ACK1时确认号字段才有效TCP规定在连接建立后所有传达的报文段都必须把ACK置1。PSH推送比特1位当两个应用进程进行交互式的通信时有时在一端的应用进程希望在键入一个命令后立即就能够收到对方的响应。在这种情况下TCP就可以使用推送push操作这时发送方TCP把PSH置1并立即创建一个报文段发送出去接收方收到PSH1的报文段就尽快地即“推送”向前交付给接收应用进程而不再等到整个缓存都填满后再向上交付。RST复位比特1位用于复位相应的TCP连接。SYN同步比特1位仅在三次握手建立TCP连接时有效。当SYN1而ACK0时表明这是一个连接请求报文段对方若同意建立连接则应在相应的报文段中使用SYN1和ACK1。因此SYN置1就表示这是一个连接请求或连接接受报文。FIN终止比特1位用来释放一个连接。当FIN1时表明此报文段的发送方的数据已经发送完毕并要求释放运输连接。 窗口16位此字段用来进行流量控制这个值是本机期望一次接收的字节数即发送数据的窗口大小。告诉对方在不等待确认的情况下可以发来多大的数据。这里表示的最大长度是2^16-165535如需要使用更大的窗口大小需要使用选项中的窗口扩大因子选项。指发送本报文段的一方的接收窗口而不是自己的发送窗口。校验和16位源主机和目的主机根据TCP报文段以及伪报头的内容计算校验和。在伪报头中存放着来自IP报头以及TCP报文段长度信息。与UDP一样伪报头并不在网络中传输并且在校验和中包含伪报头的目的是为了防止目的主机错误地接收存在路由的错误数据报。紧急指针16位仅在URG1时才有意义它指出本报文段中的紧急数据的字节数紧急数据结束后就是普通数据即指出了紧急数据的末尾在报文中的位置注意即使窗口为零时也可发送紧急数据。如果URG为1则紧急指针标志着紧急数据的结束。其值是紧急数据最后1字节的序号表示报文段序号的偏移量。 首部可变部分 选项字段长度可变最长可达40字节当没有使用选项时TCP首部长度是20字节。可能包括“窗口扩大因子”、“时间戳”等选项。填充字段用于保证任选项为32bit的整数倍。 数据部分 数据长度可变TCP首部结束之后的部分其长度由IP包的长度减去IP头部长度和TCP头部长度得出。 确认应答(ACK)机制 数据发送发送方将数据分割成较小的单元称为TCP段并为每个段分配一个唯一的序列号实际上一个字节的数据对应一个序列号。然后将这些TCP段发送给接收方并启动一个定时器来跟踪每个已发送段的确认。 数据接收与确认接收方收到TCP段后将按序将它们重新组装成完整的数据流。一旦接收方成功接收并处理了数据它会发送一个确认ACK给发送方。确认中包含接收到的最高序列号表示该序列号之前的所有数据都已正确接收。 发送方处理确认发送方在接收到确认后会停止相应定时器并继续发送下一个序列号的TCP段。如果发送方在定时器超时之前未收到确认它将重新发送未确认的TCP段。 超时重传机制 主机 A 发送数据给 B 之后 , 可能因为网络拥堵等原因 , 数据无法到达主机 B如果主机 A 在一个特定时间间隔内没有收到 B 发来的确认应答 , 就会进行重发。 但是 , 主机 A 未收到 B 发来的确认应答 , 也可能是因为 ACK 丢失了 因此主机 B 会收到很多重复数据 . 那么 TCP 协议需要能够识别出那些包是重复的包 , 并且把重复的丢弃掉。这时候我们可以利用前面提到的序列号, 就可以很容易做到去重的效果 . 连接管理机制 在正常情况下, TCP 要经过三次握手建立连接 , 四次挥手断开连接。 服务端状态转化 : [CLOSED - LISTEN] 服务器端调用 listen 后进入 LISTEN 状态, 等待客户端连接[LISTEN - SYN_RCVD] 一旦监听到连接请求(同步报文段), 就将该连接放入内核等待队列中, 并向客户端发送 SYN 确认报文[SYN_RCVD - ESTABLISHED] 服务端一旦收到客户端的确认报文, 就进入 ESTABLISHED 状态, 可以进行读写数据了[ESTABLISHED - CLOSE_WAIT] 当客户端主动关闭连接(调用 close), 服务器会收到结束报文段, 服务器返回确认报文段并进入 CLOSE_WAIT[CLOSE_WAIT - LAST_ACK] 进入 CLOSE_WAIT 后说明服务器准备关闭连接(需要处理完之前的数据); 当服务器真正调用 close 关闭连接时, 会向客户端发送 FIN, 此时服务器进入 LAST_ACK 状态, 等待最后一个 ACK 到来(这个 ACK 是客户端确认收到了 FIN) [LAST_ACK - CLOSED] 服务器收到了对 FIN 的 ACK, 彻底关闭连接 客户端状态转化 : [CLOSED - SYN_SENT] 客户端调用 connect, 发送同步报文段[SYN_SENT - ESTABLISHED] connect 调用成功, 则进入 ESTABLISHED 状态, 开始读写数据[ESTABLISHED - FIN_WAIT_1] 客户端主动调用 close 时, 向服务器发送结束报文段, 同时进入 FIN_WAIT_1[FIN_WAIT_1 - FIN_WAIT_2] 客户端收到服务器对结束报文段的确认, 则进入 FIN_WAIT_2, 开始等待服务器的结束报文段[FIN_WAIT_2 - TIME_WAIT] 客户端收到服务器发来的结束报文段, 进入TIME_WAIT, 并发出 LAST_ACK[TIME_WAIT - CLOSED] 客户端要等待一个 2MSL(Max Segment Life, 报文最大生存时间)的时间, 才会进入 CLOSED 状态. 下图是 TCP 状态转换的一个汇总 : 较粗的虚线表示服务端的状态变化情况较粗的实线表示客户端的状态变化情况CLOSED 是一个假想的起始点, 不是真实状态 三次握手建立连接 第一次握手客户端向服务器发送一个带有SYNSynchronize Sequence Numbers同步序列号标志位的TCP数据包请求建立连接。这个数据包中包含了客户端的初始序列号ISNInitial Sequence Number。第二次握手服务器收到客户端的SYN请求后会回复一个带有SYN和ACKAcknowledgment确认标志位的数据包称为SYN-ACK响应。这个响应中服务器确认了客户端的SYN请求并指定了服务器的初始序列号ISN。同时服务器还会对客户端的初始序列号进行确认即发送一个确认号ACK号表示已经收到客户端发送的序列号加1的数据。第三次握手客户端收到服务器的SYN-ACK响应后会发送一个带有ACK标志位的数据包表示确认了服务器的响应。这个ACK数据包中客户端会确认收到了服务器的SYN响应并指定了下一个要发送的序列号即服务器的初始序列号加1。至此三次握手完成TCP连接建立成功双方可以开始进行数据传输。 四次挥手断开连接 第一次挥手客户端发送一个FINFinish结束标志位的数据包表示自己的数据已经发送完毕请求关闭连接。此时客户端进入FIN_WAIT_1状态。第二次挥手服务器收到客户端的FIN包后会发送一个ACK包进行确认表示已经收到客户端的关闭请求。此时服务器进入CLOSE_WAIT状态客户端进入FIN_WAIT_2状态。第三次挥手服务器在确认自己的数据也发送完毕后会发送一个FIN包给客户端表示自己也准备关闭连接。此时服务器进入LAST_ACK状态。第四次挥手客户端收到服务器的FIN包后会发送一个ACK包进行确认。此时客户端进入TIME_WAIT状态经过一段时间通常为2MSLMaximum Segment Lifetime最大报文段生存时间后客户端进入CLOSED状态服务器在收到客户端的ACK包后也进入CLOSED状态连接彻底关闭。 理解 TIME_WAIT 状态 现在做一个测试 , 首先启动 server, 然后启动 client, 然后用 Ctrl-C 使 server 终止 , 这时马上再运行 server, 结果是 : 这是因为 虽然 server 的应用程序终止了 但 TCP 协议层的连接并没有完全断开 因此不能再次监听同样的 server 端口。 我们用 netstat 命令查看一下 : TCP 协议规定 , 主动关闭连接的一方要处于 TIME_ WAIT 状态 , 等待两个MSL(maximum segment lifetime)的时间后才能回到 CLOSED 状态。我们使用 Ctrl-C 终止了 server, 所以 server 是主动关闭连接的一方 , 在 TIME_WAIT 期间仍然不能再次监听同样的 server 端口。MSL 在 RFC1122 中规定为两分钟 , 但是各操作系统的实现不同 可以通过 cat /proc/sys/net/ipv4/tcp_fin_timeout 查看 msl 的值 在 Centos7/Ubuntu 上默认配置的值是 60s。 对于为什么处于 TIME_ WAIT 状态的一方 ,需要等待两个MSL的时间后才能回到 CLOSED 状态。这是因为MSL 是 TCP 报文的最大生存时间 , 因此 TIME_WAIT 持续存在 2MSL 的话就能保证在两个传输方向上的尚未被接收或迟到的报文段都已经消失(否则服务器立刻重启, 可能会收到来自上一个进程的迟到的数据 , 但是这种数据很可能是错误的)同时也是在理论上保证最后一个报文可靠到达(假设最后一个 ACK 丢失 , 那么服务器会再重发一个 FIN. 这时虽然客户端的进程不在了 , 但是 TCP 连接还在 , 仍然可以重发 LAST_ACK) setsockopt() 要解决 TIME_WAIT 状态引起的 bind 失败的方法我们可以使用 setsockopt 函数 int setsockopt(int sock, int level, int optname, const void *optval, socklen_t optlen); 参数说明 sock将要被设置选项的套接字描述符。level选项所在的协议层常见的取值有SOL_SOCKET通用套接字选项、IPPROTO_IPIP选项、IPPROTO_TCPTCP选项等使用 SOL_SOCKET 即可。optname需要设置的选项名如SO_BROADCAST、SO_REUSEADDR、TCP_NODELAY等设置为 SO_REUSEADDR , 表示允许创建端口号相同但 IP 地址不同的多个 socket 描述符。optval指向包含新选项值的缓冲区根据选项名称的数据类型进行转换。optlen现选项的长度。 返回值 成功执行时返回0。失败返回-1errno被设为以下的某个值 EBADFsock不是有效的文件描述词。EFAULToptval指向的内存并非有效的进程空间。EINVAL在调用setsockopt()时optlen无效。ENOPROTOOPT指定的协议层不能识别选项。ENOTSOCKsock描述的不是套接字。 使用如下 int opt 1;
setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,opt,sizeof(opt)); 滑动窗口 刚才我们讨论了确认应答策略 对每一个发送的数据段 都要给一个 ACK 确认应答。 收到 ACK 后再发送下一个数据段。 这样做有一个比较大的缺点 就是性能较差 尤其是数据往返的时间较长的时候。 既然这样一发一收的方式性能较低 那么我们一次发送多条数据 就可以大大的提高性能( 其实是将多个段的等待时间重叠在一起了 )。 窗口大小指的是无需等待确认应答而可以继续发送数据的最大值 上图的窗口大小就是 4000 个字节 ( 四个段 )。 发送前四个段的时候, 不需要等待任何 ACK, 直接发送。收到第一个 ACK 后 , 滑动窗口向后移动 , 继续发送第五个段的数据 依次类推。操作系统内核为了维护这个滑动窗口, 需要开辟 发送缓冲区 来记录当前还有哪些数据没有应答 只有确认应答过的数据 , 才能从缓冲区删掉。窗口越大, 则网络的吞吐率就越高。 那么如果出现了丢包 , 如何进行重传 ? 这里分两种情况讨论 情况一 : 数据包已经抵达 , ACK 被丢了 这种情况下 , 部分 ACK 丢了并不要紧 , 因为可以通过后续的 ACK 进行确认 情况二 : 数据包就直接丢了 当某一段报文段丢失之后 , 发送端会一直收到 1001 这样的 ACK, 就像是在提醒发送端 我想要的是 1001 一样。如果发送端主机连续三次收到了同样一个 1001 这样的应答 , 就会将对应的数据 1001 - 2000 重新发送。这个时候接收端收到了 1001 之后 , 再次返回的 ACK 就是 7001 了 ( 因为 2001 - 7000)接收端其实之前就已经收到了 , 被放到了接收端操作系统内核的 接收缓冲区 中。 这种机制被称为 高速重发控制 ( 也叫 快重传 )。 流量控制 接收端处理数据的速度是有限的。 如果发送端发的太快 导致接收端的缓冲区被打满 这个时候如果发送端继续发送 就会造成丢包 继而引起丢包重传等等一系列连锁反应。因此 TCP 支持根据接收端的处理能力 来决定发送端的发送速度 这个机制就叫做 流量 控制。 接收端将自己可以接收的缓冲区大小放入 TCP 首部中的 窗口大小 字段 , 通过 ACK 端通知发送端。接收端一旦发现自己的缓冲区快满了, 就会将窗口大小设置成一个更小的值通知给发送端发送端接受到这个窗口之后, 就会减慢自己的发送速度。如果接收端缓冲区满了, 就会将窗口置为 0 这时发送方不再发送数据 , 但是需要定期发送一个窗口探测数据段, 使接收端把窗口大小告诉发送端。 拥塞控制 虽然 TCP 有了滑动窗口这个大杀器 , 能够高效可靠的发送大量的数据 但是如果在刚开始阶段就发送大量的数据, 仍然可能引发问题。因为网络上有很多的计算机, 可能当前的网络状态就已经比较拥堵。 在不清楚当前网络状态下 贸然发送大量的数据 是很有可能引起雪上加霜的。TCP 引入 慢启动 机制 先发少量的数据 摸清当前的网络拥堵状态 再决定按照多大的速度传输数据。 此处引入一个概念称为 拥塞窗口发送开始的时候, 定义拥塞窗口大小为 1每次收到一个 ACK 应答 拥塞窗口加 1。每次发送数据包的时候将拥塞窗口和接收端主机反馈的窗口大小做比较 取较小的值作为实际发送的窗口。 像上面的拥塞窗口增长速度 是指数级别的 慢启动 只是指初使时慢 但是增长速度非常快。 为了不增长的那么快, 因此不能使拥塞窗口单纯的加倍 引入一个叫做慢启动的阈值当拥塞窗口超过这个阈值的时候, 不再按照指数方式增长 , 而是按照线性方式增长。 当 TCP 开始启动的时候 , 慢启动阈值等于窗口最大值在每次超时重发的时候, 慢启动阈值会变成原来的一半 , 同时拥塞窗口置回 1。少量的丢包, 我们仅仅是触发超时重传 大量的丢包 , 我们就认为网络拥塞。当 TCP 通信开始后 , 网络吞吐量会逐渐上升 ; 随着网络发生拥堵 , 吞吐量会立刻下降 ; 拥塞控制 , 归根结底是 TCP 协议想尽可能快的把数据传输给对方 , 但是又要避免给网络造成太大压力的折中方案。 延迟应答 如果接收数据的主机立刻返回 ACK 应答 , 这时候返回的窗口可能比较小。 假设接收端缓冲区为 1M. 一次收到了 500K 的数据 ; 如果立刻应答 , 返回的窗口就是 500K。但实际上可能处理端处理的速度很快, 10ms 之内就把 500K 数据从缓冲区消费掉了。 在这种情况下, 接收端处理还远没有达到自己的极限 , 即使窗口再放大一些 , 也能处理过来 如果接收端稍微等一会再应答, 比如等待 200ms 再应答 , 那么这个时候返回的窗口大小就是 1M。 数量限制: 每隔 N 个包就应答一次时间限制: 超过最大延迟时间就应答一次 具体的数量和超时时间 依操作系统不同也有差异。 一般 N 取 2 超时时间取 200ms。 TCP/UDP 对比 TCP与UDP的对比 对比维度TCPUDP连接性面向连接需要建立连接3次握手和断开连接4次挥手无连接不需要建立连接可靠性可靠交付通过编号与确认、流量控制、计时器等机制保证数据无差错、不丢失、不重复且按序到达不可靠交付尽最大努力交付但不保证可靠报文首部20字节开销大8字节开销小吞吐量控制有拥塞控制、流量控制、重传机制、滑动窗口等机制无双工性点对点全双工通信支持一对一、一对多、多对一和多对多的交互通信编程步骤复杂需要监听、接收、连接等步骤简单不需要监听和接收连接使用场景对传输效率要求低但准确率要求高的场景如HTTP、FTP、SMTP等对传输效率要求高但准确率要求低的场景如DNS、NFS等 结论 TCP适用于需要可靠传输的场景如文件传输、电子邮件等。UDP适用于对实时性要求高对可靠性要求不高的场景如视频会议、直播等。