1,udp丢包

困扰几天的udp内网传输部分终于做通了,解决的关键就在于setsockopt的调用,设置接收缓冲。

遇到的问题是这样的,主机端发送udp数据包:

应用层的包大小为1452byte大小,这样拆包是根据以太网的MTU为1500字节而考虑的(当然外网状态下并不一定就是以太网网络,路由MTU可能更加小),因为在网络层和传输层还有8byte的udp包头和20byte的ip包头,所以以太网帧大小为1452+8+20 = 1480byte。

主机端(linux)现在接了11路视频数据,发送的数据量还是很大的,但经过测试,数据是可以发送出去的,发送端没有问题。我在客户端用一个线程专门接包,然后进行处理,可总是处理不过来,当连接路数比较多的时候,即码流增大时,出现接收不过来的情况。开始以为是主机端问题,进行写文件测试发现主机端完全可以承受11路数据的发送(udp数据包),而接收端对每个部分都进行了详细测试,都没有效率问题而影响接包的处理,最后将目光放在了接收缓冲的问题上,经过查证,windows程序默认的udp socket的接收和发送缓冲都是8kB, 而将接收缓冲调大后,马上解决了丢包现象:

int n = 512*1024;  setsockopt(m_hRcvSock, SOL_SOCKET, SO_RCVBUF, (const char*)&n, sizeof(n));

可见对于一般而言,8kB是足够了,但是对于要接收大量数据时,默认的接收缓冲(udp)是不够的。需要进行手工设置,否则会造成包的丢失从而数据错误。之所以一开始没有想到这上面是因为我们原来的网络是用tcp进行的视频传输(暂时没有对tcp的接收和发送缓冲进行查证),而tcp状态下我们可以很好的在内网传输16路的实时视频数据,故以为在发送和接收上udp和tcp一样不存在瓶颈问题。后查得tcp是会进行流量控制的,下面是一段摘抄:

说到流量控制,不得不提到TCP的另一个重要概念-—窗口。窗口表示了接收主机能接收的最大数据量,并且,窗口大小是随着主机资源和主机当前正在接收多少个传输数量而变化的。主机将窗口字段用于流量控制,也就是说,流量控制是TCP窗口的一个功能。TCP采用流量控制管理进入接收主机缓冲区的数据流量。如果发送主机传输数据的速度比接收主机处理数据的速度更快以至接收主机缓冲区已满不能处理更多的数据时,则接收主机就会请求发送主机降低数据发送速度直到接收主机可以接收更多的数据为止;相反,如果接收主机能够处理更多的数据,则会请求发送主机加快数据的发送速度,这就是流量控制的用途,它保证了数据在传输的过程中完整的传送到接收主机。

可以看出由于tcp是基于连接的,所以其在传输过程中会牺牲很多来进行传输的保证,故即使速度下降也会保证接收端的有序和正确接收。而udp是非连接的,其发送后不进行任何处理在保证数据的传输,高效但无保障,一切检验和有序以及完整处理均需要应用层来完成(这让人想起了RTCP)。

2,绑定失败

还有一个setsockopt的选相是SO_REUSEADDR, 今天在绑定一个地址来进行侦听的时候,处理上是每来一个连接,便侦听其地址发送来的udp端口,由于要多次绑定,而开始时总遇到地址重复的错误,后来一查发现,同一个地址进行端口绑定,好像有一个时间间隔限制,该限制以内不能重复绑定,故我进行了以上的设置,就可以多次重复绑定了~

经过查证,我遇到的是地址使用错误的问题:

使用 bind API 函数来绑定一个地址(一个接口和一个端口)到一个套接字端点。可以在服务器设置中使用这个函数,以便限制可能有连接到来的接口。也可以在客户端设置中使用这个函数,以便限制应当供出去的连接所使用的接口。bind最常见的用法是关联端口号和服务器,并使用通配符地址(INADDR_ANY),它允许任何接口为到来的连接所使用。bind 普遍遭遇的问题是试图绑定一个已经在使用的端口。该陷阱是也许没有活动的套接字存在,但仍然禁止绑定端口(bind 返回EADDRINUSE),它由 TCP 套接字状态 TIME_WAIT 引起。该状态在套接字关闭后约保留 2 到 4 分钟。在 TIME_WAIT 状态退出之后,套接字被删除,该地址才能被重新绑定而不出问题。

