boost的asio接收单路大数据量udp包的方法
2017-03-17 11:26
211 查看
开发windows客户端接收RTP视频流,当h264视频达到1080P 60fps的时候,按包来调用recvfrom的函数压力比较大,存在丢包的问题,windows的完成端口的性能效果当然可以解决这个问题,而boost的asio在windows上是基于完成端口来开发的,所以采用boost的asio和环形缓冲区的方法,可以解决接收单路大数据量udp包中丢包的问题。
需要引入的头文件为:
#include "CircledBuffer.h"
#include <iostream>
#include <boost/asio.hpp>
#include <boost/bind.hpp>其中CircledBuffer.h是自定义的缓冲区的类,之后会有介绍,boost的两个文件是asio必需的两个文件。
需要定义的全局变量为:
using boost::asio::ip::udp;
boost::asio::io_service service;
boost::asio::ip::udp::socket sock(service);
boost::asio::ip::udp::endpoint sender_ep;
CircledBuffer readBuffer;
PacketBuffer* packet;其中io_service是用来标示启动的,后面会调用run。sock和endpoint类似于描述符和sockaddr_in的关系。CircledBuffer和PacketBuffer*,是自定义缓冲区。
主函数为:
int main(int argc, char* argv[]) {
boost::asio::ip::udp::endpoint ep( boost::asio::ip::address::from_string("192.168.1.206"),
9002);
sock.open(ep.protocol());
sock.set_option(boost::asio::ip::udp::socket::reuse_address(true));
boost::asio::socket_base::receive_buffer_size recv_option(8*65534);
sock.set_option(recv_option);
sock.bind(ep);
packet = readBuffer.GetLast();
sock.async_receive_from(boost::asio::buffer(packet->data, packet->bufferSize), sender_ep, &on_read);
service.run();
}
初始化ep和sock,其中udp接收的数量比较大的话,需要设定receive_buffer_size,然后bind,设置接受buffer为packet。
介绍一下async_receive_from函数,它有三个参数,分别为接收的buffer,远端的ep,注意与本端的ep不同,远端的ep不用初始化设置,再就是buffer收满后的回调函数。
回调函数的内容是:
void on_read(const boost::system::error_code & err, std::size_t
read_bytes) {
std::cout << "read: " << read_bytes << std::endl;
readBuffer.MoveNext();
packet= readBuffer.GetLast();
sock.async_receive_from(boost::asio::buffer(packet->data, packet->bufferSize), sender_ep, &on_read);
}与main函数的接收部分一致,这里用了不断的自身回调,来实现while recvfrom的功能。
补充说一句,用申请好的CircledBuffer,便于后期的多线程或者异步strand的处理,而不阻塞接收。
缓冲区类的代码:
头文件:
#ifndef CIRCLED_BUFFER_H
#define CIRCLED_BUFFER_H
#include <memory.h>
#include <boost/atomic.hpp>
#define CIRCLED_BUFFER_SIZE 300
#define BUFFER_SIZE 2000
struct PacketBuffer
{
PacketBuffer(){bufferSize=BUFFER_SIZE;dataSize=0;}
unsigned int bufferSize;
unsigned int dataSize;
char data[BUFFER_SIZE];
PacketBuffer& operator=(PacketBuffer& other)
{
memcpy(data,other.data,other.dataSize);
dataSize = other.dataSize;
bufferSize = other.bufferSize;
return *this;
}
};
class CircledBuffer
{
public:
CircledBuffer(unsigned int bufSize=CIRCLED_BUFFER_SIZE);
public:
~CircledBuffer(void);
PacketBuffer* GetAt(unsigned int idx){return &packets[idx];}
PacketBuffer* GetLast()
{
return GetAt(writeIndex.load(boost::memory_order_consume));
};
void MoveNext()
{
unsigned int idx = writeIndex.load(boost::memory_order_relaxed);
writeIndex.store((idx+1)%bufferSize,boost::memory_order_release);
};
unsigned int GetLastIndex(){return writeIndex.load(boost::memory_order_consume);};
unsigned int GetSize(){return bufferSize;};
protected:
boost::atomic<unsigned int> writeIndex;
unsigned int bufferSize;
PacketBuffer* packets;
};
#endif
缓冲区类的构造函数与析构函数
#include "CircledBuffer.h"
CircledBuffer::CircledBuffer(unsigned int bufSize)
:bufferSize(bufSize),
writeIndex(0)
{
packets = new PacketBuffer[bufSize];
}
CircledBuffer::~CircledBuffer(void)
{
delete []packets;
}
源代码下载链接
需要引入的头文件为:
#include "CircledBuffer.h"
#include <iostream>
#include <boost/asio.hpp>
#include <boost/bind.hpp>其中CircledBuffer.h是自定义的缓冲区的类,之后会有介绍,boost的两个文件是asio必需的两个文件。
需要定义的全局变量为:
using boost::asio::ip::udp;
boost::asio::io_service service;
boost::asio::ip::udp::socket sock(service);
boost::asio::ip::udp::endpoint sender_ep;
CircledBuffer readBuffer;
PacketBuffer* packet;其中io_service是用来标示启动的,后面会调用run。sock和endpoint类似于描述符和sockaddr_in的关系。CircledBuffer和PacketBuffer*,是自定义缓冲区。
主函数为:
int main(int argc, char* argv[]) {
boost::asio::ip::udp::endpoint ep( boost::asio::ip::address::from_string("192.168.1.206"),
9002);
sock.open(ep.protocol());
sock.set_option(boost::asio::ip::udp::socket::reuse_address(true));
boost::asio::socket_base::receive_buffer_size recv_option(8*65534);
sock.set_option(recv_option);
sock.bind(ep);
packet = readBuffer.GetLast();
sock.async_receive_from(boost::asio::buffer(packet->data, packet->bufferSize), sender_ep, &on_read);
service.run();
}
初始化ep和sock,其中udp接收的数量比较大的话,需要设定receive_buffer_size,然后bind,设置接受buffer为packet。
介绍一下async_receive_from函数,它有三个参数,分别为接收的buffer,远端的ep,注意与本端的ep不同,远端的ep不用初始化设置,再就是buffer收满后的回调函数。
回调函数的内容是:
void on_read(const boost::system::error_code & err, std::size_t
read_bytes) {
std::cout << "read: " << read_bytes << std::endl;
readBuffer.MoveNext();
packet= readBuffer.GetLast();
sock.async_receive_from(boost::asio::buffer(packet->data, packet->bufferSize), sender_ep, &on_read);
}与main函数的接收部分一致,这里用了不断的自身回调,来实现while recvfrom的功能。
补充说一句,用申请好的CircledBuffer,便于后期的多线程或者异步strand的处理,而不阻塞接收。
缓冲区类的代码:
头文件:
#ifndef CIRCLED_BUFFER_H
#define CIRCLED_BUFFER_H
#include <memory.h>
#include <boost/atomic.hpp>
#define CIRCLED_BUFFER_SIZE 300
#define BUFFER_SIZE 2000
struct PacketBuffer
{
PacketBuffer(){bufferSize=BUFFER_SIZE;dataSize=0;}
unsigned int bufferSize;
unsigned int dataSize;
char data[BUFFER_SIZE];
PacketBuffer& operator=(PacketBuffer& other)
{
memcpy(data,other.data,other.dataSize);
dataSize = other.dataSize;
bufferSize = other.bufferSize;
return *this;
}
};
class CircledBuffer
{
public:
CircledBuffer(unsigned int bufSize=CIRCLED_BUFFER_SIZE);
public:
~CircledBuffer(void);
PacketBuffer* GetAt(unsigned int idx){return &packets[idx];}
PacketBuffer* GetLast()
{
return GetAt(writeIndex.load(boost::memory_order_consume));
};
void MoveNext()
{
unsigned int idx = writeIndex.load(boost::memory_order_relaxed);
writeIndex.store((idx+1)%bufferSize,boost::memory_order_release);
};
unsigned int GetLastIndex(){return writeIndex.load(boost::memory_order_consume);};
unsigned int GetSize(){return bufferSize;};
protected:
boost::atomic<unsigned int> writeIndex;
unsigned int bufferSize;
PacketBuffer* packets;
};
#endif
缓冲区类的构造函数与析构函数
#include "CircledBuffer.h"
CircledBuffer::CircledBuffer(unsigned int bufSize)
:bufferSize(bufSize),
writeIndex(0)
{
packets = new PacketBuffer[bufSize];
}
CircledBuffer::~CircledBuffer(void)
{
delete []packets;
}
源代码下载链接
相关文章推荐
- boost的asio接收单路大数据量udp包的方法
- Android使用wifi通过UDP协议发送广播数据包给PC接收不到问题解决方法
- android模拟器接收不到UDP数据包解决方法
- boost::asio编程-同步UDP
- boost::asio 之udp协议的使用
- Boost.Asio C++ Chapter_3 udp_sync
- boost::asio学习 - 常用方法总结
- boost::asio 之udp协议的使用
- boost::asio使用UDP协议通信源码实现
- Boost.Asio 异步执行方法,post()\dispach()\wrap().
- [boost::asio学习 03]用ASIO编写UDP通信程序
- boost.asio防止恶意空连接的方法
- Boost的UDP接收server示例
- boost::asio 之udp协议的使用
- boost::asio学习之[五]运行udp tcp服务
- UDP boost::asio的实现
- Win7下MingW编译Boost Asio程序的错误解决方法
- 网络编程一:概述、网络模型、TCP\UDP、Socket套接字、UDP发送和接收、UDP聊、阻塞式方法
- 关于在mac 下面#include<boost/asio.hpp>报错的解决方法
- 接收udp组播信息的方法