这里主要用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优化设置总结&amp; MTU的相关介绍 - yxwkaifa - 博客园

【Network】UDP 大包怎么发? MTU怎么设置?的更多相关文章

  1. 路由器mtu值设置

    MTU=最大传输单元 单位:字节 英文:Maximum Transmission Unit”我们平时上网时的各种操作,都是通过一个又一个“数据包”传输来实现的.而MTU指定了网络中可传输数据包的最大尺 ...

  2. 备忘:有MTU值设置不当导致的部分网站无法访问问题

    如题,有时候突然weibo.com,webQQ等网站网络连接超时,怎么找也没得原因,今天管理电信的光猫,发现设置的MTU的1400,突然想起之前电脑和路由器上设置的MTU是1500,感觉可能是这个问题 ...

  3. FreeSWITCH小结:关于sip的UDP、TCP与MTU

    1.关于SIP的UDP与MTU的关系 如果sip消息的大小超过了MTU,则有可能被网络中的某一节点分片,而UDP处理分片会有很大的问题,从而导致sip消息传输失败.要解决该问题的话,两种方案: 1)减 ...

  4. Network | UDP checksum

    1. 校验和 ICMP,IP,UDP,TCP报头部分都有checksum(检验和)字段.IP 首部里的校验和只校验首部:ICMP.IGMP.TCP和UDP首部中的校验和校验首部和数据. UDP和TCP ...

  5. Linux 使用第三方邮箱发邮件的设置

    mail命令在Ubuntu下是需要安装的,使用下条命令进行安装: sudo apt-get install heirloom-mailx 在CentOS 下安装则是: yum install mail ...

  6. SAP 采购订单行项目中科目分配被隐藏,发现行项目设置中显示字段长度为0

    1.sm30 维护 视图 TCVIEW 修改对应字段的显示长度

  7. TCP/IP具体解释--TCP/UDP优化设置总结&amp; MTU的相关介绍

    首先要看TCP/IP协议,涉及到四层:链路层,网络层.传输层,应用层. 当中以太网(Ethernet)的数据帧在链路层 IP包在网络层 TCP或UDP包在传输层 TCP或UDP中的数据(Data)在应 ...

  8. [转帖]关于网络编程中MTU、TCP、UDP优化配置的一些总结

    关于网络编程中MTU.TCP.UDP优化配置的一些总结 https://www.cnblogs.com/maowang1991/archive/2013/04/15/3022955.html 感谢原作 ...

  9. NB-IOT使用LWM2M移动onenet对接之MTU最大传输单元设置

    1. 最近遇到的一个项目NB-IOT使用LWM2M移动onenet对接,要求设置传输的MTU,因此首先需要搞懂MTU是什么? 以太网的MTU值是1500 bytes,假设发送者的协议高层向IP层发送了 ...

随机推荐

  1. C++中指针数组的分配与释放

    C++中可用new和delete关键字分配和释放内存,但是如果遇到指针数组(或指向指针的指针),分配和释放必须慎重,不然容易造成内存泄漏. 下面用一段代码给出如何使用指向指针的指针来分配和释放内存: ...

  2. 积极主动敲代码,使用Junit学习Java程序设计

    积极主动敲代码,使用JUnit学习Java 早起看到周筠老师在知乎的回答软件专业成绩很好但是实际能力很差怎么办?,很有感触. 从读大学算起,我敲过不下100本程序设计图书的代码,我的学习经验带来我的程 ...

  3. C#进阶系列——DDD领域驱动设计初探(二):仓储Repository(上)

    前言:上篇介绍了DDD设计Demo里面的聚合划分以及实体和聚合根的设计,这章继续来说说DDD里面最具争议的话题之一的仓储Repository,为什么Repository会有这么大的争议,博主认为主要原 ...

  4. cookie学习指南

    一.什么是cookie cookie也叫HTTP cookie,最初是用来客户端和服务器端进行会话用的,由于HTTP是一种无状态的协议,为了维持用户和跟踪用户信息,所以引入了cookie和sessio ...

  5. canvas弹动

    弹动,和缓动类似,不过是在终点前反复运动几次达到反弹的效果,具体的算法就是用目标点(target)和物体(mouse)的距离乘以系数累加至坐标上,这样就会有简单的弹动效果,但是一般的弹动效果都是慢慢变 ...

  6. 前端代码目录结构、常用 piugin、元素补充用法及其它注意事项

    目录结构: app:  .html文件 css: .css文件 script: 脚本文件 plugin: 插件  (此目录放一些通用代码) 注意事项: 1.在IE浏览器下img会显示边框,为了保证兼容 ...

  7. raw_input和input的区别

    raw_input的返回类型是String类型 input的返回类型是int类型 >>> rawinput = raw_input("raw_input:") r ...

  8. 数据结构图文解析之:队列详解与C++模板实现

    0. 数据结构图文解析系列 数据结构系列文章 数据结构图文解析之:数组.单链表.双链表介绍及C++模板实现 数据结构图文解析之:栈的简介及C++模板实现 数据结构图文解析之:队列详解与C++模板实现 ...

  9. Java基础-包名和文件夹名字必须对应

    .java文件夹中的包名必须与物理文件夹的对应. 如果修改包名或者文件夹名,双方都需要同时更新.

  10. Oracle表格建立

    Oracle学习第一天:学习了如何在网页上建立表空间,以及在关联性表格上建立表格,填充表格,学习了如何建立自己的表空间.效果如下: