Boost asio UDP客户端未接收数据
我正在尝试使用 UDP 将数据从服务器发送到特定客户端,而不让客户端先将数据发送到服务器,根本不发送服务器数据。问题是客户端使用 receive_from()
函数,什么也没得到。由于某种原因,服务器确实设法发送数据,并且在发送整个有效负载后,它会自行关闭,但我不知道它将数据发送到哪里。 如果我在没有客户端的情况下运行服务器,数据也成功发送,我不知道为什么,服务器不应该阻止 send_to()
函数直到数据发送吗?
这是客户端停止的地方(我的代码的一部分):
void UDPclient::run()
{
std::string relative_path = "assets/";
std::thread thread_context = std::thread([&] {_io_context.run(); }); //start the context.
file_info fileInfo;
boost::asio::io_context::work idleWork(_io_context);
boost::system::error_code error;
udp::socket socket(_io_context); //the file descriptor
WirehairCodec decoder;
udp::endpoint sender;
memset(&fileInfo, sizeof(fileInfo), 0); //reset the struct to 0 (good practice)
std::size_t bytes_transferred = socket.receive_from(
boost::asio::buffer(&fileInfo, sizeof(fileInfo)),
sender);
...
socket.close();
}
服务器(我的代码的一部分):
int main()
{
std::uint16_t port = 2000;
file_info fileInfo;
std::string filePath;
boost::asio::io_context io_context;
udp::socket socket(io_context, udp::endpoint(udp::v4(), port));
udp::endpoint destination(boost::asio::ip::address::from_string("127.0.0.1"), port);
boost::system::error_code ec;
const WirehairResult initResult = wirehair_init(); //initialize wirehair
if(initResult != Wirehair_Success)
{
std::cout << "failed to initialize wirehair: " << initResult << std::endl;
return -1;
}
if (ec)
std::cerr << ec.message() << std::endl;
else
{
std::cout << "Enter the specified file (Full path) to send: ";
std::cin >> filePath;
while (!boost::filesystem::exists(filePath))
{
std::cerr << "file doesn't exist." << std::endl;
std::cout << "Enter the specified file (Full path) to send: ";
std::cin >> filePath;
}
read_fileToVector(filePath, vBuffer);
file_info fileInfo;
memset(&fileInfo, 0, sizeof(fileInfo)); // Always set the struct values to 0, good practice.
//send file size, name
fileInfo.size = vBuffer.size();
strncpy(fileInfo.fileName, filePath.substr(filePath.find_last_of("/\\") + 1).c_str(),
sizeof(fileInfo.fileName) - 1);
std::cout << "name: " << fileInfo.fileName << std::endl;
std::cout << "size: " << fileInfo.size << std::endl;
socket.send_to(boost::asio::buffer(&fileInfo, sizeof(fileInfo)), destination);
socket.wait(socket.wait_write);
...
socket.close();
}
I'm trying to send data from the server to a specific client using UDP, without making the client send data to the server first, without sending the server data at all. The problem is that the client waits for data using thereceive_from()
function, and gets nothing. For some reason the server does manage to send data and after sending the whole payload, it closes itself, but I don't know to where it sends the data.
If I run the server without the client the data is also successfully sent, and I don't know why, isn't the server supposed to block the send_to()
function until the data is sent?
this is where the client stops (part of my code):
void UDPclient::run()
{
std::string relative_path = "assets/";
std::thread thread_context = std::thread([&] {_io_context.run(); }); //start the context.
file_info fileInfo;
boost::asio::io_context::work idleWork(_io_context);
boost::system::error_code error;
udp::socket socket(_io_context); //the file descriptor
WirehairCodec decoder;
udp::endpoint sender;
memset(&fileInfo, sizeof(fileInfo), 0); //reset the struct to 0 (good practice)
std::size_t bytes_transferred = socket.receive_from(
boost::asio::buffer(&fileInfo, sizeof(fileInfo)),
sender);
...
socket.close();
}
Server(part of my code):
int main()
{
std::uint16_t port = 2000;
file_info fileInfo;
std::string filePath;
boost::asio::io_context io_context;
udp::socket socket(io_context, udp::endpoint(udp::v4(), port));
udp::endpoint destination(boost::asio::ip::address::from_string("127.0.0.1"), port);
boost::system::error_code ec;
const WirehairResult initResult = wirehair_init(); //initialize wirehair
if(initResult != Wirehair_Success)
{
std::cout << "failed to initialize wirehair: " << initResult << std::endl;
return -1;
}
if (ec)
std::cerr << ec.message() << std::endl;
else
{
std::cout << "Enter the specified file (Full path) to send: ";
std::cin >> filePath;
while (!boost::filesystem::exists(filePath))
{
std::cerr << "file doesn't exist." << std::endl;
std::cout << "Enter the specified file (Full path) to send: ";
std::cin >> filePath;
}
read_fileToVector(filePath, vBuffer);
file_info fileInfo;
memset(&fileInfo, 0, sizeof(fileInfo)); // Always set the struct values to 0, good practice.
//send file size, name
fileInfo.size = vBuffer.size();
strncpy(fileInfo.fileName, filePath.substr(filePath.find_last_of("/\\") + 1).c_str(),
sizeof(fileInfo.fileName) - 1);
std::cout << "name: " << fileInfo.fileName << std::endl;
std::cout << "size: " << fileInfo.size << std::endl;
socket.send_to(boost::asio::buffer(&fileInfo, sizeof(fileInfo)), destination);
socket.wait(socket.wait_write);
...
socket.close();
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
确实没有足够的代码可以告诉,但我可以指出一些气味:
memset 调用是错误的。由于显然
file_info
必须是简单且标准的布局(对于 memset 来说是合法的),为什么不使用空初始化器对其进行聚合初始化,以达到相同的效果(默认初始化每个成员)?您的上下文显然是一个类成员,但您正在为每个接收启动一个线程?这看起来很奇怪。我希望有一个具有 io_context/work 生命周期的线程。
如果您确实想重用/重新启动相同的 io_context,请记住需要在其间调用
.reset()
。您不需要为每个接收打开/关闭套接字
您可能希望将 UDP 套接字绑定到特定端口以进行接收
我期望看到的内容类似于:
为此,我编写了一个由两种类型的消息组成的协议,其神奇标头定义为:
另请注意异常安全句柄类型 CodecPtr 可以避免泄漏这些资源的任何风险。
使用 Wirehair 的完整演示
出于兴趣,我查看了 Wirehair 编解码器并使用它实现了一个简单的同步文件传输。
wirehair_encoder_create
会失败)。您必须创建一个例外来涵盖此类情况。xfer_id
字段作为相关 ID 放入协议消息中。我无法将演示放在网上,但您可以使用 https://github 的存储库自行构建它。 com/sehe/wirehair-demo:
There's not really enough code to tell, but there are a few smells that I can point out:
the memset call is wrong. Since clearly
file_info
must be trivial and standard layout (for memset to be legal), why not aggregate-initialize it with empty initializer instead, with the same effect (default-initializing every member)?your context is apparently a class member, but you are starting a thread for each receive? That seems odd. I'd expect a single thread with the lifetime of the io_context/work.
If you really want to reuse/restart the same io_context, keep in mind the need to call
.reset()
on it in between.You don't need to open/close a socket for each receive either
You might want to bind your UDP socket to a specific port to receive on
What'd I'd expect to see is something similar to:
For this I made up a protocol consisting of two types of messages with magic headers defined as:
Note also the exception-safe handle type
CodecPtr
that avoids any risk of leaking these resources.Full Demo Using Wirehair
Out of interest, I looked at the Wirehair codec and implemented a simple synchronous file transfer using it.
wirehair_encoder_create
fails in that case). You'd have to create an exception to cover such cases.xfer_id
field in to the protocol messages as a correlation id.I cannot put the demo live online, but you can build it yourself with the repository at https://github.com/sehe/wirehair-demo: