序言

项目涉及基于UDP的socket通信,该部分的基本情况如下:

  • 发端程序:主函数开启4个发包线程,每个线程发送一定量的数据,通过限制发包速率限制发包流量。

  • 收端程序:主函数对应开启4个收包线程,每个线程收取对应端口的数据,收到数据包即时封装处理。

其他说明:

  • 本地收发。如果不限制发包速率将会非常快

  • 基于UDP。使用recvfrom()函数收包

  • recvfrom()接收后立即将包加入队列并封装处理,即一次处理单个包

  • 发包流量最大160Mbps = 20MBps

  • 多种流量:160Mbps,80Mbps,40Mbps等进行测试

测试方式:

  • 发送一定时间的数据。

    • 如设置发送1s,发送数据量160Mbits,即160Mbps流量
  • 收到数据包后进行包计数。

    • 统计收包率/丢包率
  • 记录收端处理数据耗时,对比发端耗时。

    • 即测试收端处理速度,不过应该注意此处的耗时只是处理所收到数据包的耗时,并不一定是所有数据量的耗时,如果存在丢包的话。
  • 但是现在测试出现的问题如下:

  • 收包率低/丢包率高。

    • 丢包率最高时可达67%
      • 速率逐渐降低,收包率有上升趋势
      • 到一定速率,速率继续降低,收包数也不继续上升
  • 最大容量下耗时超过了发包耗时

    • 耗时最大可达发送时间的2倍以上
      • 速率逐渐降低,耗时有减小趋势
      • 到一定速率,速率继续降低,由于只能处理一定收包数,耗时基本稳定

一、问题分析

  • 收包率低/丢包率高的原因分析

    • (1) 缓存太小,不能及时接收数据。

      • 连续多个UDP包超过了UDP接收缓冲区大小
      • 如:UDP包过大
      • 如:UDP发包速率过快,突发大数据流量超过了缓冲区上限
    • (2)recvfrom()接收到数据之后处理速度太慢

    • 如果数据接收和处理/渲染是连续进行的,那么可能由于数据处理过慢,两次recvfrom调用的时间间隔里发过来的包丢失。


二、问题验证和解决措施

  • (1) 缓存太小不能及时接收数据

  • [1] 分析:

  • UDP无需真正的发送缓冲区:

    • UDP是不可靠连接,不必保存应用进程的数据拷贝,因此无需真正的发送缓冲区(TCP需要)。应用进程的数据在沿协议栈往下传递,以某种形式拷贝到内核缓冲区,然而数据链路层在送出数据之后将丢弃该拷贝。
  • UDP是没有流量控制的:

    • 较快的发送端可以很容易淹没较慢的接收端,导致接收端的UDP丢弃数据报。

    • UDP套接字的缓冲区是以一个个报文为单位进行排队的,调用一次recvfrom表示提取一个报文,和TCP基于字节流的方式是不同的

  • 因此,如果socket接收缓存设置过小,就会因为UDP包过大或者发包速率过快而丢包

[2] 解决方法:重新设置UDP接收缓冲区大小

  • UDP接收缓冲区默认值:cat /proc/sys/net/core/rmem_default

    • 本系统:212992 = 208K
  • UDP接收缓冲区最大值:cat /proc/sys/net/core/rmem_max,UDP最大可设置值的一半

    • 本系统:212992 = 208K,即最大值425984 = 416K
  • UDP接收缓冲区最小值:sysctl -a | grep rmem

    • 本系统:net.ipv4.udp_rmem_min = 4096 = 2K,由内核的宏决定
  • UDP发送缓冲区默认值:cat /proc/sys/net/core/wmem_default

    • 本系统:212992 = 208K
  • UDP发送缓冲区最大值:cat /proc/sys/net/core/wmem_max

    • 本系统:212992 = 208K,即最大值425984 = 416K
  • UDP发送缓冲区最小值:sysctl -a | grep wmem

    • 本系统:net.ipv4.udp_wmem_min = 4096 = 2K,由内核的宏决定

