Как оптимизировать клиент / сервер с помощью C / C ++ и Boost Asio - PullRequest
0 голосов
/ 07 июня 2011

У меня есть два приложения, которые работают как клиент / сервер TCP.

Первое приложение - это клиент, который использует OpenCV для обнаружения и отправки команд через TCP на сервер, который управляет мобильным роботом.

Мои приложения работают хорошо, если я нахожусь на своем развивающемся компьютере, но когда я тестирую его в реальном мире с моим роботом, я понимаю, что у меня есть некоторые задержки с обменом данными между клиентом и сервером.Это происходит потому, что компьютер, на котором я тестирую приложения, немного медленнее, чем мой развивающийся компьютер, который работает быстрее и не доставляет проблем.В реальном случае сервер не получает пакеты от клиента в режиме реального времени, поэтому он выполняет операции с задержкой.

Итак, проблема в том, что клиент теряет обнаружение и отправляет команды на сервер в порядкечтобы остановить это.Сервер получает пакеты с задержкой, поэтому, когда клиенты отправляют стоп-сервер (заголовок = 0, расстояние = 0, узловое соединение), сервер не получает команду сразу, потому что он получает пакеты предыдущих команд, и поэтому он останавливается только через несколько метров.

Я бы хотел найти решение, чтобы немедленно остановить сервер и отбросить все пакеты с движущейся информацией, потому что они бесполезны, если робот должен остановиться.Чтобы остановить робота, я отправляю пакет с запросом узла, который, к сожалению, не поступает в режиме реального времени, поэтому робот продолжает двигаться некоторое время.(Я делаю этот тест на той же машине, поэтому я подключаюсь к localhost)

В данный момент клиент использует этот код:

