Forum Programmation.c++ Client udp qui écoute plusieurs ports en utilisant boost

Posté par  (site web personnel) . Licence CC By‑SA.
Étiquettes : aucune
0
8
juin
2021

Bonjour à tous,

ça fait un petit moment que je galère et je n'arrive pas à m'en sortir. Je dois
écrire un client qui reçoit des données en udp. La connexion se fait en point à
point. Mon pc à une certaine IP qui permet au serveur de me reconnaître. Les
données sont envoyées sur 5 ports différents
- 50000/54000 début/fin de daq
- 51000/53000 début/fin de tranche
- 52000 données utiles du système

J'ai besoin de récupérer toutes les données et de les écrire dans le fichier.

Préalablement j'avais fait un petit client sur un seul port et j'avais testé
avec netcat; ça fonctionnait plutôt bien. Au passage de 1 vers 5 sockets… J'y
arrive plus. L'envoie des requêtes vers le serveur fonctionne toujours
correctement mais la réception ne fonctionne pas; je n'entre jamais dans les
handlers…

Ce que je sais par contre c'est que les données sont bien envoyées car ce que je
vois ensuite à partir du paquet 6 est exactement ce que je dois recevoir.

Je n'y arrive pas, je suis perdu… Est-ce qu'une ame charitable pourrait me
mettre sur la voie ?

Merci d'avance pour votre aide.

Olivier

Ci-dessous, un extrait de ce que wireshark voit
markdown
| 1 | 0 | 192.168.0.254 | 192.168.0.1 | UDP | 50 | 49890 → 5 Len=8 | 1 |
| 2 | 1.0876E-05 | 192.168.0.254 | 192.168.0.1 | UDP | 50 | 49890 → 5 Len=8 | 2 |
| 3 | 1.3583E-05 | 192.168.0.254 | 192.168.0.1 | UDP | 50 | 49890 → 5 Len=8 | 3 |
| 4 | 1.5884E-05 | 192.168.0.254 | 192.168.0.1 | UDP | 50 | 49890 → 5 Len=8 | 4 |
| 5 | 1.7992E-05 | 192.168.0.254 | 192.168.0.1 | UDP | 50 | 49890 → 5 Len=8 | 5 |
| 6 | 4.5684E-05 | 192.168.0.1 | 192.168.0.254 | UDP | 60 | 50000 → 32776 Len=8 | 6 |
| 7 | 4.5781E-05 | 192.168.0.1 | 192.168.0.254 | UDP | 74 | 51000 → 32776 Len=32 | 7 |
| 8 | 8.7986E-05 | 192.168.0.254 | 192.168.0.1 | ICMP | 102 | Destination unreachable (Communication administratively filtered) | 8 |
| 9 | 0.000107264 | 192.168.0.1 | 192.168.0.254 | UDP | 486 | 52000 → 32776 Len=444 | 9 |
| 10 | 0.000115677 | 192.168.0.254 | 192.168.0.1 | ICMP | 514 | Destination unreachable (Communication administratively filtered) | 10 |
| 12 | 0.014089529 | 192.168.0.1 | 192.168.0.254 | UDP | 466 | 52000 → 32776 Len=424 | 12 |
| 13 | 0.014131458 | 192.168.0.254 | 192.168.0.1 | ICMP | 494 | Destination unreachable (Communication administratively filtered) | 13 |
| 14 | 0.034794761 | 192.168.0.1 | 192.168.0.254 | UDP | 474 | 52000 → 32776 Len=432 | 14 |
| 15 | 0.034836852 | 192.168.0.254 | 192.168.0.1 | ICMP | 502 | Destination unreachable (Communication administratively filtered) | 15 |
| 17 | 0.071217607 | 192.168.0.1 | 192.168.0.254 | UDP | 474 | 52000 → 32776 Len=432 | 17 |
| 18 | 0.071260595 | 192.168.0.254 | 192.168.0.1 | ICMP | 502 | Destination unreachable (Communication administratively filtered) | 18 |
| 19 | 0.080098375 | 192.168.0.1 | 192.168.0.254 | UDP | 190 | 52000 → 32776 Len=148 | 19 |
| 20 | 0.080098482 | 192.168.0.1 | 192.168.0.254 | UDP | 74 | 53000 → 32776 Len=32 | 20 |
| 21 | 0.080098503 | 192.168.0.1 | 192.168.0.254 | UDP | 74 | 51000 → 32776 Len=32 | 21 |
| 22 | 0.080149978 | 192.168.0.254 | 192.168.0.1 | ICMP | 218 | Destination unreachable (Communication administratively filtered) | 22 |
| 24 | 0.160146554 | 192.168.0.1 | 192.168.0.254 | UDP | 486 | 52000 → 32776 Len=444 | 24 |