[3] 解决步骤:

  • 调整UDP缓冲区大小:使用函数setsockopt()函数修改接收缓冲区大小

    • 缓冲区改大可以处理突发的大流量数据,不至于数据(视音频等)变化、流量突然增大的时候缓冲区溢出
  • 重新设置系统缓冲区最大值,再调整UDP缓冲区大小:

    • 打开配置文件:sudo vim /etc/sysctl.conf

    • 在文件末尾添加:net.core.rmem_max = 6291456

      • 将接收缓冲最大值设置为12582912 = 12M
    • 执行配置:sysctl -p

    • 重新查看最大值:cat /proc/sys/net/core/rmem_max

    • 发现系统接收缓冲最大值已改变,此时可以通过setsockopt函数设置更大接收缓存。发送缓冲最大值也可以通过类似方式修改:net.core.wmem_max = 6291456,sysctl -p

/* setsockopt()函数修改:*/

//函数原型
int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);

sockfd: 标识一个套接字的描述字
level: 选项定义的层次:支持SOL_SOCKET, IPPROTO_TCP, IPPROTO_IP,和IPPROTO_IPV6
optname:需设置得选项 SO_RCVBUF(接收缓冲区),SO_SNDBUF(发送缓冲区)
optval:指针,指向存放选项待设置的新值的缓冲区
optlen:optval的大小


//示例
int recv_size = 2 * 1024 * 1024;    //设置为4M
setsockopt(s,SOL_SOCKET, SO_RCVBUF, (const char *)&recv_size,sizeof(recv_size));  

(2)recvfrom()接收到数据之后处理速度太慢

[1] 分析:

  • UDP无需真正的缓冲区,不必保存应用进程的数据拷贝

    • 这就对数据处理的实时性提出了很高要求
  • recvfrom()接收速率并不是系统受限因素

    • recvfrom()处理速度是由CPU速度决定的(看到过这种说法,待验证),如果线程正常调用,几百Mbps的速度该函数肯定能跟上
  • 数据处理是速度受限因素之一

    • 程序在recvfrom接收到数据之后还进行了封装处理,即数据接收和数据处理是绑定的,处理速度跟不上接收速度(渲染速度跟不上socket接收速度)
  • 线程挂起再唤醒耗时受限速度之二

    • 尽管由CPU决定的recvfrom接收速度足够快,但如果接收数据线程从挂起再到唤醒接收数据,这个过程耗时可达数百毫秒

[2] 解决方法:

  • 数据处理速度受限:数据接收和数据处理分离

    • 接收数据单独存储,然后直接返回,保证recvfrom不丢数据或超时
    • 数据处理由其他函数或线程独立完成
  • 线程响应速度受限:保持线程一直在运行或监听状态

    • 因为数据接收和处理函数都在同一线程,可将数据接收和处理从逻辑上分开
    • 如果不在统一线程,由于数据到了再起线程速度过慢,可考虑使用线程池技术

[3] 解决步骤:

  • recvfrom和数据处理函数不再顺序执行一次只处理一个包。
  • 逻辑上分离数据接收和处理:

    • recvfrom负责接收数据并存储,设置单独计数1
    • 数据处理函数负责从从存储中拿数据并处理,设置单独计数2
  • 抓包线程一直处于运行状态:while

    • 数据处理可以等待唤醒
    • 但数据接收需要一直进行,否则难免丢包

补充:TCP缓冲区查看和修改命令

  • TCP接收缓冲区大小

    • TCP接收缓冲区默认值:cat /proc/sys/net/ipv4/tcp_rmem

      • 本系统:87380,约85K
    • TCP接收缓冲区最大值:cat /proc/sys/net/core/rmem_max ,TCP最大可设置值的一半(与UDP同)

      • 本系统:212992 = 208K,即最大值425984 = 416K。
      • 已被我修改为:3145728 = 3M,即最大值6291456 = 6M
  • TCP接收缓冲区最小值:sysctl -a | grep rmem

    • 本系统:net.ipv4.udp_rmem_min = 4096 = 2K
  • 通用命令:cat /proc/sys/net/ipv4/tcp_rmem

    • 4096 87380 6291456,依次为最小值、默认值、最大值

注:通过cat /proc/sys/net/ipv4/tcp_wmem命令和cat /proc/sys/net/core/wmem_max命令得出的TCP发送缓冲区最大值不一致,我觉得应该以cat /proc/sys/net/ipv4/tcp_wmem为准,即最大值为4M。

GitHub 加速计划 / li / linux-dash
10.39 K
1.2 K
下载
A beautiful web dashboard for Linux
最近提交(Master分支:2 个月前 )
186a802e added ecosystem file for PM2 4 年前
5def40a3 Add host customization support for the NodeJS version 4 年前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