sendto () завершается ошибкой для пользовательского протокола UDP, используя генератор трафика протокола Seagull - PullRequest
0 голосов
/ 06 июля 2018

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

Сейчас я пытаюсь использовать этот клиент для отправки сообщений на сервер в моей локальной сети (192.x.x.x), но Seagull не может отправлять сообщения. Это не проблема сети, потому что я смог пропинговать адрес без потери пакетов. Я отследил источник ошибки до функции sendto(), которая продолжает работать из-за неверного аргумента. Я прошел по коду с использованием GDB, когда в качестве места назначения был задан как локальный шлейф, так и другой IP-адрес, а аргументы, переданные функции sendto (), были точно такими же, за исключением разных IP-адресов в структуре sockaddr что, конечно, ожидается. Однако, когда я смотрю на регистры после системного вызова в sendto(), тот, который содержит значение для длины длины сообщения, становится во время вызова отрицательным, и это значение, которое возвращается из вызова функции это не происходит с локальной петлевой сетью. Вот фрагмент кода, который вызывает sendto() и завершается ошибкой:

  size_t C_SocketWithData::send_buffer(unsigned char     *P_data, 
                                     size_t             P_size){
  //                                     T_SockAddrStorage *P_remote_sockaddr,
  //                                     tool_socklen_t    *P_len_remote_sockaddr) {

  size_t L_size = 0 ;
  int    L_rc       ;

  if (m_write_buf_size != 0) { 

    // Try to send pending data 
    if (m_type == E_SOCKET_TCP_MODE) {
      L_rc = _call_write(m_write_buf, m_write_buf_size) ;
    } else {
      L_rc = _write(m_write_buf, m_write_buf_size) ;
    }

    if (L_rc < 0) {
      SOCKET_ERROR(0,
                   "send failed [" << L_rc << "] [" << strerror(errno) << "]");
      switch (errno) {
      case EAGAIN:
        SOCKET_ERROR(0, "Flow control not implemented");
        break ;
      case ECONNRESET:
        break ;
      default:
        SOCKET_ERROR(0, "process error [" << errno << "] not implemented");
        break ;
      }
      return(0);

где _write() - оболочка для sendto().

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

Я запускаю клиент в Ubuntu v 14.04 через виртуальную машину (Virtualbox) на хосте Windows 10, куда я пытаюсь отправить сообщения. Заранее спасибо!

1 Ответ

0 голосов
/ 09 июля 2018

Я нашел ответ на этот вопрос после нескольких дней отладки и просмотра исходного кода, и я хочу обновить его на тот случай, если у какой-нибудь бедной души в будущем возникнет та же проблема. Исходная реализация Seagull всегда пытается связать сокет перед вызовом send / sendto. В этом случае, поскольку sendto автоматически связывает сокет, я смог удалить привязку для этого случая.

Оригинальная реализация в C_SocketClient :: _ open (C_Socket.cpp Строка 666):

} else {
  L_rc = call_bind(m_socket_id, 
                   (sockaddr *)(void *)&(m_remote_addr_info->m_addr_src),
                   SOCKADDR_IN_SIZE(&(m_remote_addr_info->m_addr_src)));

Отредактированная версия:

 } else {
  L_rc = call_bind(m_socket_id, 

  /* UDP Does not need to bind first */
  if(m_type != E_SOCKET_UDP_MODE) {
    L_rc = call_bind(m_socket_id, 
                    (sockaddr *)(void *)&(m_remote_addr_info->m_addr_src),
                    SOCKADDR_IN_SIZE(&(m_remote_addr_info->m_addr_src)));

    } else {
  L_rc = 0;
    }

Теперь Чайка работает, и я могу отправить свой собственный протокол! Я открыл запрос на извлечение исходного исходного кода, чтобы это можно было исправить.

...