如何使用boost asio在UDP套接字上发送unsigned char的std :: vector?

时间:2017-05-10 11:58:19

标签: c++ sockets boost udp boost-asio

这是我上一个问题here的扩展,其中包含" 最小可行示例"代码。

我开发了一个UDPClient& UDPServer应用程序如下。这些应用与boost official udp client& boost official udp server

UDPClient.cpp

#include <iostream>
#include <algorithm>
#include <boost/asio.hpp>

using boost::asio::ip::udp;

struct Person {

    char name[1024];
    int age;
};

int main(int argc, char* argv[]) {

  // Turn this variable TRUE on to send structs of "Person"
  bool send_structs = false;

  try {
    if (argc != 2) {
      std::cerr << "Usage: client <host>" << std::endl;
      return 1;
    }

    boost::asio::io_service io_service;
    udp::resolver resolver(io_service);
    udp::resolver::query query(udp::v4(), argv[1], "7123");

    udp::endpoint receiver_endpoint = *resolver.resolve(query);

    udp::socket socket(io_service);
    socket.open(udp::v4());

    for (;;) {

      if (send_structs == true) {

        // Send structs
        Person send_data = { "something_from_client", 123 };
        boost::system::error_code ignored_error;
        socket.send_to(boost::asio::buffer(&send_data, sizeof(send_data)), receiver_endpoint, 0, ignored_error);

        udp::endpoint sender_endpoint;
        Person receive_data;
        std::size_t len = socket.receive_from(boost::asio::buffer(&receive_data, sizeof(receive_data)), sender_endpoint);
        std::cout << "After receiving at client header is " << receive_data.name << std::endl;
        std::cout << "After receiving at client version is " << receive_data.age << std::endl;
      }
      else {

        // Send & receive char vectors
        std::vector<unsigned char> send_data(1024);
        std::string str = "Hello from Client";
        std::copy (str.begin(),str.begin(), send_data.begin());

        boost::system::error_code ignored_error;
        std::cout << "Before sending vector length is " << send_data.size() << std::endl;
        socket.send_to(boost::asio::buffer(send_data.data(), send_data.size()), receiver_endpoint, 0, ignored_error);

        udp::endpoint sender_endpoint;
        std::vector<unsigned char> receive_data;
        receive_data.resize(1024);
        std::size_t bytes_rec = socket.receive_from(boost::asio::buffer(receive_data), sender_endpoint);
        std::cout << "After receiving at client vector size is " << receive_data.size() << std::endl;
        std::cout << "Received bytes at client are " << bytes_rec << std::endl;
      }
    }

  }
  catch (std::exception& e) {
    std::cerr << e.what() << std::endl;
  }
  return 0;
}

UDPServer.cpp

#include <iostream>
#include <algorithm>
#include <boost/asio.hpp>

using boost::asio::ip::udp;

struct Person {

    char name[1024];
    int age;
};

int main() {

  // Turn this variable TRUE on to send structs of "Person"
  bool send_structs = false;

  try {
    boost::asio::io_service io_service;
    udp::socket socket(io_service, udp::endpoint(udp::v4(), 7123));

    for (;;) {

      udp::endpoint remote_endpoint;

      if (send_structs == true) {

        // Send structs
        boost::system::error_code error;
        Person receive_data;
        size_t len = socket.receive_from(boost::asio::buffer(&receive_data, sizeof(receive_data)), remote_endpoint, 0, error);
        std::cout << "After receiving at server header is " << receive_data.name << std::endl;
        std::cout << "After receiving at server version is " << receive_data.age << std::endl;

        if (error && error != boost::asio::error::message_size)
          throw boost::system::system_error(error);

        boost::system::error_code ignored_error;
        Person send_data = { "something_from_server", 456 };
        socket.send_to(boost::asio::buffer(&send_data, sizeof(send_data)), remote_endpoint, 0, ignored_error);
      }
      else {

        // Send & receive char vectors
        boost::system::error_code error;
        std::vector<unsigned char> receive_data;
        receive_data.resize(1024);
        std::size_t bytes_rec = socket.receive_from(boost::asio::buffer(receive_data), remote_endpoint, 0, error);
        std::cout << "Bytes received at server are " << bytes_rec << std::endl;
        std::cout << "After receiving at server vector length is " << receive_data.size() << std::endl;

        if (error && error != boost::asio::error::message_size)
          throw boost::system::system_error(error);

        boost::system::error_code ignored_error;
        std::vector<unsigned char> send_data(1024);
        std::string str = "Hello from Server";
        std::copy (str.begin(),str.begin(), send_data.begin());

        std::cout << "Before sending vector length is " << send_data.size() << std::endl;
        std::size_t bytes_sent = socket.send_to(boost::asio::buffer(send_data.data(), send_data.size()), remote_endpoint, 0, ignored_error);
        std::cout << "Bytes sent from server are " << bytes_sent << std::endl;
      }
    }
  }
  catch (std::exception& e) {
    std::cerr << e.what() << std::endl;
  }
  return 0;
}

我正在使用编译命令在clang OSX上构建应用程序:

clang++ -std=c++14 -lboost_system UDPClient.cpp -o UDPClient
clang++ -std=c++14 -lboost_system UDPServer.cpp -o UDPServer

在控制台上运行 这样的应用程序。首先在客户端启动之前运行服务器:

./UDPServer
./UDPClient <host_ip>

以下是问题:

当我通过在两侧设置布尔标志send_structs作为true发送结构时,它可以很好地发送结构。但是,当我将send_structs设置为双方都是假的时候。尝试使用相同的技术发送std::vector<unsigned char>,奇怪的是它不起作用。

那么,如何使用boost asio在UDP套接字上发送std::vector unsigned char

服务器应用日志快照:

After receiving at server vector length is 0
Before sending vector length is 1024
Bytes sent from server are 1024
Bytes received at server are 0
After receiving at server vector length is 0
Before sending vector length is 1024
Bytes sent from server are 1024
Bytes received at server are 0
After receiving at server vector length is 0

客户端应用日志快照:

Before sending vector length is 1024
After receiving at client vector size is 0
Received bytes at client are 0
Before sending vector length is 1024
After receiving at client vector size is 0

如您所见,收到矢量长度后为零!!

PS:我还注意到,在发送结构时,当我首先启动服务器时,它会一直等到客户端打开套接字。 但是,当发送向量时,服务器只是盲目地继续循环发送。这是我的代码或预期行为中的错误吗? (次要问题)

1 个答案:

答案 0 :(得分:1)

如果要接收矢量,则必须调整缓冲区大小以指示您希望接收多少。这正是这个答案中发生的事情:boost asio write/read vector

现在,这个:

std::vector<unsigned char> receive_data;
std::size_t bytes_rec = socket.receive_from(boost::asio::buffer(receive_data), sender_endpoint);

要求接收0个字节(因为接收缓冲区的大小为0)。

您可能知道预期的数据报大小。否则,您可以简单地过度标注缓冲区,因为收到的bytes_rec将告诉您已收到多少元素。