【Network】UDP 大包怎么发? MTU怎么设置?
这里主要用UDP来发送视频,当发送的数据大于1500时分包发送,保证每包小于1500.
发送好办,分割后循环发就可以了,关键是接收时的处理。
先做一下处理的方法 :
发送时每包上面加上标识,比如RTP的做法是加时间戳,SSRC,媒体类型还有结束标识。简单参考一下,我们也加上一些标识(直接拿RTP头也可以, 不过我们的目标是更简洁一些)。另外,我们的目的和RTP稍有不同,UDP库当时设计是传输数据,而不关心数据的内容是什么。这样,简单一化,包头第一个INT定义为类型,第二个INT为序号,第三个为结束标志,之后是数据长度和数据内容。
代码演示:
int CUDPSession::SplitData(char* pBuff, uint32_t nLen)
{
int nBlockNum = nLen / UDP_BLOCK_SIZE;
if (nLen % UDP_BLOCK_SIZE != 0)
{
nBlockNum++;
}
int sendlen = 0;
for (int i = 0; i < nBlockNum; i++)
{
int poayload_size = UDP_BLOCK_SIZE;
char* payload = pBuff + UDP_BLOCK_SIZE * (i);
if (nLen - UDP_BLOCK_SIZE * (i) < UDP_BLOCK_SIZE)
poayload_size = nLen - UDP_BLOCK_SIZE * (i);
CPackOut* pack = new CPackOut;
(*pack) << PACK_TYPE_DATA;
(*pack) << m_nFrameIndex;
if (i == nBlockNum - 1)
{
(*pack) << 1;
}
else
{
(*pack) << 0;
}
(*pack) << poayload_size;
(*pack).SetBuffer(payload, poayload_size);
int ret = SendPacket(pack, m_destIP, m_destPort);
printf("SendPacket ret = %d\n", ret);
sendlen += ret;
delete pack;
pack = NULL;
}
return sendlen;
}
发送端就这么简单。
下面详细说一下接收端:
因为UDP是不可靠的,不保证数据帧一定正常到达,即使收到,顺序也可能发生变化,比如先发的后到,当然丢包的可能最大,乱序的情况比较少。
正常的处理方法一般这样:
假设一个端口只接收固定一个对方数据源,这样,收到一个数据包放到缓冲里,然后在缓冲里根据帧的序号排序(每一帧的大序号是相同的,自己可以给每一个小片加上小序号,包头里可以加上本次数据帧一共分多少片,收到一片就统计一下,判断是否收齐)。 当收齐后,这个帧去掉包头回调给上层。当在一定时间内该帧数据还没有收齐,就说明传输过程有丢包了,把已收到的都丢掉就可以。
当上层的应该收到回调的数据后,可以进行解码播放。不过在解码之前,先判断一下帧序列是否连续。做为视频数据,
如果中间有缺少的,就把这一序列都丢掉,直到下一个I帧。每个帧的序号,最好收发之间协商好,在发送的时候带上。
如果把上面整个过程都实现,完全自己写的话,是需要几天的时间。不过,从很多RTP开源库里发现,处理的都非常简单,很多都没有管乱序情况,简单地来一份数据就向缓冲里追加一份,直到发现mark为1。我们这里做为简单使用的项目,也采用了这种简单方法,先把功能完成,之后有时间再来优化。
简单的重组代码:
int CUDPSession::Reassemble(CPackIn& pack, uint32_t ip, uint32_t port)
{
int nSeq = 0;
int nMark = 0;
int nLen = 0;
pack >> nSeq;
pack >> nMark;
pack >> nLen;
if (m_nRecvFrameIndex != nSeq)
{
if (m_buffer)
{
evbuffer_free(m_buffer);
m_buffer = NULL;
}
m_nRecvFrameIndex = nSeq;
}
if (m_buffer == NULL)
{
m_buffer = evbuffer_new();
}
char* pBuf = 0;
int nSize;
pack.GetBuffer(pBuf, nSize);
evbuffer_add(m_buffer, pBuf, nSize);
if (nMark == 1)
{
//回调
if (m_pCB)
{
m_pCB(m_udpIO.m_handle, (char*)(m_buffer->buffer), m_buffer->off, ip, port,
m_pParam);
}
evbuffer_free(m_buffer);
m_buffer = NULL;
}
return 0;
}
程序里使用的evbuffer,是从libevent里面拿来的,主要用来处理数据缓冲,非常好用,效率也很好,见evbuffer.h和buffer.cpp。
完整代码在git上,这次实现的功能是:本机UDP bind5500端口-->摄像机采集-->编码-->发送给本机的5500端口-->收到后再解码--> 显示。
发送的代码:m_Sess.Send((char*)pData, nLen, inet_addr("127.0.0.1"), 5500);
这个程序可以分别运行在两台机器上,一台是发送,另一台是接收。发送方只要把上面这一句里面的127.0.0.1换上你目标的ip,另一台机器就可以接收并解码了。
本文结束后,完整的客户端功能基本就差不多了,下一步开始完成server端的stun, 协商穿透, 实p2p和中转视频。
另补充一下,如果发送的是int类型的数据,一般应该用htonl,htons和ntohl,ntohs转换一下。这里的代码暂时没有用,以后会完善的。如果自己写代码应该注意。
https://github.com/sxcong/rttim
参考资料
- java - Which is the best approach to send large UDP packets in sequence - Stack Overflow
- networking - sending a big file in UDP in C - Stack Overflow
- sockets - is it possible to send very big data over UDP? - Stack Overflow
- c - How to send UDP packets of size greater than 64 KB - Stack Overflow
- udp - How to send large data using C# UdpClient? - Stack Overflow
- sockets - Python: Sending large object over UDP - Stack Overflow
- UDP and packets greater than 1500 bytes
- UDP and packets larger than 1500 bytes / Networking, Server, and Protection / Arch Linux Forums
- UDP主要丢包原因及具体问题分析
- UDP需要自己分包么 - C/C++-ChinaUnix.net
- 音视频聊天开发: 5 UDP发送视频数据的分包和重组 -sxcong-ChinaUnix博客
- Neutron 理解 (3): Open vSwitch + GRE/VxLAN 组网 - 极客头条 - CSDN.NET
- TCP/IP具体解释--TCP/UDP优化设置总结& MTU的相关介绍 - yxwkaifa - 博客园
【Network】UDP 大包怎么发? MTU怎么设置?的更多相关文章
- 路由器mtu值设置
MTU=最大传输单元 单位:字节 英文:Maximum Transmission Unit”我们平时上网时的各种操作,都是通过一个又一个“数据包”传输来实现的.而MTU指定了网络中可传输数据包的最大尺 ...
- 备忘:有MTU值设置不当导致的部分网站无法访问问题
如题,有时候突然weibo.com,webQQ等网站网络连接超时,怎么找也没得原因,今天管理电信的光猫,发现设置的MTU的1400,突然想起之前电脑和路由器上设置的MTU是1500,感觉可能是这个问题 ...
- FreeSWITCH小结:关于sip的UDP、TCP与MTU
1.关于SIP的UDP与MTU的关系 如果sip消息的大小超过了MTU,则有可能被网络中的某一节点分片,而UDP处理分片会有很大的问题,从而导致sip消息传输失败.要解决该问题的话,两种方案: 1)减 ...
- Network | UDP checksum
1. 校验和 ICMP,IP,UDP,TCP报头部分都有checksum(检验和)字段.IP 首部里的校验和只校验首部:ICMP.IGMP.TCP和UDP首部中的校验和校验首部和数据. UDP和TCP ...
- Linux 使用第三方邮箱发邮件的设置
mail命令在Ubuntu下是需要安装的,使用下条命令进行安装: sudo apt-get install heirloom-mailx 在CentOS 下安装则是: yum install mail ...
- SAP 采购订单行项目中科目分配被隐藏,发现行项目设置中显示字段长度为0
1.sm30 维护 视图 TCVIEW 修改对应字段的显示长度
- TCP/IP具体解释--TCP/UDP优化设置总结& MTU的相关介绍
首先要看TCP/IP协议,涉及到四层:链路层,网络层.传输层,应用层. 当中以太网(Ethernet)的数据帧在链路层 IP包在网络层 TCP或UDP包在传输层 TCP或UDP中的数据(Data)在应 ...
- [转帖]关于网络编程中MTU、TCP、UDP优化配置的一些总结
关于网络编程中MTU.TCP.UDP优化配置的一些总结 https://www.cnblogs.com/maowang1991/archive/2013/04/15/3022955.html 感谢原作 ...
- NB-IOT使用LWM2M移动onenet对接之MTU最大传输单元设置
1. 最近遇到的一个项目NB-IOT使用LWM2M移动onenet对接,要求设置传输的MTU,因此首先需要搞懂MTU是什么? 以太网的MTU值是1500 bytes,假设发送者的协议高层向IP层发送了 ...
随机推荐
- C#中TransactionScope的使用方法和原理
在.net 1.1的时代,还没有TransactionScope类,因此很多关于事务的处理,都交给了SqlTransaction和SqlConnection,每个Transaction是基于每个Con ...
- vtk工作流
要理解VTK的工作原理,首先应明确几个类型: 1.vtkSource(数据源) 这个就好比一个剧本里面的角色,让演员知道要演的是什么人物. 数据源有:vtkConeSource,vtkSphere ...
- silverlight 4.0 的oob模式下,调用com通过wmi重启自身进程 killself
silverlight目前开发的应用,想做到系统内注销后自动重新启动下 sllauncher.exe ,实现方式是通过WMI的COM接口,获取到当前应用的执行命令行(CommandLine):并通过s ...
- 软件工程(FZU2015)赛季得分榜,第一回合
目录 第一回合 第二回合 第三回合 第四回合 第五回合 第6回合 第7回合 第8回合 第9回合 第10回合 第11回合 积分规则 积分制: 作业为10分制,练习为3分制:alpha30分: 团队项目分 ...
- ipvsadm命令
NAME ipvsadm - Linux Virtual Server administration SYNOPSIS ipvsadm -A|E -t|u|f service-address [-s ...
- haproxy实现自定义错误页面的内容
现在利用haproxy实现自定义的haproxy的错误页面 我们现在实现自定义错误页面有以下的方法: 一种是自定义错误页面 haproxy.conf defaults errorfile 404 /e ...
- Python学习 过程中零散知识点的总结
自学资料比较零碎,本文是对在Python学习过程中积累的零零散散的知识点的总结 ============================================================ ...
- c#.NET微信自定义菜单
private void customMenu() { //获取access_token string access_token = GetAccessToken(); StringBuilder s ...
- 关于获取、设置css样式封装的函数入门版
<html> <head> <meta charset="UTF-8"> <title>CSS样式的获取和设置:简单版</ti ...
- TYVJ1338 QQ农场
时间: 1000ms / 空间: 131072KiB / Java类名: Main 背景 Sandytea前段时间沉迷于QQ农场中……一天夜里,他梦见来到好友X的农场上…… 描述 这个农场和游戏中略有 ...