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. IIS7 ASP.NET 未被授权访问所请求的资源

    IIS7 ASP.NET 未被授权访问所请求的资源 ASP.NET 未被授权访问所请求的资源.请考虑授予 ASP.NET 请求标识访问此资源的权限. ASP.NET 有一个在应用程序没有模拟时使用的基 ...

  2. FreePascal经典资料

    ------------------------------------------------------------------------ 这是每个版本的changelog: http://bu ...

  3. 美丽渐变色的Form

    一直都非常喜欢渐变色的界面,但是没想到漂亮的渐变Form原来这么简单...实在是没想到...看来我不仅技术水平低,脑袋里的创意也是空空如也... --------------------------- ...

  4. 开放api设计资料收藏

    REST设计 api设计范例http://www.ibm.com/developerworks/cn/web/1103_chenyan_restapi/index.html?ca=drs http:/ ...

  5. 分布式缓存系统热点key解决方案

    1. 读访问量高(万级别及以上),读访问远大于写访问 这种情况典型的业务场景之一就是存储配置信息,配置信息一般数据量较小,更新频率低,但读访问量高.这种场景有两种方法优化: a. 对同一个key存储多 ...

  6. 【USACO】【section1.1】Your Ride Is Here

    以前的账号忘记了,只能从头了. 入门题不解释,就是sumg和sumc初始值置1不能置0.开始享用一个循环计算出sumg和sumc,其实两个数组最大程度为6,节省不了什么时间. /*ID:Moment1 ...

  7. YTU 2602: 熟悉题型——类设计( 矩形类定义【C++】)

    2602: 熟悉题型--类设计( 矩形类定义[C++]) 时间限制: 1 Sec  内存限制: 128 MB 提交: 183  解决: 119 题目描述 定义一个矩形类,数据成员包括左下角和右上角坐标 ...

  8. leetcode:Power of Two

    Given an integer, write a function to determine if it is a power of two. 分析:这道题让我们判断一个数是否为2的次方数(而且要求 ...

  9. 【Todo】字符串相关的各种算法,以及用到的各种数据结构,包括前缀树后缀树等各种树

    另开一文分析字符串相关的各种算法,以及用到的各种数据结构,包括前缀树后缀树等各种树. 先来一个汇总, 算法: 本文中提到的字符串匹配算法有:KMP, BM, Horspool, Sunday, BF, ...

  10. 如何将SD卡或者TF卡的debian系统刷入nand

    1. 在windows端下载辅助文件: a) http://dl.cubieforums.com/loz/boot_partition/bootloader/cubie_nand_uboot_part ...