Модераторы: feodorv

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> баг asio? или баг TCP стека? 
V
    Опции темы
boostcoder
Дата 2.4.2011, 23:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 13
Всего: 110



вручную управлять памятью страшно smile 
PM WWW   Вверх
phprus
Дата 2.4.2011, 23:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 129
Регистрация: 22.8.2006

Репутация: 1
Всего: 3



boostcoder
Везде да.
У меня к каждому клиенту привязан объект класса Client, который привязан к одному io_service и который гарантированно работает в одном потоке. В качестве буферов (которые и передаются asio) используется два std::vector<char>, как поля класса Client, а данные получаемые из другого потока в виде обычного указателя используются очень локализовано и после чего удаляются, по этому я и согласился на ручное управление памятью, а не стал дальше думать, как обойти такое ограничение shared_ptr.

Это сообщение отредактировал(а) phprus - 2.4.2011, 23:18
PM MAIL WWW ICQ   Вверх
boostcoder
Дата 8.4.2011, 00:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 13
Всего: 110



убрал из кода все смарт-поинтеры.
проблема осталась smile 

на стороне клиента, сохраняю отправляемые массивы в файл, чтоб убедится в том, что массивы не портятся.
так и есть. массивы не искаженны.
user posted image

на стороне сервера, так же, сохраняю принятые массивы.
но тут, массив приходит искаженным:
user posted image

вот снифф этого участка, tcpdump`ом, на стороне клиента:
user posted image

а это на стороне сервера:
user posted image



на стороне клиента, как раз в то место где данные искаженны, добавлены какие-то данные. не мои.
видно, что на стороне сервера, массив, после прочтения при помощи asio, уже испорчен. но tcpdump показывает что массив не испорчен.

я в замешательстве smile 


выложу код в тему, в надежде, что кто-то внесет ясность в ситуацию.

клиент:
Код


#include "header.hpp"

/***************************************************************************/

int main(int argc, char** argv) {
   if ( argc != 4 ) {
      std::cout << "client ip port 0/1 - sleed disabled/enabled" << std::endl;
      return 0;
   }
   std::string ip = argv[1];
   boost::uint16_t port = boost::lexical_cast<boost::uint16_t>(argv[2]);
   bool wsleep = (argv[3][0] == '1');
   std::cout << "sleep " << (wsleep?"enabled":"disabled") << std::endl;
   
   FILE* in = fopen("client_in.log", "wb");
   FILE* out= fopen("client_out.log", "wb");
   if ( !out || !in ) {
      std::cout << "can`t open file!" << std::endl;
      return 1;
   }

   boost::asio::ip::tcp::endpoint endpoint(
      boost::asio::ip::address::from_string(ip), port
   );

   boost::asio::io_service ios;
   boost::shared_ptr<boost::asio::io_service::work> work(new boost::asio::io_service::work(ios));

   boost::thread thread(boost::bind(&boost::asio::io_service::run, &ios));
   
   boost::asio::ip::tcp::socket socket(ios);
   socket.connect(endpoint);

   boost::asio::socket_base::non_blocking_io non_blocking_io(true);
   socket.io_control(non_blocking_io);

   client_read(socket, in);

   for ( size_t idx = 0; idx < 100000000; ++idx ) {
      char* buf = new char[send_buffer_size];
      sprintf(buf, "cs:%8d\n", idx);
      start_write(socket, buf, out);
      if ( wsleep ) {
         boost::this_thread::sleep(boost::posix_time::microseconds(1000));
      }
   }

   std::cout
   << "send data to server finished!" << std::endl
   << "waiting for all ask`s from server..." << std::endl;

   work.reset();

   while ( counter ) {
      boost::this_thread::sleep(boost::posix_time::microseconds(1000));
      std::cout << "." << std::flush;
   }

   std::cout << std::endl << std::endl
   << "all ask`s received." << std::endl
   << "terminate client..." << std::endl;

   socket.cancel();
   socket.close();

   thread.join();
   fclose(in);
   fclose(out);
}

/***************************************************************************/

http://liveworkspace.org/code/15c1e78ea451...f1eebe7e08564a7

сервер:
Код


#include "header.hpp"

/***************************************************************************/