while (key_mode!='q')
    {
        //wait and error processing

        context.WaitAnyUpdateAll();

        // obtain al the metadata image,depthmap and scene

        Mat frame = getImageFromKinect();

        // do detection and tracking

        switch(mode)

        {
..
                               case ROBOT_CONTROL:

                 {

                 // Connect to the server

                 using boost::asio::ip::tcp;

                             boost::asio::io_service io_service;

                                 tcp::resolver resolver(io_service);

                     tcp::resolver::query query(tcp::v4(), server, boost::lexical_cast<string>(porta));

                                 tcp::resolver::iterator iterator = resolver.resolve(query);

                                 tcp::socket s(io_service); 

                                 try

                 {

                                 s.connect(*iterator);

                 }

                                 catch (boost::system::system_error const& e)

                 {

                                 std::cout << "Warning: could not connect to the server\n" << e.what() << "\nPossible Solution: try to check is Server is UP\n" << std::endl;

                 }

..
..
 float delta = heading - last_heading;

                     if (!is_equal(delta, 0.0)){ 

                    // heading_data = send_heading + token + boost::lexical_cast<std::string>(delta);

                    // heading_length = strlen(heading_data.c_str());

                     try

                     {

                        // boost::asio::write(s, boost::asio::buffer(heading_data, heading_length));  

                     }

                     catch (boost::system::system_error const& e)

                     {

                         std::cout << "Warning: could not send commands : " << e.what() << std::endl;

                     }



                     }

                                         last_heading = heading; // store current for next subtraction

                     #endif

                     #if 1

                                         heading_scalato = heading / 3.0;

                     heading_data = send_heading + token + boost::lexical_cast<std::string>(heading_scalato);

                     heading_length = strlen(heading_data.c_str());

                         try

                     {

                         boost::asio::write(s, boost::asio::buffer(heading_data, heading_length));  

                     }

                     catch (boost::system::system_error const& e)

                     {

                         std::cout << "Warning: could not send commands : " << e.what() << std::endl;

                     }

                                         #endif



                                        distance_data = send_distance + token + boost::lexical_cast<std::string>(distance);





                    distance_length = strlen(distance_data.c_str());



                    try

                    {

                    boost::asio::write(s, boost::asio::buffer(distance_data, distance_length));

                    }

                    catch (boost::system::system_error const& e)

                    {

                    std::cout << "Warning: could not connect : " << e.what() << std::endl;

                    }
..
..
// if it has to stop:

else

                {

                    // stop rover

                    //control.setHeading(0.0);

                    //control.setDistance(0.0);

                                        float heading = 0.0;

                                        float distance = 0.0;

                                        heading_data = send_heading + token + boost::lexical_cast<std::string>(heading);

                                        distance_data = send_distance + token + boost::lexical_cast<std::string>(distance);

                                        heading_length = heading_data.size();//strlen(heading_data.c_str());

                    distance_length = strlen(distance_data.c_str());



                        try

                    {

                                        boost::asio::write(s, boost::asio::buffer(heading_data, heading_length));

                                        boost::asio::write(s, boost::asio::buffer(distance_data, distance_length));

                    }

                    catch (boost::system::system_error const& e)

                    {

                        std::cout << "Warning: could not send commands : " << e.what() << std::endl;

                    }





                    // write info on image

                    char text[100];

                    sprintf(text,"ROBOT CONTROL: No detection");

                    putText(hogResultFrame,text,Point(4,89),FONT_HERSHEY_PLAIN,1,Scalar(0,0,0));

                    putText(hogResultFrame,text,Point(5,90),FONT_HERSHEY_PLAIN,1,Scalar(100,100,255));

                                        nodetection_length = nodetection.size();

                    try

                    {

                                        boost::asio::write(s, boost::asio::buffer(nodetection, nodetection_length));

                    }

                    catch (boost::system::system_error const& e)

                    {

                        std::cout << "Warning: could not send commands : " << e.what() << std::endl;

                    }

На сервере я использую:

void* runThread(void*)
  {

        while(Aria::getRunning())
        {
            if(start_routine){

                if(temp_heading < 0.0){
                printf("\n\nStarting Discovering routine, then sleeping 3 seconds.\a\n\n");
                robot.setRotVel(5.0);
                ArUtil::sleep(3000);
        temp_heading = -1;
        }           
            else if(temp_heading >= 0.0) {
        printf("\n\nStarting Clockwise Discovering routine, then sleeping 3 seconds.\a\n\n");
                robot.setRotVel(-5.0);
                ArUtil::sleep(3000);
        temp_heading = 1;
                } 

                } 


                if( !flag_heading && !flag_distance)
            {               

                myMutex.lock();
                temp_heading=m_heading;
                temp_distance=m_distance;
                myMutex.unlock();

                if (is_equal(temp_heading, 0.0)){
                    robot.setRotVel(0.0);
                    }
                else robot.setRotVel(-ArMath::radToDeg(temp_heading));

                if(temp_distance <= distanza_minima || is_equal(temp_distance, 0.0))
                    robot.setVel(0.0);
                else
                    robot.setVel(float(temp_distance/20));

                printf("runThread:: heading= %f distance = %f rob_vel = %f rob_rot_vel = %f\n",ArMath::radToDeg(temp_heading),temp_distance, robot.getVel(),robot.getRotVel());

                flag_heading = true;
                flag_distance = true;
                start_routine = false;
            }
                ArUtil::sleep(100);

        }
  }
DataLine GetValueFromLine(const std::string& sData) {

  std::string sName, sInteger;
  std::stringstream ss;
  DataLine Result;

  size_t sz = sData.find('@');

  sName = sData.substr(0,sz); // Just in case you need it later

  Result.sName = sName;

  sInteger = sData.substr(sz + 1,sData.length() - sz);

  ss.str(sInteger);

  ss >> Result.nNumber;

  if (ss.fail()) {

    // something went wrong, probably not an integer
  }

  return Result;
}
void session(socket_ptr sock)
{
  try
  {
    for (;;)
    {
      char data[max_length];

      boost::system::error_code error;
      size_t length = sock->read_some(boost::asio::buffer(data), error);
      data[length] = 0;
      if (error == boost::asio::error::eof)
        break; // Connection closed cleanly by peer.
      else if (error)
        throw boost::system::system_error(error); // Some other error.

      output = GetValueFromLine(data);



      std::cout << "*******************\n";
      comando = output.sName;
      valore = output.nNumber;
      if (output.sName == "nodetection"){
      start_routine = true;
      std::cout << "\nSto ricevendo: " << output.sName;
      }
      else if (output.sName == "heading"){
      start_routine = false;
      control.setHeading(output.nNumber);
      std::cout << "\nSto ricevendo: " << output.sName << "e heading: " << output.nNumber;
      }                                
      else if (output.sName == "distance"){
      start_routine = false;
      control.setDistance(output.nNumber);
      std::cout << "\nSto ricevendo: " << output.sName << "e distance: " << output.nNumber;
      }                             




     // boost::asio::write(*sock, boost::asio::buffer(data, length));

    }
  }
  catch (std::exception& e)
  {
    std::cerr << "Exception in thread: " << e.what() << "\n";
  }
}

void server(boost::asio::io_service& io_service, short port)
{
  tcp::acceptor a(io_service, tcp::endpoint(tcp::v4(), port));
  for (;;)
  {
    socket_ptr sock(new tcp::socket(io_service));
    a.accept(*sock);
    boost::thread t(boost::bind(session, sock));

  }
}

int main(int argc, char **argv)
{
         // control server initialitation..
         ....

          boost::asio::io_service io_service;  
          server(io_service, porta);

  return 0;                                    
}

Я думал заставить клиента закрыть TCP-соединение, когда оно достигает условия отсутствия обнаружения, чтобы заставить сервер отклонять ожидающие пакеты, но как я могу это сделать?Как уничтожить указатель s в boost?

Есть ли другие решения?Если я закрываю соединение, сервер отклоняет ожидающие пакеты?

1 Ответ

2 голосов
/ 07 июня 2011

Насколько я понимаю вашу проблему, у вас есть сообщение о том, что вы намерены отказаться от всей текущей обработки и очистить очередь ввода. Однако, поскольку приложение занято получением и обработкой предыдущих сообщений, оно не получает сообщение о прекращении и сбросе до тех пор, пока не будут обработаны все предыдущие сообщения, что приводит к отказу и сбросу без операции

ИМХО вам нужно спроектировать и кодировать многопоточное приложение.

Одна ветка, как можно более легкая, считывает входящие сообщения как можно быстрее и быстро проверяет сообщение об отказе и сбросе. Если сообщение в порядке, оно добавляется в очередь и проверяется следующее сообщение.

Второй поток извлекает сообщения из очереди, в которой сообщения хранятся первым потоком, и обрабатывает их, возможно, на это уходит много времени. Время от времени он проверяет сигнал отмены и сброса из первого потока.

Другой подход к рассмотрению: приложение, отправляющее сообщения, поддерживает очередь. Когда приложение, которое получает сообщения, заканчивает обработку сообщения, оно отправляет запрос на следующее сообщение. Отправитель отправляет сообщения только по запросу. Если возникает условие оставления и сброса, приложение, отправляющее сообщения, следит за этим. Приложение, получающее сообщения, имеет дело только с одним за раз. Этот подход значительно упрощает приемник сообщений за счет сложности приложения-отправителя, более сложного протокола связи и, возможно, снижения максимальной пропускной способности.

...