I have a C++ application which uses a UDP Server (using Boost.Asio) that receives packets from a gigabit local network device at a high frequency (3500 packets per second). Some users report a few packet losses. So in the end I chose to run in parallel WireShark and my application to check if there are any packets that WireShark is able to receive but not my application.
What I found is that WireShark does not receive every packet, it seems that it misses some. My application misses also a few more frames that Wireshark received correctly.
My questions : Is it possible WireShark gets packets that my application does not ? I thought maybe WireShark has low-level access to the IP stack and packets are discarded by the OS even if they are shown in WireShark ?
Is it possible that the operation in (1) takes too much time such that the next async_receive_from
is called too late?
I would like to have opinions on this subject. Thanks.
Here is the code I use (quite basic). udp_server.h :
#pragma once
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <fstream>
const int MAX_BUFFER_SIZE = 65537;
using boost::asio::ip::udp;
class UDPServer
{
public:
UDPServer(boost::asio::io_service& ios, udp::endpoint endpoint)
:m_io_service(ios),
m_udp_socket(m_io_service, endpoint)
{
// Resize the buffer to max size in the component property
m_recv_buffer.resize(MAX_BUFFER_SIZE);
m_output_file.open("out.bin", std::ios::out | std::ios::binary);
StartReceive();
}
public:
void StartReceive()
{
m_udp_socket.async_receive_from(
boost::asio::buffer(m_recv_buffer), m_remote_endpoint,
boost::bind(&UDPServer::HandleReceive, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
private:
void HandleReceive(const boost::system::error_code& error, std::size_t bytes_transferred)
{
if (!error || error == boost::asio::error::message_size)
{
// Write to output -- (1)
m_output_file.sputn(&m_recv_buffer[0], bytes_transferred);
// Start to receive again
StartReceive();
}
}
boost::asio::io_service& m_io_service;
udp::socket m_udp_socket;
udp::endpoint m_remote_endpoint;
std::vector<char> m_recv_buffer;
std::filebuf m_output_file;
};
main.cpp:
include <boost/asio.hpp>
#include "udp_server.h"
const unsigned short PORT_NUMBER = 44444;
int main()
{
boost::asio::io_service ios;
boost::asio::ip::udp::endpoint endpoint(udp::endpoint(udp::v4(), PORT_NUMBER));
UDPServer server(ios, endpoint);
ios.run();
return 0;
}
Is this possible that WireShark get a packet and that my application does not ?
Yes. In particular, each socket has its own fixed-size incoming-data buffer, and if, at the moment the kernel tries to add the new incoming packet to that buffer, the buffer doesn't have enough available space to hold that packet, then the packet will not be added to the buffer, and so the application reading incoming data from that socket will not receive it.
Given that, it's entirely possible that WireShark's buffer had room to accept the incoming packet, but your own app's buffer did not.
How much bytes in a packet? You make a buffer as 64K, let the size be 32K. Then 3.5k * 32k
means 112MB/s, I don't think a gigabit network afford it. And, you write packets to a file, the sputn
may block you from receiving more packets, consequently the buffer of the driver overflowed, packets discarded.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With