目的
通往外网只有一个节点可以通,这个时候我们需要一个转发桥, 做一个udp 转发桥是非常简单的,简单而有用,我们使用asio c++ 来编程序
原理
使用asio 异步接收并且发送,在接收到以后,立刻在桥上转发,转发到外网地址。这里做演示,程序里面使用的是127.0.0.1.
代码
#define ASIO_STANDALONE
#include <iostream>
#include <cstdlib>
#include <iostream>
#include "asio.hpp"
using asio::ip::udp;
static const asio::ip::udp::endpoint s_end_point(asio::ip::address::from_string("127.0.0.1"), 6000);
class TicToc
{
public:
TicToc()
{
tic();
}
void tic()
{
start = std::chrono::system_clock::now();
}
double toc()
{
end = std::chrono::system_clock::now();
std::chrono::duration<double> elapsed_seconds = end - start;
start = end;
return elapsed_seconds.count() ;
}
private:
std::chrono::time_point<std::chrono::system_clock> start, end;
};
class server
{
private:
TicToc v_tock;
public:
server(asio::io_context& io_context, short port)
: socket_(io_context, udp::endpoint(udp::v4(), port))
{
do_receive();
}
int64_t v_i = 0;
uint64_t v_recvbytes = 0;
void do_receive()
{
socket_.async_receive_from(
asio::buffer(data_, max_length), sender_endpoint_,
[this](std::error_code ec, std::size_t bytes_recvd)
{
if (!ec && bytes_recvd > 0)
{
if (v_i == 0)
v_tock.tic();
v_recvbytes += bytes_recvd;
if (v_i++ > 100) //每一百个包统计一次
{
double res = v_tock.toc();
float m = v_recvbytes / res /1000.0f;
std::cout<<"time:"<<res<<" bytes:"<< v_recvbytes<<" recv byte every second:" << m <<"KB"<< std::endl;
v_i = 0;
v_recvbytes = 0;
}
do_send(bytes_recvd);
}
else
{
do_receive();
}
});
}
void do_send(std::size_t length)
{
socket_.async_send_to(
asio::buffer(data_, length), s_end_point,
[this](std::error_code /*ec*/, std::size_t /*bytes_sent*/)
{
do_receive();
});
}
private:
udp::socket socket_;
udp::endpoint sender_endpoint_;
udp::endpoint sender_to;
enum { max_length = 1500 };
char data_[max_length];
};
int main(int argc, char* argv[])
{
try
{
/*if (argc != 2)
{
std::cerr << "Usage: async_udp_echo_server <port>\n";
return 1;
}*/
asio::io_context io_context;
server s(io_context, 5000);
io_context.run();
}
catch (std::exception& e)
{
std::cerr << "Exception: " << e.what() << "\n";
}
return 0;
}
实验
写一个RTP发送程序,使用摄像头,摄像头转发到RTP地址的端口5000上,然后使用桥转接到外网IP地址,这里为了演示使用本机内网地址127.0.0.1,我们再使用vlc来从转发桥那里接收数据
我在程序里面使用了计数,每100个rtp包接收一次,大概每秒钟300Kbit-400Kbit左右,打开vlc接收数据
如图所示,vlc 正常接收到rtp程序数据以后正常播放。
这个程序的好处是无论是rtp还是gb28181 的ps流都可以正常转发。
扩展和迭代
后面再做tcp 转发,tcp的转发显然比udp 要复杂很多,,为这个程序还要制定一个http restful,里面还需要增加ssrc 等rtp包数据获取,http协议等待接收告诉服务程序需要转发哪一个rtp包, 等待下一篇吧