I'm developing a tool which is analyzing video stream.
I've worked with a file, I generate the file with this socat command (that someone's given to me):
socat -u UDP4-RECV:1234,ip-add-membership=xxx.xxx.xxx.xxx:0.0.0.0 CREATE:temp.ts
But now I'd like to work directly with the UDP stream.
With this code, I've tried to read the first received block and write it on the console, but I don#t get anything - the program gets stuck...
void Decoder::open_udp_stream(std::string ip_adress)
{
boost::asio::io_service io_service;
udp::endpoint receiver_endpoint (boost::asio::ip::address::from_string("xxx.xxx.xxx.xxx"), 1234);
udp::socket socket(io_service);
socket.open(udp::v4());
boost::array<char, 128> recv_buf;
udp::endpoint sender_endpoint;
size_t len = socket.receive_from(boost::asio::buffer(recv_buf), sender_endpoint);
std::cout.write(recv_buf.data(), len);
}
What should I do to get the blocks from this IP, as with the socat command ?
This code is working (thanks David Schwarz)
void Decoder::open_udp_stream(std::string ip_adress)
{
boost::asio::io_service io_service;
boost::asio::ip::udp::socket socket_(io_service);
boost::asio::ip::udp::endpoint sender_endpoint;
// Create the socket so that multiple may be bound to the same address.
boost::asio::ip::udp::endpoint listen_endpoint(
boost::asio::ip::address::from_string("0.0.0.0"), 1234);
socket_.open(listen_endpoint.protocol());
socket_.set_option(boost::asio::ip::udp::socket::reuse_address(true));
socket_.bind(listen_endpoint);
// Join the multicast group.
socket_.set_option(
boost::asio::ip::multicast::join_group(boost::asio::ip::address::from_string("xxx.xxx.xxx.xxx")));
boost::array<char, BUF_SIZE> recv_buf;
size_t len = socket_.receive_from(boost::asio::buffer(recv_buf), sender_endpoint);
std::cout.write(recv_buf.data(), len);
}
Related
I'm trying to implement two-way multicast UDP communication using Boost.Asio.
Actually what I need is client-server architecture.
I used these tutorials and examples and modified them:
https://www.boost.org/doc/libs/1_71_0/doc/html/boost_asio/example/cpp11/multicast/receiver.cpp
https://www.boost.org/doc/libs/1_71_0/doc/html/boost_asio/example/cpp11/multicast/sender.cpp
https://www.boost.org/doc/libs/1_71_0/doc/html/boost_asio/example/cpp11/futures/daytime_client.cpp
https://www.boost.org/doc/libs/1_71_0/doc/html/boost_asio/tutorial/tutdaytime6.html
Futures daytime client and daytime server works perfectly fine, unless I use multicast address for it, which I have to. It just doesn't communicate.
I modified client's daytime function and server example's constructor to look like this:
Client:
void get_daytime(boost::asio::io_context& io_context,
const boost::asio::ip::address& listenAddress,
const boost::asio::ip::address& multicastAddress)
{
try
{
udp::socket socket(io_context);
boost::asio::ip::udp::endpoint listenEndpoint(listenAddress, multicastPort);
socket.open(listenEndpoint.protocol());
socket.set_option(boost::asio::ip::udp::socket::reuse_address(true));
socket.bind(listenEndpoint);
socket.set_option(boost::asio::ip::multicast::join_group(multicastAddress));
std::array<char, 1U> send_buf = {{ 0 }};
std::future<std::size_t> send_length =
socket.async_send_to(boost::asio::buffer(send_buf),
listenEndpoint,
boost::asio::use_future);
send_length.get();
std::array<char, 128U> recv_buf{};
udp::endpoint sender_endpoint;
std::future<std::size_t> recv_length =
socket.async_receive_from(
boost::asio::buffer(recv_buf),
sender_endpoint,
boost::asio::use_future);
std::cout.write(
recv_buf.data(),
recv_length.get()); // Blocks until receive is complete.
}
catch (std::system_error& e)
{
std::cerr << e.what() << std::endl;
}
}
Server:
udp_server(boost::asio::io_context& io_context,
const boost::asio::ip::address& listenAddress,
const boost::asio::ip::address_v4& multicastAddress)
: socket_(io_context)
{
boost::asio::ip::udp::endpoint listenEndpoint(listenAddress, multicastPort);
socket_.open(listenEndpoint.protocol());
socket_.set_option(boost::asio::ip::udp::socket::reuse_address(true));
socket_.bind(listenEndpoint);
socket_.set_option(boost::asio::ip::multicast::join_group(multicastAddress));
start_receive();
}
How should I modify the code in order to make it work over multicast? Thanks.
I found a solution to my problem. I didn't have to modify getDaytime() function, though my udp_server() constructor now looks like this:
udp_server(boost::asio::io_context& io_context)
: socket_(io_context, udp::endpoint(boost::asio::ip::make_address("0.0.0.0"), 60000))
{
socket_.set_option(boost::asio::ip::multicast::join_group(boost::asio::ip::make_address("239.192.0.1")));
start_receive();
}
I try to implement a simple http server with blocking sockets on Windows. Basically, I have a simple server that just write data to a socket when a network connection occurs before exit. The problem is that the last socket.send as no effect if I don't delay the process exit. Writing to this socket is supposed to block until all the data as been written.
I have tried to use the completion condition of write, to use the non_blocking method of the socket. I still get the same problem.
Note that the problem doesn't occur on Linux.
Here is the code:
#include <boost/asio.hpp>
int main(int argc, char *argv[]) {
char *address = "0.0.0.0";
char *port = "8180";
boost::asio::io_service io_service;
boost::asio::ip::tcp::acceptor acceptor(io_service);
boost::asio::ip::tcp::resolver resolver(io_service);
boost::asio::ip::tcp::resolver::query query(address, port);
boost::asio::ip::tcp::endpoint endpoint = *resolver.resolve(query);
acceptor.open(endpoint.protocol());
acceptor.bind(endpoint);
acceptor.listen();
boost::asio::ip::tcp::socket sock(io_service);
acceptor.accept(sock);
std::string body("Hello, World!");
sock.send(boost::asio::buffer(std::string("HTTP/1.1 200 OK\r\n")));
sock.send(boost::asio::buffer(std::string("Content-Length: ") + std::to_string(body.size()) + "\r\n\r\n"));
sock.send(boost::asio::buffer(body));
Sleep(1000); // The body would not be sent without this
return 0;
}
According to this post, on windows the send method will block only if the kernel runs out of socket buffers.
It also say that if the program is killed, the sockets are forcibly closed and the non sent data is discarded.
I wanted to add this as a comment but I don't have enough point, sorry about that.
I have a server running very heavy 3D simulations that I want to display in real time on a client machine. For now I am running my tests in localhost to get rid of the network brandwidth and latency issues, and I use boost::asio to stream my data (geometry) through the network.
I have to use tcp because I have to compress my geometry, split it into multiple packages and then send it through the network, and on the client, gather the packages to rebuild my archive, so network packages have to arrive in the good order.
This works pretty well, I can run my simulation and stream my data at ~90-120fps, depending on the quantity of data to stream, which is very good.
My problem is that sometimes, it suddenly takes ~1second for the socket to connect() on the client, and consequently as much time for the server's to accept(). This causes my simulation to stop being streamed randomly, and I can't find the problem.
I though the problem could come from some kind of buffer overflow on the socket, preventing the server to write more data as long as the client didn't read some, but it can't be that, since I have no latency between the client and the server, so the client reads the packages fast enough (as soon as they arrive, basically)
Here's a shortened piece of code for the server:
while (1)
{
//archive some data in a stringstream using boost::archive...
boost::asio::io_service ioservice;
tcp::acceptor acceptor(ioservice, tcp::endpoint(tcp::v4(), PORT));
boost::system::error_code ignored_error;
tcp::socket socket(ioservice);
acceptor.accept(socket);
gettimeofday(&m_tv, NULL);
accept += (m_tv.tv_usec - m_timer);
m_timer = m_tv.tv_usec;
size_t bytes_sent = boost::asio::write(socket, boost::asio::buffer(ss.str()), boost::asio::transfer_all(), ignored_error);
}
and on the client I get something like:
while (1)
{
boost::asio::io_service io_service;
tcp::resolver resolver(io_service);
tcp::resolver::query query(IP, PORT);
tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
tcp::resolver::iterator end;
tcp::socket socket(io_service);
boost::system::error_code error = boost::asio::error::host_not_found;
while (error && endpoint_iterator != end)
{
socket.close();
socket.connect(*endpoint_iterator++, error);
}
if (error)
throw boost::system::system_error(error);
while(1)
{
boost::array<char, 200000> buf;
ss.write(buf.data(), bytes_received);
boost::system::error_code error;
bytes_received = socket.read_some(boost::asio::buffer(buf), error);
if (error == boost::asio::error::eof)
break;
else if (error)
throw boost::system::system_error(error);
}
}
I create a socket every frame, which is probably the problem, but I couldn't find an easier way of telling my client that he finished reading the package. By closing the socket every frame, I send eof to the client who then knows that he can build the archive using the data retrieved.
Is there something I can do to avoid opening a socket every frame, without having to check the content of my packages to know the size of the data to retrieve?
I am using boost asio to create a test server to test an http client. This will run on the same machine as the client. Now what I want to do is create a server with a randomly assigned port. I have looked at this thread here: Using boost::asio is there a portable way to find out free port number but I'm frankly still a little baffled.
My code looks something like this:
boost::asio::io_service service;
tcp::acceptor acceptor(service);
unsigned short port(0);
tcp::endpoint endPoint(tcp::endpoint(tcp::v4(), port);
acceptor.open(endPoint.protocol());
acceptor.set_option(tcp::acceptor::reuse_address(true));
acceptor.bind(endPoint);
port = endPoint.port();
std::cout<<port<<std::endl; // prints 0
My thoughts were that by creating an endpoint with 'port 0' and then trying to bind to that port, it should cause an available port to be randomly assigned but this doesn't seem to be the case. Any idea what I'm doing wrong?
Cheers.
boost::asio::io_service service;
boost::asio::ip::tcp::acceptor acceptor(service);
unsigned short port(0);
boost::asio::ip::tcp::endpoint endPoint(tcp::endpoint(tcp::v4(), port);
acceptor.open(endPoint.protocol());
acceptor.set_option(tcp::acceptor::reuse_address(true));
acceptor.bind(endPoint);
m_acceptor.listen();
boost::asio::ip::tcp::endpoint le = acceptor.local_endpoint(); //THIS LINE SOLVES IT
port = le.port();
// port = endPoint.port(); // This is didn't work for me
Helpful answer
Similar question
You can shorten this by using a different constructor for the acceptor:
using boost::asio;
io_service service;
ip::tcp::acceptor acceptor(service, ip::tcp::endpoint(ip::tcp::v4(), 0));
unsigned short port = acceptor.local_endpoint().port();
This constructor calls open(), bind() and listen() on the acceptor.
Fixed. I needed to do:
boost::asio::io_service service;
tcp::acceptor acceptor(service);
unsigned short port(0);
tcp::endpoint endPoint(tcp::endpoint(tcp::v4(), port);
acceptor.open(endPoint.protocol());
acceptor.set_option(tcp::acceptor::reuse_address(true));
acceptor.bind(endPoint);
m_acceptor.listen(); // NEEDED TO ADD THIS BIT!
port = endPoint.port();
std::cout<<port<<std::endl; // prints 0
I have small piece of code
boost::asio::ip::tcp::no_delay option(true);
boost::asio::ip::tcp::socket* sock = new boost::asio::ip::tcp::socket(ios);
sock->set_option(option);
_session_acceptor.async_accept(*sock,
boost::bind(&server::playerAccept, this, sock, boost::asio::placeholders::error));
If i call set_option on socket before accepting server dont accept any connections. But if i call set_option after connections are accepted. Is there any magic?
You should call set_option on acceptor, not socket. Example from my project:
Listener::Listener(int port)
: acceptor(io, ip::tcp::endpoint(ip::tcp::v4(), port))
, socket(io) {
boost::asio::ip::tcp::no_delay opt_nodelay(true);
acceptor.set_option(opt_nodelay);
start_accept();