文章目录
一、TCP丢包原因、解决办法
二、UDP丢包
TCP是基于不可靠的网络实现可靠的传输,肯定也会存在掉包的情况,如果通信中发现缺少数据或者丢包,那么,最大的可能在于程序发送的过程或者接收的过程出现问题。
例如服务端要给客户端发送大量数据,Send频率很高,那么就很有可能在Send环节出现错误(1.程序处理逻辑错误,2.多线程同步问题,3.缓冲区溢出等),如果没有对Send发送失败做处理,那么客户端收到的数据比理论要收到的数据少,就会造成丢数据,丢包现象。
TCP协议(Transimission Control Protocol)是以一种面向连接的、可靠的、基于字节流的传输层通信协议。
TCP是基于不可靠的网路实现可靠传输,肯定会存在丢包问题。
如果在通信过程中,发现缺少数据或者丢包,那边么最大的可能性是程序发送过程或者接受过程中出现问题
例如:我有2台服务器 ,A和B服务器。A服务器发送数据给B服务器频率过高时,B服务器来不及处理,造成数据丢包。(原因可能是程序逻辑问题,多线程同步问题,缓冲区溢出问题)。
如果A服务器不对发送频率进行控制,或者数据进行重发的话,那么B服务器收到数据就会少。就会造成丢失数据
为了保障传输可靠性,TCP协议本身有如下规定:
关于TCP如何保障传输可靠性,可查阅 计算机网络常见面试题(一):TCP/IP五层模型、TCP三次握手、四次挥手,TCP传输可靠性保障、ARQ协议
按理说,TCP协议经过处理、已能保障传输可靠性,但是IP协议是不可靠、无连接的,以下情况仍有可能会丢包:
对应解决方案如下:
1、服务端要给客户端发送大量数据时,Send频率很高,Send环节可能出现错误(程序处理逻辑错误、多线程同步问题、缓冲区溢出等)
2、有大量TCP连接请求
3、网络较差(譬如握手过程中丢包) :TCP 本身具有重传机制,但在极端情况下,丢包仍然可能发生
(1)调整TCP参数
# 增加重传次数
sudo sysctl -w net.ipv4.tcp_retries2=15
# 增加超时时间
sudo sysctl -w net.ipv4.tcp_fin_timeout=30
reno
、cubic
、bbr
等# 查看当前使用的拥塞控制算法
sysctl net.ipv4.tcp_congestion_control
# 设置为 BBR( Bottleneck Bandwidth and RTT)
sudo sysctl -w net.ipv4.tcp_congestion_control=bbr
(2)使用TCP快速重传和恢复
# 开启快速重传
sudo sysctl -w net.ipv4.tcp_frto=2
(3)使用TCP快速打开
TCP 快速打开(TCP Fast Open,简称 TFO)是一种优化 TCP 连接建立过程的技术。传统的 TCP 连接建立需要三次握手(SYN, SYN-ACK, ACK),而在某些情况下,这三次握手会导致额外的延迟。TCP 快速打开允许客户端在第一次 SYN 包中携带数据,从而减少了一次往返时间(RTT),提高了连接建立的速度。
TCP 快速打开的工作原理
TCP 快速打开(TCP Fast Open)可以减少建立连接的时间,从而减少丢包的可能性。
# 开启 TCP 快速打开
sudo sysctl -w net.ipv4.tcp_fastopen=3
参数3的含义是:客户端和服务器都支持 TFO、客户端可以发送 TFO 请求、服务器可以接受 TFO 请求
(4)优化网络设备和驱动、调整网络设备参数
可以通过调整网络设备的参数来优化性能,例如增加接收缓冲区大小。
# 增加接收缓冲区大小
sudo ethtool -G eth0 rx 4096
(5)使用网络监控工具
使用网络监控工具(如 Wireshark、tcpdump)来监控和分析网络流量,及时发现和解决问题。
# 使用 tcpdump 抓包
sudo tcpdump -i eth0 -w capture.pcap
TCP(传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议。TCP 端口是用于标识网络应用的逻辑地址。每个 TCP 连接由源 IP 地址、源端口号、目标 IP 地址和目标端口号唯一标识。
TCP(传输控制协议)端口号是一个 16 位的数字,用于标识网络应用程序的逻辑地址。每个 TCP 连接由四个部分唯一标识:
端口号的范围是从 0 到 65535,其中:
当有多个 TCP 请求时,这些请求并不一定都使用同一个端口。实际上,每个连接都有唯一的四元组(源 IP 地址、源端口号、目标 IP 地址、目标端口号)来区分。
1)服务器端口
服务器通常监听一个固定的端口,例如 HTTP 服务通常监听 80 端口,HTTPS 服务通常监听 443 端口。当客户端发起连接请求时,服务器的监听端口会接受连接请求,并为每个连接分配一个新的端口。
2)客户端端口
客户端发起连接时,操作系统会为每个连接分配一个临时端口(通常是动态端口,范围在 49152-65535 之间)。这个临时端口在连接期间是唯一的。
3)示例说明
假设有一个 Web 服务器监听 80 端口,两个客户端分别从不同的 IP 地址发起连接:
服务器接收到这两个连接请求后,会为每个连接分配一个新的端口:
尽管服务器监听的是同一个端口(80),但由于每个连接的四元组不同,服务器可以区分这些连接并同时处理它们。
当有大量 TCP 连接请求时,服务器需要采取一些措施来有效地管理和处理这些连接,以保证系统的性能和稳定性。以下是一些常见的处理方法:
1. 使用高性能服务器
2. 优化网络配置
net.core.somaxconn
(最大监听队列长度)、net.ipv4.tcp_max_syn_backlog
(SYN 队列长度)、net.ipv4.tcp_fin_timeout
(FIN 超时时间)等。3. 使用连接池
4. 服务器端优化
5. 负载均衡
6. 限制连接速率
7. 优化应用程序
TCP | UDP |
---|---|
面向连接 | 无连接 |
提供可靠服务 | 不保证可靠交互 |
有状态 | 无状态 |
面向字节流 | 面向报文 |
传输效率较慢 | 传输效率较快 |
有拥塞控制 | 没有拥塞控制 |
每一条TCP连接只能是stron | 支持一对一、一对多、多对一、多对多 |
首部开销20字节 | 首部开销8字节 |
1、接收端处理时间过长导致丢包:
调用recv方法接收端收到数据后,处理数据花了一些时间,处理完后再次调用recv方法,在这二次调用间隔里,发过来的包可能丢失。对于这种情况可以修改接收端,将包接收后存入一个缓冲区,然后迅速返回继续recv。
2、发送的包巨大丢包:
虽然send方法会帮你做大包切割成小包发送的事情,但包太大也不行。例如超过50K的一个udp包,不切割直接通过send方法发送也会导致这个包丢失。这种情况需要切割成小包再逐个send。
3、发送的包较大,超过接受者缓存导致丢包:
包超过mtu size数倍,几个大的udp包可能会超过接收者的缓冲,导致丢包。这种情况可以设置socket接收缓冲。以前遇到过这种问题,我把接收缓冲设置成64K就解决了。
4、发送的包频率太快:
虽然每个包的大小都小于mtu size 但是频率太快,例如40多个mut size的包连续发送中间不sleep,也有可能导致丢包。这种情况也有时可以通过设置socket接收缓冲解决,但有时解决不了。所以在发送频率过快的时候还是考虑sleep一下吧。
5、局域网内不丢包,公网上丢包:
这个问题我也是通过切割小包并sleep发送解决的。如果流量太大,这个办法也不灵了。总之udp丢包总是会有的,如果出现了用我的方法解决不了,还有这个几个方法: 要么减小流量,要么换tcp协议传输,要么做丢包重传的工作。
1.发送频率过高导致丢包
很多人会不理解发送速度过快为什么会产生丢包,原因就是UDP的SendTo不会造成线程阻塞,也就是说,UDP的SentTo不会像TCP中的SendTo那样,直到数据完全发送才会return回调用函数,它不保证当执行下一条语句时数据是否被发送(SendTo方法是异步的)。这样,如果要发送的数据过多或者过大,那么在缓冲区满的那个瞬间要发送的报文就很有可能被丢失。至于对“过快”的解释,作者这样说:“A few packets a second are not an issue; hundreds or thousands may be an issue.”(一秒钟几个数据包不算什么,但是一秒钟成百上千的数据包就不好办了)。
要解决接收方丢包的问题很简单,首先要保证程序执行后马上开始监听(如果数据包不确定什么时候发过来的话),其次,要在收到一个数据包后最短的时间内重新回到监听状态,其间要尽量避免复杂的操作(比较好的解决办法是使用多线程回调机制)。
2.报文过大丢包
至于报文过大的问题,可以通过控制报文大小来解决,使得每个报文的长度小于MTU。以太网的MTU通常是1500 bytes,其他一些诸如拨号连接的网络MTU值为1280 bytes,如果使用speaking这样很难得到MTU的网络,那么最好将报文长度控制在1280 bytes以下。
3.发送方丢包
发送方丢包:内部缓冲区(internal buffers)已满,并且发送速度过快(即发送两个报文之间的间隔过短); 接收方丢包:Socket未开始监听; 虽然UDP的报文长度最大可以达到64 kb,但是当报文过大时,稳定性会大大减弱。这是因为当报文过大时会被分割,使得每个分割块(翻译可能有误差,原文是fragmentation)的长度小于MTU,然后分别发送,并在接收方重新组合(reassemble),但是如果其中一个报文丢失,那么其他已收到的报文都无法返回给程序,也就无法得到完整的数据了。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。