int main(int argc, char** argv) {
   if ( argc != 3 ) {
      std::cout << "server ip port" << std::endl;
      return 0;
   }
   std::string ip = argv[1];
   boost::uint16_t port = boost::lexical_cast<boost::uint16_t>(argv[2]);

   FILE* in = fopen("server_in.log", "wb");
   FILE* out= fopen("server_out.log", "wb");
   if ( !out || !in ) {
      std::cout << "can`t open file!" << std::endl;
      return 1;
   }

   boost::asio::ip::tcp::endpoint endpoint(
      boost::asio::ip::address::from_string(ip), port
   );
   
   boost::asio::io_service ios;
   boost::asio::ip::tcp::acceptor acceptor(ios, endpoint);
   boost::asio::ip::tcp::socket socket(ios);

   acceptor.accept(socket);
   std::cout << "new connection from: " << socket.remote_endpoint().address().to_string() << std::endl;
   
   boost::asio::socket_base::non_blocking_io non_blocking_io(true);
   socket.io_control(non_blocking_io);

   server_read(socket, in, out);

   ios.run();

   fclose(in);
   fclose(out);
}

/***************************************************************************/

http://liveworkspace.org/code/0a8e2cb728f8...d31f28c46ddf9e2

общий хидер:
Код


#ifndef _header_hpp_included_
#define _header_hpp_included_

#include <iostream>
#include <sstream>
#include <iomanip>
#include <cstdio>
#include <boost/bind.hpp>
#include <boost/asio.hpp>
#include <boost/thread.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/shared_array.hpp>
#include <boost/lexical_cast.hpp>

enum { recv_buffer_size = 13 };
enum { send_buffer_size = 13 };

volatile size_t counter = 0;

/***************************************************************************/

void client_readed(
   boost::asio::ip::tcp::socket&,
   char*,
   FILE*,
   const boost::system::error_code&
);

void client_read(
   boost::asio::ip::tcp::socket& sock,
   FILE* out
) {
   char* buf = new char[recv_buffer_size];
   boost::asio::async_read(
      sock,
      boost::asio::buffer(buf, recv_buffer_size),
      boost::bind(
         &client_readed,
         boost::ref(sock),
         buf,
         out,
         boost::asio::placeholders::error
      )
   );
}

void client_readed(
   boost::asio::ip::tcp::socket& sock,
   char* buf,
   FILE* out,
   const boost::system::error_code& e
) {
   if ( e ) {
      if ( !counter ) return;
      std::cout << "read handler: " << e.message() << std::endl;
      return;
   }

   fwrite(buf, recv_buffer_size, 1, out);

   counter--;

#ifdef _my_debug_
   printf("client_readed(): %s", buf);
   fflush(stdout);
#endif

   static size_t idx = 0;
   size_t tmp = 0;
   char* p = strchr(buf, ':');
   if ( p ) {
      p++;
      sscanf(p, "%8d", &tmp);
   } else {
      throw std::runtime_error("input data error!");
   }
   
   delete[] buf;
   
   if ( idx != tmp ) {
      std::ostringstream os;
      os << "read error. expected " << idx << " get " << tmp;
      throw std::runtime_error(os.str());
   }
   idx++;
   client_read(sock, out);
}

/***************************************************************************/

void writen(
   char*,
   FILE*,
   const boost::system::error_code&
);

void start_write(
   boost::asio::ip::tcp::socket& sock,
   char* buf,
   FILE* out
) {
   counter++;
   boost::asio::async_write(
      sock,
      boost::asio::buffer(buf, send_buffer_size),
      boost::bind(
         &writen,
         buf,
         out,
         boost::asio::placeholders::error
      )
   );
}

void writen(
   char* buf,
   FILE* out,
   const boost::system::error_code& e
) {
   fwrite(buf, send_buffer_size, 1, out);
   delete[] buf;
   if ( e ) {
      std::cout << "writen(): " << e.message() << std::endl;
   }
}

/***************************************************************************/

void server_readed(
   boost::asio::ip::tcp::socket&,
   char*,
   FILE*,
   FILE*,
   const boost::system::error_code&
);
   
void server_read(
   boost::asio::ip::tcp::socket& sock,
   FILE* in,
   FILE* out
) {
   char* buf = new char[recv_buffer_size];
   boost::asio::async_read(
      sock,
      boost::asio::buffer(buf, recv_buffer_size),
      boost::bind(
         &server_readed,
         boost::ref(sock),
         buf,
         in,
         out,
         boost::asio::placeholders::error
      )
   );
}

void server_readed(
   boost::asio::ip::tcp::socket& sock,
   char* buf,
   FILE* in,
   FILE* out,
   const boost::system::error_code& e
) {
   if ( e ) {
      std::cout << "read handler: " << e.message() << std::endl;
      return;
   }

#ifdef _my_debug_
   printf("server_readed(): %s", buf);
#endif

   fwrite(buf, recv_buffer_size, 1, in);
   
   static const char* ptr = "sc:";
   memcpy(buf, ptr, strlen(ptr));
   start_write(sock, buf, out);
   server_read(sock, in, out);
}