等待 TIME_WAIT 结束可能是令人恼火的一件事,特别是如果您正在开发一个套接字服务器,就需要停止服务器来做一些改动,然后重启。幸运的是,有方法可以避开 TIME_WAIT 状态。可以给套接字应用 SO_REUSEADDR 套接字选项,以便端口可以马上重用。

同样,我在每次UDP侦听socket使用完毕后,使用closesocket将使用的socket清除,这样手动释放后,不需要再进行setsockopt的设置也可以重复绑定了。从此可看出,原本我创建的socket为局部的,但其释放好像并不同与普通的c变量的释放方式,故在函数下次调用时候,出现地址重复的错误,而手动清除是保险的。该错误在linux和windows平台均有,但好像windows再调用setsockopt后,socket接收有异常,偶尔接收不了UDP报文,而linux下没有此种现象。

什么会导致udp丢包呢,我这里列举了如下几点原因:

1.调用recv方法接收端收到数据后,处理数据花了一些时间,处理完后再次调用recv方法,在这二次调用间隔里,发过来的包可能丢失。对于这种情况可以修改接收端,将包接收后存入一个缓冲区,然后迅速返回继续recv。

2.发送的包巨大丢包。虽然send方法会帮你做大包切割成小包发送的事情,但包太大也不行。例如超过30K的一个udp包,不切割直接通过send方法发送也会导致这个包丢失。这种情况需要切割成小包再逐个send。

3.发送的包较大,超过mtu size数倍,几个大的udp包可能会超过接收者的缓冲,导致丢包。这种情况可以设置socket接收缓冲。以前遇到过这种问题,我把接收缓冲设置成64K就解决了。
int nRecvBuf=32*1024;//设置为32K
setsockopt(s,SOL_SOCKET,SO_RCVBUF,(const char*)&nRecvBuf,sizeof(int));

4.发送的包频率太快,虽然每个包的大小都小于mtu size 但是频率太快,例如40多个mut size的包连续发送中间不sleep,也有可能导致丢包。这种情况也有时可以通过设置socket接收缓冲解决,但有时解决不了。

5.发送的广播包或组播包在windws和linux下都接收正常,而arm上接收出现丢包。这个还不好解决,我的解决方法是大包切割成大小为1448的小包发送,每个包之间sleep 1毫秒,虽然笨,但有效。我这里mtu size为1500字节,减去udp包头8个字节,减去传输层几十个字节,实际数据位1448字节。
除此之外还可以试试设置arm操作系统缓冲:
//设置mtu size 1500最大
ifconfig eth0 mtu 1500
//查看接收缓冲最大和默认大小。
sysctl -A | grep rmem
//设置接收缓冲的最大大小
sysctl -w net.core.rmem_max=1048576
sysctl -w net.core.rmem_default=1048576
sysctl -w net.ipv4.udp_mem=1048576
sysctl -w net.ipv4.udp_rmem_min=1048576

6,局域网内不丢包,公网上丢包。这个问题我也是通过切割小包并sleep发送解决的。如果流量太大,这个办法也不灵了。

总之udp丢包总是会有的,如果出现了用我的方法解决不了,还有这个几个方法: 要么减小流量,要么换tcp协议传输,要么做丢包重传的工作

