TCP/UDP常见问题小结
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常见问题小结的更多相关文章
- TCP&UDP协议小结
TCP和UDP 传输层功能 网络安全 Tcp可靠性 Tcp流控 Tcp拥塞控制 Tcp运输连接管理 一个网页可能很大,一个数据包传不过来,就需要分段传输. 网络可能拥塞,某段可能丢失.那必须有人监管, ...
- 二十.Nginx反向代理、Nginx的TCP/UDP调度器、Nginx常见问题处理
proxy client web1 web2 1.nginx反向代理 使用Nginx实现Web反向代理功能,实现如下功能: 后端Web服务器两台(web1 192.168.2.100 web2 ...
- Nginx反向代理,Nginx的TCP/UDP调度器以及Nginx常见问题处理
nginx反向代理: 方案 使用4台RHEL7虚拟机,其中一台作为Nginx代理服务器,该服务器需要配置两块网卡,IP地址分别为192.168.4.5和192.168.2.5,两台Web服务器IP地址 ...
- 高性能 TCP/UDP/HTTP 通信框架 HP-Socket v4.1.1
HP-Socket 是一套通用的高性能 TCP/UDP/HTTP 通信框架,包含服务端组件.客户端组件和 Agent 组件,广泛适用于各种不同应用场景的 TCP/UDP/HTTP 通信系统,提供 C/ ...
- TODO:Golang语言TCP/UDP协议重用地址端口
TODO:Golang语言TCP/UDP协议重用地址端口 这是一个简单的包来解决重用地址的问题. go net包(据我所知)不允许设置套接字选项. 这在尝试进行TCP NAT时尤其成问题,其需要在同一 ...
- 高性能 TCP/UDP/HTTP 通信框架 HP-Socket v4.1.2
HP-Socket 是一套通用的高性能 TCP/UDP/HTTP 通信框架,包含服务端组件.客户端组件和 Agent 组件,广泛适用于各种不同应用场景的 TCP/UDP/HTTP 通信系统,提供 C/ ...
- 高性能 TCP/UDP/HTTP 通信框架 HP-Socket v4.0.1
HP-Socket 是一套通用的高性能 TCP/UDP/HTTP 通信框架,包含服务端组件.客户端组件和 Agent 组件,广泛适用于各种不同应用场景的 TCP/UDP/HTTP 通信系统,提供 C/ ...
- 高性能 TCP & UDP 通信框架 HP-Socket v3.5.3
HP-Socket 是一套通用的高性能 TCP/UDP 通信框架,包含服务端组件.客户端组件和 Agent 组件,广泛适用于各种不同应用场景的 TCP/UDP 通信系统,提供 C/C++.C#.Del ...
- 高性能 TCP & UDP 通信框架 HP-Socket v3.5.2
HP-Socket 是一套通用的高性能 TCP/UDP 通信框架,包含服务端组件.客户端组件和 Agent 组件,广泛适用于各种不同应用场景的 TCP/UDP 通信系统,提供 C/C++.C#.Del ...
随机推荐
- photoshop:css3插件
CSS3PS是Photoshop 插件,用来将 PhotoShop 的图层如内阴影.内发光.阴影.外发光.图片圆角等效果转成用 CSS3 样式. 官方下载地址>> http://css3p ...
- PHP如何提取img标签属性
extract_attrib是一个提取的图像标签属性的PHP脚本函数,使用正则表达式方法提取. 当你想在HTML的img标签中提取图像数据,这非常有用. 如果你知道如何修改正则表达式,那么同样的功能进 ...
- iOS:地图:MapKit和CoreLocation
地图:MapKit和CoreLocation 简介: 现在很多的社交软件都引入了地图和定位功能,要想实现这2大功能,那就不得不学习其中的2个框架:MaKit和CoreLocation CoreLoca ...
- html 用图片代替重置按钮
提交时,若把按钮设置成图片提交特别方便只要 <input type="image" alt="点此提交" src="images/button. ...
- 51nod 1117 聪明的木匠 (贪心)
http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1117 跟挑战程序书上例题一样,将要切割的n断木板,分别对应二叉树树的叶子 ...
- leetcode:Coin Change
You are given coins of different denominations and a total amount of money amount. Write a function ...
- win7下搭建opengles2.0编程环境
原帖地址:http://sixgod.org/archives/72 1.下载AMD的OpenGL ES2.0的模拟器,地址: http://www.opengles-book.com/ESEmu ...
- orm 通用方法——GetOneModel 条件查询一个对象
数据连接层的方法封装成通用方法是很有必要,节省不必要的重复写代码. Golang的orm.xorm框架没有封装这些操作. 这里是一个查询单个对象的方法. 此处抛砖引玉,大家继续完善. 通用方法定义代码 ...
- HDU 3544 (不平等博弈) Alice's Game
切巧克力的游戏,想得还是不是太明白. 后者会尽量选前着切后其中小的一块来切,那么先手须尽量取中间来切. So?题解都是这么一句话,不知道是真懂了还是从别人那抄过来的. 后来找到一个官方题解,分析得比较 ...
- POJ 3468 (线段树 区间增减) A Simple Problem with Integers
这题WA了好久,一直以为是lld和I64d的问题,后来发现是自己的pushdown函数写错了,说到底还是因为自己对线段树理解得不好. 因为是懒惰标记,所以只有在区间分开的时候才会将标记往下传递.更新和 ...