4
votes

This is a extension to my previous question here with a "minimum viable example" of the code.

I have developed a UDPClient & UDPServer app as below. These apps are very much similar to the 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;
}

I am building the apps on clang OSX with following compile command:

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

Run the apps on console like so. Run the server firstly before client has started:

./UDPServer
./UDPClient <host_ip>

Here is the problem:

When I send structs by setting boolean flag send_structs as true on both sides then it works all fine sending the structs nicely. But when I set send_structs as false on both sides & try the same technique to send an std::vector<unsigned char>, it strangely doesn't work.

So, How can I send an std::vector of unsigned char over an UDP socket using boost asio?

Snapshot of server app log:

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

Snapshot of client app log:

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

As you can see, after receiving the vector length is zero !!

PS: I also noticed that while sending the structs, when I start the server firstly, it waits until the client has opened the socket. But, when sending vectors, server just blindly keeps looping on the send. Is that a mistake in my code or expected behaviour? (secondary question)

1
You don't show the output of your logging - what is it?Useless
@Useless updated the logs now. Note that the vector length after receive is zero on both client & server side is zeroTheWaterProgrammer
if I start the client first & server next, then both sides are simply hung. exactly the same problem I have mentioned in my previous question hereTheWaterProgrammer

1 Answers

2
votes

If you want to receive into a vector, you will have to size the buffer to indicate how much you want to receive. This is exactly what happened in this answer: boost asio write/read vector

Right now, this:

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

Asks to receive 0 bytes (because the size of the receiving buffer is 0).

You might know the expected datagram size. Otherwise, you can simply over-dimension the buffer, because the received bytes_rec will tell you how many elements have been received.