TCP/UDP常见问题小结的更多相关文章

  1. TCP&UDP协议小结

    TCP和UDP 传输层功能 网络安全 Tcp可靠性 Tcp流控 Tcp拥塞控制 Tcp运输连接管理 一个网页可能很大,一个数据包传不过来,就需要分段传输. 网络可能拥塞,某段可能丢失.那必须有人监管, ...

  2. 二十.Nginx反向代理、Nginx的TCP/UDP调度器、Nginx常见问题处理

    proxy client web1 web2 1.nginx反向代理   使用Nginx实现Web反向代理功能,实现如下功能:   后端Web服务器两台(web1 192.168.2.100 web2 ...

  3. Nginx反向代理,Nginx的TCP/UDP调度器以及Nginx常见问题处理

    nginx反向代理: 方案 使用4台RHEL7虚拟机,其中一台作为Nginx代理服务器,该服务器需要配置两块网卡,IP地址分别为192.168.4.5和192.168.2.5,两台Web服务器IP地址 ...

  4. 高性能 TCP/UDP/HTTP 通信框架 HP-Socket v4.1.1

    HP-Socket 是一套通用的高性能 TCP/UDP/HTTP 通信框架,包含服务端组件.客户端组件和 Agent 组件,广泛适用于各种不同应用场景的 TCP/UDP/HTTP 通信系统,提供 C/ ...

  5. TODO:Golang语言TCP/UDP协议重用地址端口

    TODO:Golang语言TCP/UDP协议重用地址端口 这是一个简单的包来解决重用地址的问题. go net包(据我所知)不允许设置套接字选项. 这在尝试进行TCP NAT时尤其成问题,其需要在同一 ...

  6. 高性能 TCP/UDP/HTTP 通信框架 HP-Socket v4.1.2

    HP-Socket 是一套通用的高性能 TCP/UDP/HTTP 通信框架,包含服务端组件.客户端组件和 Agent 组件,广泛适用于各种不同应用场景的 TCP/UDP/HTTP 通信系统,提供 C/ ...

  7. 高性能 TCP/UDP/HTTP 通信框架 HP-Socket v4.0.1

    HP-Socket 是一套通用的高性能 TCP/UDP/HTTP 通信框架,包含服务端组件.客户端组件和 Agent 组件,广泛适用于各种不同应用场景的 TCP/UDP/HTTP 通信系统,提供 C/ ...

  8. 高性能 TCP & UDP 通信框架 HP-Socket v3.5.3

    HP-Socket 是一套通用的高性能 TCP/UDP 通信框架,包含服务端组件.客户端组件和 Agent 组件,广泛适用于各种不同应用场景的 TCP/UDP 通信系统,提供 C/C++.C#.Del ...

  9. 高性能 TCP & UDP 通信框架 HP-Socket v3.5.2

    HP-Socket 是一套通用的高性能 TCP/UDP 通信框架,包含服务端组件.客户端组件和 Agent 组件,广泛适用于各种不同应用场景的 TCP/UDP 通信系统,提供 C/C++.C#.Del ...

随机推荐

  1. 一行代码设置TLabel.Caption的前世今生

    第零步,测试代码: procedure TForm1.Button1Click(Sender: TObject); begin Label1.Caption := 'Hello World'; end ...

  2. Java:多态性

    Java的多态性:发送消息给某个对象,让该对象自行决定响应何种行为. 通过将子类对象引用赋值给超类对象引用变量来实现动态方法调用. java的多态性要满足三个条件: 1.继承关系 2.在子类重写父类的 ...

  3. Spring Loaded is a JVM agent for reloading class file changes

    <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot ...

  4. [转载]TexturePacker 如何使用自带的加密功能及在cocos2dx中的使用

    在cocos2dx中使用纹理图集是非常节省资源的,在这里推荐 TexturePacker,而且 TexturePacker工具的加密接口也非常的好用,下面就来介绍一下... TexturePacker ...

  5. 【流媒体】 Android 实时视频编码—H.264硬编码

    [流媒體] Android 实时视频编码—H.264硬编码 SkySeraph Apr 4th 2012 Email:skyseraph00@163.com 1  硬编码 & 软编码 硬编码: ...

  6. 易犯的PHP小错误及相应分析

    变量声明如果在一条语句中声明一个变量,如下所示:$var = 'value'; 编译器首先会求出语句右半部分的值,恰恰正是语句的这一部分常常会引发错误.如果使用的语法不正确,就会出现解析错误. 解析错 ...

  7. POJ 1743 Musical Theme(后缀数组)

    题意:有n个数值,算出相邻两个值的差值,此时有n-1个值的序列,把这序列当做字符串的话,求最长重复子串,且这两个子串不能重叠. 分析:后缀数组解决.先二分答案,把题目变成判定性问题:判断是否存在两个长 ...

  8. C# winFrom 制作、打包、签名、发布Activex全过程

    注:转自园中 http://www.cnblogs.com/still-windows7/p/3148623.html 一.前言 最近有这样一个需求,需要在网页上面启动客户端的软件,软件之间的通信.调 ...

  9. 10.10 dos试验

    一. 实验目的 (1)认识DOS: (2)掌握命令解释程序的原理: (3)掌握简单的DOS调用方法: (4)掌握C语言编程初步. 二. 实验内容和要求 编写类似于DOS,UNIX的命令行解释程序 (1 ...

  10. oracle数据导入的常用命令

    oracle 中数据库完全导入导出:cmd命令行模式 oracle数据库cmdfile数据库服务器constraints Oracle数据导入导出imp/exp就相当于oracle数据还原与备份.ex ...