I have a simple UDP server created using boost\asio
which, for now, only prints the data received, as shown below.
using boost::asio::ip::udp;
enum { max_length = 2048 };
void server(boost::asio::io_context& io_context, unsigned short port)
{
std::cout << "Server Created on port " + std::to_string(port) << " \n" << std::flush;
udp::socket sock(io_context, udp::endpoint(udp::v4(), port));
while(true)
{
udp::endpoint sender_endpoint;
std::vector<char> v(max_length);
sock.receive_from(boost::asio::buffer(v), sender_endpoint);
for (int i = 0; i < v.size(); i++)
{
std::cout << v[i] <<std::flush;
}
std::cout << std::endl;
}
}
I create 3 threads of the server
function using boost::thread
which I assign to a thread_group
:
boost::asio::io_context io_context;
boost::thread_group tg;
boost::thread *t = new boost::thread(server, std::ref(io_context), 8889);
boost::thread *t1 = new boost::thread(server, std::ref(io_context), 8890);
boost::thread *t2 = new boost::thread(server, std::ref(io_context), 11111);
tg.add_thread(t);
tg.add_thread(t1);
tg.add_thread(t2);
tg.join_all();
To test the server I have used Packet Sender. The problem is that the output is... scrambled.
When sending packets on the 3 ports at (more or less) the same time once per second the output is slightly misplaced, but when increasing the packet frequency to once per 0.1 second, the output becomes unreadable, as shown in these two images. I have tried giving one separate io_context
object to every server, but the output remains the same at high frequency. Is there any way to avoid this?
std::cout
automatically does some locking for you, a single print operation won't overlap with another print from a different thread. However as you are printing one character at a time the output from each thread is likely to overlap. Flushing after every printed character is also likely to lead to poor performance.
If you build what you want to print into a single string it should print correctly:
std::vector<char> v(max_length);
size_t bytes = sock.receive_from(boost::asio::buffer(v), sender_endpoint);
std::string str(v.data(), bytes);
str += '\n';
std::cout << str;
Or you can skip the vector and save straight to a string:
std:: string str(max_length);
size_t bytes = sock.receive_from(boost::asio::buffer(str), sender_endpoint);
str.resize(bytes)
str += '\n';
std::cout << str;