et ici le code

#include "udp_client.hxx"
#include <iostream>
#include <fstream>
#include <functional>
#include <vector>
//#include <thread>
#include <boost/bind/bind.hpp>
#include <boost/asio.hpp>
#include <ctime>
#include <boost/date_time/posix_time/posix_time.hpp>
#include "udp_constants.hxx"
using  boost::asio::ip::udp;

        udp_client::udp_client(boost::asio::io_context &io) :
          strand(boost::asio::make_strand(io)),
          socket_data(io, udp::endpoint(udp::v4(), udp_constants::ports::data)),
          socket_daq_start(io, udp::endpoint(udp::v4(), udp_constants::ports::daq_start)),
          socket_daq_stop(io, udp::endpoint(udp::v4(), udp_constants::ports::daq_stop)),
          socket_slice_start(io, udp::endpoint(udp::v4(), udp_constants::ports::slice_start)),
          socket_slice_stop(io, udp::endpoint(udp::v4(), udp_constants::ports::slice_stop)),
          socket_tx(io),
          timer{strand}
        {

          socket_daq_start.connect(udp::endpoint(boost::asio::ip::address::from_string("192.168.0.1"), 50000));
          socket_daq_stop.connect(udp::endpoint(boost::asio::ip::address::from_string("192.168.0.1"), 54000));
          socket_slice_start.connect(udp::endpoint(boost::asio::ip::address::from_string("192.168.0.1"), 51000));
          socket_slice_stop.connect(udp::endpoint(boost::asio::ip::address::from_string("192.168.0.1"), 53000));
          socket_data.connect(udp::endpoint(boost::asio::ip::address::from_string("192.168.0.1"), 52000));

          datagrams.push_back(std::vector<unsigned char>{0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00});
          datagrams.push_back(std::vector<unsigned char>{0x00, 0x01, 0x00, 0x01, 0x00, 0x7a, 0x11, 0xfe});
          datagrams.push_back(std::vector<unsigned char>{0x00, 0x01, 0x00, 0x02, 0x00, 0x7a, 0x11, 0xfe});
          datagrams.push_back(std::vector<unsigned char>{0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x05});
          datagrams.push_back(std::vector<unsigned char>{0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01});
          set_acquisition_and_get_data(datagrams);
          filename="/home/lemaire/data.dat";
        }


        udp_client::~udp_client()
        {
          socket_daq_start.close();
          socket_slice_start.close();
          socket_slice_stop.close();
          socket_daq_stop.close();
          socket_data.close();
          // close file
          output_stream.close();
          // inform user
          std::cout << "udp server destructor" << std::endl;
        }


        /**
         * @brief udp_client::get_time_stamp
         * @return
         *
         * @note je ne sais pas pour l'instant si c'est bien pertinent mais
         * l'objet c'était d'avoir un getter...
         */
        uint64_t udp_client::get_timestamp()
        {
          return create_timestamp();
        }

        std::vector<unsigned char> udp_client::ui64_to_vector(uint64_t w)
        {
          std::vector<unsigned char> vec(8, 0x0);
          char c;
          size_t d{0};
          for(int i{0}; i<8; i++)
          {
            d = (8-1-i)*8;
            c = static_cast<unsigned char>(w >> d);
            vec[i] = c;
          }
          return vec;
        }

        bool udp_client::send_data(std::vector<std::vector<unsigned char>>& datagrams)
        {
          std::cout << __PRETTY_FUNCTION__ << std::endl;
          using udp = boost::asio::ip::udp;
          auto endpoint = udp::endpoint(
                boost::asio::ip::address::from_string(udp_constants::ip::fpga),
                udp_constants::ports::configuration);
          try
          {
            socket_tx.open(boost::asio::ip::udp::v4());
            for(auto datagram: datagrams)
              socket_tx.send_to(boost::asio::buffer(datagram), endpoint);
            socket_tx.close();
          }
          catch (const boost::system::system_error& e)
          {
            std::cout << e.what() << std::endl;
          }

          return true;
        }

        bool udp_client::set_acquisition_and_get_data(std::vector<std::vector<unsigned char>>& datagrams)
        {
          std::cout << __PRETTY_FUNCTION__ << " begin" << std::endl;
          start_receive();
          std::cout << __PRETTY_FUNCTION__ << " start receive launched" << std::endl;
          send_data(datagrams);
          std::cout << __PRETTY_FUNCTION__ << " instructions sent" << std::endl;
          return true;
        }

        void udp_client::start_receive()
        {
          std::cout << __PRETTY_FUNCTION__ << std::endl;
          output_stream.open(filename,
                             std::ofstream::out |
                             std::ofstream::trunc |
                             std::ofstream::binary);

          std::vector<udp::endpoint> endpoints(5);
          socket_daq_start.async_receive
              (boost::asio::buffer(buffer_daq_start.data(), 16),
               boost::asio::bind_executor
               (strand,
                boost::bind
                (&udp_client::handle_daq_start,
                 this,
                 boost::asio::placeholders::error,
                 boost::asio::placeholders::bytes_transferred
                 )
                )
               );
          std::cout << __PRETTY_FUNCTION__ << " socket daq start started" << std::endl;
          // --
          socket_slice_start.async_receive
              (boost::asio::buffer(buffer_slice_start.data(), 64),
               boost::asio::bind_executor
               (strand,
                boost::bind
                (&udp_client::handle_slice_start,
                 this,
                 boost::asio::placeholders::error,
                 boost::asio::placeholders::bytes_transferred
                 )
                )
               );
          std::cout << __PRETTY_FUNCTION__ << " socket slice start started" << std::endl;
          // --
          socket_slice_stop.async_receive
              (boost::asio::buffer(buffer_slice_stop.data(), 64),
               boost::asio::bind_executor
               (strand,
                boost::bind
                (&udp_client::handle_slice_stop,
                 this,
                 boost::asio::placeholders::error,
                 boost::asio::placeholders::bytes_transferred
                 )
                )
               );
          std::cout << __PRETTY_FUNCTION__ << " socket slice stop started" << std::endl;
          // --
          socket_daq_stop.async_receive
              (boost::asio::buffer(buffer_daq_stop.data(), 16),
               boost::asio::bind_executor
               (strand,
                boost::bind
                (&udp_client::handle_daq_stop,
                 this,
                 boost::asio::placeholders::error,
                 boost::asio::placeholders::bytes_transferred
                 )
                )
               );
          std::cout << __PRETTY_FUNCTION__ << " socket slice stop started" << std::endl;
          // --
          socket_data.async_receive
              (boost::asio::buffer(buffer_data_1.data(), 16),
               boost::asio::bind_executor
               (strand,
                boost::bind
                (&udp_client::handle_data,
                 this,
                 boost::asio::placeholders::error,
                 boost::asio::placeholders::bytes_transferred
                 )
                )
               );
          std::cout << __PRETTY_FUNCTION__ << " socket data started" << std::endl;

          return;
        }

        void udp_client::handle_daq_start(const boost::system::error_code& error, // Result of operation.
                                          std::size_t bytes_transferred)
        {
          std::cout << __PRETTY_FUNCTION__ << std::endl;
          if(!error)
          {
            // write the data
            if(!output_stream.is_open())
              output_stream.open(filename,
                                 std::ofstream::out |
                                 std::ofstream::trunc |
                                 std::ofstream::binary);
            output_stream.write(buffer_daq_start.data(), bytes_transferred);
            timer.expires_after(boost::asio::chrono::milliseconds(timeout));
            timer.async_wait(boost::bind(&udp_client::handle_timeout, this,
                                         boost::asio::placeholders::error));
          }
          else
          {
            std::cerr << "handle daq start error";
            std::cerr << "message : " << error.message() << std::endl;
          }
          return;
        }

        void udp_client::handle_slice_start(const boost::system::error_code &error,
                                            std::size_t bytes_transferred)
        {
          if(!error)
          {
            // add time to the timeout timer
            timer.expires_after(boost::asio::chrono::milliseconds(timeout));
            timer.async_wait(boost::bind(&udp_client::handle_timeout, this,
                                         boost::asio::placeholders::error));
            // write the data
            output_stream.write(buffer_slice_start.data(), bytes_transferred);
      }
      else
      {
        std::cerr << "handle daq start error" << std::endl;
        std::cerr << error.message() << std::endl;
      }
      return;
    }

    void udp_client::handle_slice_stop(const boost::system::error_code &error,
                                       std::size_t bytes_transferred)
    {
      if(!error)
      {
        // add time to the timeout timer
        timer.expires_after(boost::asio::chrono::milliseconds(timeout));
        timer.async_wait(boost::bind(&udp_client::handle_timeout, this,
                                     boost::asio::placeholders::error));
        // write the data
        output_stream.write(buffer_slice_start.data(), bytes_transferred);
      }
      else
      {
        std::cerr << "handle daq start error" << std::endl;
        std::cerr << error.message() << std::endl;
      }
      return;
    }

    void udp_client::handle_data(const boost::system::error_code& error,
                                 std::size_t bytes_transferred)
    {
      if(!error)
      {
        // add time to the timeout timer
        timer.expires_after(boost::asio::chrono::milliseconds(timeout));
        timer.async_wait(boost::bind(&udp_client::handle_timeout, this,
                                     boost::asio::placeholders::error));
        // write the data
        output_stream.write(buffer_slice_start.data(), bytes_transferred);

        //    receive_data();
      }
      else
      {
        std::cerr << "handle daq start error" << std::endl;
        std::cerr << error.message() << std::endl;
      }
      receive_data();
      return;
    }

    void udp_client::receive_data()
    {
      socket_data.async_receive
          (boost::asio::buffer(buffer_data_1.data(), buffer_data_1.size()),
           boost::asio::bind_executor
           (strand,
            boost::bind
            (&udp_client::handle_data,
             this,
             boost::asio::placeholders::error,
             boost::asio::placeholders::bytes_transferred
             )
            )
           );
      return;
    }

    void udp_client::handle_daq_stop(const boost::system::error_code &error,
                                     std::size_t bytes_transferred)
    {
      if(!error)
      {
        // add time to the timeout timer
        timer.expires_after(boost::asio::chrono::milliseconds(timeout));
        timer.async_wait(boost::bind(&udp_client::handle_timeout, this,
                                     boost::asio::placeholders::error));
        // write the data
        output_stream.write(buffer_daq_stop.data(), bytes_transferred);
      }
      output_stream.close();
      return;
    }

    const std::string udp_client::get_data_file_name()
    {
      return filename+std::to_string(file_index)+".dat";
    }

    void udp_client::handle_timeout(const boost::system::error_code& e)
    {
      if (e != boost::asio::error::operation_aborted)
      {
        // close sockets
        socket_daq_start.shutdown(udp::socket::shutdown_both);
        socket_slice_start.shutdown(udp::socket::shutdown_both);
        socket_slice_stop.shutdown(udp::socket::shutdown_both);
        socket_daq_stop.shutdown(udp::socket::shutdown_both);
        socket_data.shutdown(udp::socket::shutdown_both);
        output_stream.close();
        std::cout << "file written and closed, socket closed" << std::endl;
      }
    }
    #include "udp_client.hxx"
    #include <boost/asio.hpp>
    #include <signal.h>
    #include <chrono>
    #include <boost/thread/thread.hpp>
    #include <boost/asio/thread_pool.hpp>

    int main()
    {
      try
      {
        boost::asio::io_context io;
        udp_client client(io);
        boost::thread t{boost::bind(&boost::asio::io_context::run, &io)};
        io.run();
        t.join();
      }
      catch (std::exception& e)
      {
        std::cout << "erreur" << std::endl;
        std::cerr << e.what() << std::endl;
      }
      return 0;
    }
  • # des questions diverses

    Posté par  . Évalué à 2. Dernière modification le 08 juin 2021 à 18:19.

    1. où est fait le Wireshark ? car on voit des paquets qui ne correspondent pas au probleme (UDP port <50.000, ICMP)
    2. on voit des paquets partir sur les ports 50000, 51000, 52000, 53000, 54000 vers une seule destination 192.168.0.254:32776

    attention en UDP ce n'est pas parce qu'un paquet part, qu'il arrive à destination et que tu peux passer à la suite

    le paquet peut etre perdu sans que l'autre en fasse n'en tienne rigueur

    • [^] # Re: des questions diverses

      Posté par  (site web personnel) . Évalué à 1.

      où est fait le Wireshark ? car on voit des paquets qui ne correspondent pas au probleme (UDP port <50.000, ICMP)

      le wireshark est fait la où je lance le code. En fait le serveur udp est sur un fpga. Par contre c'est vrai que je ne sais pas à quoi correspondent ces paquets ICMP…

      on voit des paquets partir sur les ports 50000, 51000, 52000, 53000, 54000 vers une seule destination 192.168.0.254:32776

      L'adresse 192.168.0.1 est l'adresse du fpga qui fait tourner le serveur
      L'adresse 192.168.0.254 est celle du pc qui execute le code et wireshark

      Donc si je dis pas de bétises, le serveur envoie sur plusieurs ports mais le PC, lui, reçoit tout sur un seul port…

      Les logiciels de traitement de texte sont à la rédaction ce que la 2CV est à l'automobile, une vieille voiture dont on se souvient avec nostalgie mais technologiquement dépassée

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.