/***************************************************************************/

#endif // _header_hpp_included_


http://liveworkspace.org/code/fa23c521eab1...320dcff6290e656

всем спасибо.


зы
во вложении, архив с исходниками и Makefile`ом. проверено на gcc-linux и на mingw32.


Это сообщение отредактировал(а) boostcoder - 8.4.2011, 01:24

Присоединённый файл ( Кол-во скачиваний: 3 )
Присоединённый файл  asiotest2.zip 2,78 Kb
PM WWW   Вверх
phprus
Дата 8.4.2011, 10:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 129
Регистрация: 22.8.2006

Репутация: 1
Всего: 3



Из замеченного при помощи wireshark:
Когда включен - TCP-сегменты ходят с данными ровно в 13 байт и у каждого стоит флаг PUSH (сразу отдавать на уровень выше, те приложению).
Когда sleep выключен сегменты содержат множество склееных блоков по 13 байт (возможно не целое число блоков).

А что говорят по этому поводу на https://svn.boost.org/trac/boost/ ? Может быть имеет смысл написать Bug report?
PM MAIL WWW ICQ   Вверх
boostcoder
Дата 8.4.2011, 12:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 13
Всего: 110



при помощи strace обнаружил, что для ввода-вывода используются sendmsg() и recvmsg(), а не send() и recv() как предполагал.

Цитата(phprus @  8.4.2011,  10:02 Найти цитируемый пост)
Когда включен - TCP-сегменты ходят с данными ровно в 13 байт и у каждого стоит флаг PUSH (сразу отдавать на уровень выше, те приложению).
Когда sleep выключен сегменты содержат множество склееных блоков по 13 байт (возможно не целое число блоков).

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

Цитата(phprus @  8.4.2011,  10:02 Найти цитируемый пост)
А что говорят по этому поводу на https://svn.boost.org/trac/boost/ ? Может быть имеет смысл написать Bug report? 

та я потому и не писал, ибо все же не был уверен что это не мой баг в коде.
сейчас напишу..
PM WWW   Вверх
boostcoder
Дата 8.4.2011, 21:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 13
Всего: 110



вот что еще странно...
в один прекрасный момент, сервер принимает это:
user posted image

в первой строке сверху - все хорошо.
во второй и третьей строке, вместо завершающего нуля, вставлен символ c
в четвертой строке, символа c вначале, попросту нет.
PM WWW   Вверх
phprus
Дата 9.4.2011, 09:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 129
Регистрация: 22.8.2006

Репутация: 1
Всего: 3



boostcoder
Если sleep сделать с временем ожидания, равным 0 ( boost::this_thread::sleep(boost::posix_time::microseconds(0)) ) то  проблема тоже уходит, а sleep(0) в теории должен вызывать передачу управления другому процессу, те в коде похоже зарылась гонка. Только не могу понять в каком коде.

Цитата(boostcoder @  8.4.2011,  15:13 Найти цитируемый пост)
та я потому и не писал, ибо все же не был уверен что это не мой баг в коде.
сейчас напишу..

Сообщите пожалуйста ссылку на тикет.

Это сообщение отредактировал(а) phprus - 9.4.2011, 09:41
PM MAIL WWW ICQ   Вверх
boostcoder
Дата 9.4.2011, 14:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 13
Всего: 110



Цитата(phprus @  9.4.2011,  09:38 Найти цитируемый пост)
sleep(0) в теории должен вызывать передачу управления другому процессу

по идее - да.

Цитата(phprus @  9.4.2011,  09:38 Найти цитируемый пост)
те в коде похоже зарылась гонка

не спорю... но где?! и как побороть?! smile 
PM WWW   Вверх
boostcoder
Дата 9.4.2011, 15:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 13
Всего: 110



phprus, так у тебя этот баг тоже воспроизводиться?
скажи как тестируешь? версии ОС, компилятора, boost? локально, удаленно?
PM WWW   Вверх
MAKCim
Дата 9.4.2011, 15:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Воін дZэна
****


Профиль
Группа: Экс. модератор
Сообщений: 5644
Регистрация: 10.12.2005
Где: Менск, РБ

Репутация: 6
Всего: 207



Цитата(boostcoder @  8.4.2011,  00:44 Найти цитируемый пост)
на стороне клиента, как раз в то место где данные искаженны, добавлены какие-то данные. не мои.

ну так это может быть пустой пакет с tcp флагами...
хотя я не очень понимаю формат снифа

еще проверь у себя версию в аттаче
там логинг asio заменен а логинг sendmsg/recvmsg

Присоединённый файл ( Кол-во скачиваний: 4 )
Присоединённый файл  asiotest.rar 3,33 Kb


--------------------
Ах, у елі, ах, у ёлкі, ах, у елі злыя волкі ©

PM MAIL   Вверх
phprus
Дата 9.4.2011, 15:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 129
Регистрация: 22.8.2006

Репутация: 1
Всего: 3



Цитата(boostcoder @  9.4.2011,  18:00 Найти цитируемый пост)
phprus, так у тебя этот баг тоже воспроизводиться?
скажи как тестируешь? версии ОС, компилятора, boost? локально, удаленно? 


Да, воспроизводится.
Boost 1.46.1
openSUSE 11.3 (2.6.34.7-0.7-desktop)
g++ (SUSE Linux) 4.5.0 20100604 [gcc-4_5-branch revision 160292]

Тестирую локально, путем запуска сервера и клиента с двух соседних консолей в Konsole.
PM MAIL WWW ICQ   Вверх
MAKCim
Дата 9.4.2011, 15:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Воін дZэна
****


Профиль
Группа: Экс. модератор
Сообщений: 5644
Регистрация: 10.12.2005
Где: Менск, РБ

Репутация: 6
Всего: 207



и еще
вы пробовали запускать io_service::run не в отдельном потоке?


--------------------
Ах, у елі, ах, у ёлкі, ах, у елі злыя волкі ©

PM MAIL   Вверх
phprus
Дата 9.4.2011, 15:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 129
Регистрация: 22.8.2006

Репутация: 1
Всего: 3



В реальной сети, с rtt min/avg/max/mdev = 5.226/5.250/5.281/0.023ms  баг воспроизводится значительно быстрее. В среднем до падения проходит 0,1 - 0,3 секунды, а в случае с локальным запуском код работает до падения минимум несколько секунд. Но тут boost 1.46.0 и CentOS с родным GCC 4.1.2.
PM MAIL WWW ICQ   Вверх
boostcoder
Дата 9.4.2011, 15:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 13
Всего: 110



Цитата(MAKCim @  9.4.2011,  15:14 Найти цитируемый пост)
еще проверь у себя версию в аттаче
там логинг asio заменен а логинг sendmsg/recvmsg

сделал. на локальной машине.
в аттаче. это 7z архив. расширение сменил потому что форум не позволяет приаттачивать 7z.

Цитата(MAKCim @  9.4.2011,  15:14 Найти цитируемый пост)
хотя я не очень понимаю формат снифа

скажите как сделать? а то я не очень разбираюсь в снифферах.

Добавлено @ 15:52
Цитата(MAKCim @  9.4.2011,  15:28 Найти цитируемый пост)
вы пробовали запускать io_service::run не в отдельном потоке?

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

Добавлено через 11 минут и 24 секунды
Цитата(phprus @  9.4.2011,  09:38 Найти цитируемый пост)
Если sleep сделать с временем ожидания, равным 0 ( boost::this_thread::sleep(boost::posix_time::microseconds(0)) ) то  проблема тоже уходит

проверил. у меня ничего не изменилось.
ubuntu-10.10
gcc-4.5.1
boost-1.46.1


Это сообщение отредактировал(а) boostcoder - 9.4.2011, 15:55

Присоединённый файл ( Кол-во скачиваний: 2 )
Присоединённый файл  logs1.zip 139,60 Kb
PM WWW   Вверх
MAKCim
Дата 9.4.2011, 16:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Воін дZэна
****


Профиль
Группа: Экс. модератор
Сообщений: 5644
Регистрация: 10.12.2005
Где: Менск, РБ

Репутация: 6
Всего: 207



boostcoder
Цитата(boostcoder @  9.4.2011,  15:49 Найти цитируемый пост)
а клиенту, помимо того, что отправлять сообщения в цикле, нужно еще и принимать ответы от сервера. потому там я оставил один поток.

эмм
так а в чем проблема это все делать в одном потоке?
делаешь async_read, потом async_write
далее run и уже в обработчиках written/readed генерируешь новые операции...

или я ошибаюсь?

Добавлено через 1 минуту и 14 секунд
в общем нужно, имхо, избавиться от более одного потока в клиенте и сервере
и снова проверить

Добавлено через 2 минуты и 4 секунды
Цитата(boostcoder @  8.4.2011,  00:44 Найти цитируемый пост)
вот снифф этого участка, tcpdump`ом, на стороне клиента:

вот я не понимаю, как этот скрин был получен


--------------------
Ах, у елі, ах, у ёлкі, ах, у елі злыя волкі ©

PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Сети | Следующая тема »


 




[ Время генерации скрипта: 0.1336 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.