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

Поиск:

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


pattern`щик
****


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

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



Цитата(mes @  10.4.2011,  00:14 Найти цитируемый пост)
запись какой нибудь последовательности..

Цитата(mes @  10.4.2011,  00:14 Найти цитируемый пост)
запись дополнительной последовательности в файл должна показать причину..

поясните. не понял.

Добавлено через 3 минуты и 58 секунд
еще, на сервере во входящих есть такое:
user posted image

в hex:
user posted image
т.е. три нуля.

PM WWW   Вверх
mes
Дата 10.4.2011, 00:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


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

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



после каждого сброса буффера в файл записывайте туда еще например "$$$"
чтоб наглядно бросалась в глаза.. 


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


pattern`щик
****


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

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



Цитата(mes @  10.4.2011,  00:22 Найти цитируемый пост)
после каждого сброса буффера в файл

но мне не известно когда буфера сбрасываются.
все что я могу, это принудительно вызывать fflush(). т.е. предлагаете вставить вызовы fflush() в обертки над sendmsg() и recvmsg() ?

Добавлено через 6 минут и 4 секунды
mes, я обернул код клиента в try-catch блок. теперь буфера не потеряются.
есть ли смысл сбрасывать буфера после каждой записи в файл?

Добавлено через 11 минут и 5 секунд
теперь свалился с таким сообщением:
Цитата

(exception): read error. expected 6690986 get 6690987

в client_in.log такое:
user posted image

число 6690985 повторяется дважды. хотя второе должно было быть 6690986
и пропал символ c и : 
PM WWW   Вверх
mes
Дата 10.4.2011, 00:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


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

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



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


--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 10.4.2011, 00:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


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

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



сервер вот что отправил:
user posted image
последние две строки повторяются.
PM WWW   Вверх
mes
Дата 10.4.2011, 00:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


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

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



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



--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 10.4.2011, 00:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


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

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



еще раз свалилось.
user posted image
тут уже повторение с предыдущими запусками. опять повтор. и опять пропали два символа.

Добавлено @ 00:48
Цитата(mes @  10.4.2011,  00:42 Найти цитируемый пост)
1. чтение не полной записи с сокета, а следовательно невозможность получения ожидаемого индекса используемым способом

это от меня не зависит. согласно документации, хэндлер вызовется в случае:
Цитата

The asynchronous operation will continue until one of the following conditions is true:
1. The supplied buffers are full. That is, the bytes transferred is equal to the sum of the buffer sizes.
2. An error occurred.


с другой стороны, в последних трех скринах ситуация повторилась.

Цитата(mes @  10.4.2011,  00:42 Найти цитируемый пост)
2. не обнуление буффера, которое  приводило к появлению неожидаемых символов..

это я сделал.


Это сообщение отредактировал(а) boostcoder - 10.4.2011, 00:51
PM WWW   Вверх
mes
Дата 10.4.2011, 01:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


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

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



Цитата(boostcoder @  9.4.2011,  23:25 Найти цитируемый пост)
в client_in.log такое:

сорри.. наверно ночь сказывается, но я  так и не понял откуда данные попадают в этот лог..

Добавлено через 1 минуту и 8 секунд
Цитата(boostcoder @  9.4.2011,  23:25 Найти цитируемый пост)
есть ли смысл сбрасывать буфера после каждой записи в файл?

не в сбрасывании цель, а в добавлении визуального разделителя..

Добавлено через 7 минут и 5 секунд
Цитата(boostcoder @  9.4.2011,  23:46 Найти цитируемый пост)
это от меня не зависит. 

просто Вы не в праве применять scanf до тех пор пока не наполните свой буффер.. 



--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 10.4.2011, 01:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


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

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



Цитата(mes @  10.4.2011,  01:00 Найти цитируемый пост)
я  так и не понял откуда данные попадают в этот лог

в client.cpp есть такой код:
Код

   FILE* in = fopen("server_in.log", "wb");
   FILE* out= fopen("server_out.log", "wb");
   dbg::in = in; // dbg::in и dbg::out используются в wrappers.cpp
   dbg::out = out;

в wrappers.cpp есть такое:
Код

static void dump(const struct msghdr *msg, FILE *fp)
{
    size_t i;
    for (i = 0; i < msg->msg_iovlen; ++i)
    {
        struct iovec *iov = &msg->msg_iov[i];
        fwrite(iov->iov_base, iov->iov_len, 1, fp);
    }
}

extern "C"
{

ssize_t (*_sendmsg)(int sockfd, const struct msghdr *msg, int flags);
ssize_t (*_recvmsg)(int sockfd, struct msghdr *msg, int flags);

ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags)
{
    if (dbg::out)
    {
        dump(msg, dbg::out); // запись отсылаемого
    }
    return _sendmsg(sockfd, msg, flags);
}

ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags)
{
    ssize_t error;
    error = _recvmsg(sockfd, msg, flags);
    if (dbg::in && error > 0)
    {
        dump(msg, dbg::in); // запись принятого
    }
    return error;
}

}



Добавлено через 1 минуту и 11 секунд
Цитата(mes @  10.4.2011,  01:00 Найти цитируемый пост)
Вы не в праве применять scanf до тех пор пока не наполните свой буффер

так scanf() вызывается в хэндлере. а хэндлер вызывается тогда, когда указанный объем прочитан.
PM WWW   Вверх
mes
Дата 10.4.2011, 01:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


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

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



Цитата(boostcoder @  10.4.2011,  00:08 Найти цитируемый пост)
так scanf() вызывается в хэндлере. а хэндлер вызывается тогда, когда указанный объем прочитан. 

сделайте strlen перед этим для проверки и будет ясно там ли мы ищем причину..

Добавлено @ 01:15
Цитата(boostcoder @  10.4.2011,  00:08 Найти цитируемый пост)
в wrappers.cpp есть такое:

тогда, если подозрения правильные, то ошибки должны быть в server_out и в client_in
но не в двух других..

Это сообщение отредактировал(а) mes - 10.4.2011, 01:32


--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 10.4.2011, 05:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


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

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



Цитата(mes @  10.4.2011,  01:11 Найти цитируемый пост)
сделайте strlen перед этим для проверки и будет ясно там ли мы ищем причину..

сделал.

Цитата(mes @  10.4.2011,  01:11 Найти цитируемый пост)
тогда, если подозрения правильные, то ошибки должны быть в server_out и в client_in
но не в двух других..

Вы правы.
вот только я немогу понять закономерность...

клиент свалился с таким сообщением:
Цитата

expected: 10661261, get: 1066126, buf:  1066126 1expected: 10661262, get: 661262, buf: 0661262
 1expected: 10661263, get: 661263, buf: 0661263
...

где:
"expected: 10661261" - правильно. это и должно было прийти.
"get: 1066126" - тут, внезапно, пропал последний знак.
"buf:  1066126" - тут его тоже нет.
"1expected: 10661262" - а ни это ли наша пропавшая единичка?;) на ее месте должен быть символ перевода строки.
"get: 661262" - тут нет первых двух знаков. т.е. "10"
"buf: 0661262" - а тут нет только первой единички.

сервер получил это:
user posted image
а отослал это:
user posted image
значение 10661262 повторяется дважды.

а клиент получил это:
user posted image


ну что, кто-то раскусил головоломку? ;)

последняя версия кодов.
клиент:
Код


#include <iostream>
#include <boost/bind.hpp>
#include <boost/asio.hpp>
#include <boost/thread.hpp>
#include <boost/lexical_cast.hpp>

#include "header.hpp"

size_t req_cnt = 0;
size_t ask_cnt = 0;
size_t requests = 0;
size_t answers = 0;
bool wsleep = false;

void timer_func() {
   while ( true ) {
      std::cout
      << "per sec requests: " << requests << std::endl
      << "per sec answers : " << answers << std::endl
      << "total requests  : " << req_cnt << std::endl
      << "total answers   : " << ask_cnt << std::endl << std::endl;
      requests = answers = 0;
      boost::this_thread::sleep(boost::posix_time::milliseconds(1000));
   }
}

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

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

void start_read(boost::asio::ip::tcp::socket& sock) {
   char* buf = new char[recv_buffer_size];
   memset(buf, 0, recv_buffer_size);
   boost::asio::async_read(
      sock,
      boost::asio::buffer(buf, recv_buffer_size),
      boost::bind(
         &readed,
         boost::ref(sock),
         buf,
         boost::asio::placeholders::error,
         boost::asio::placeholders::bytes_transferred
      )
   );
}

void readed(boost::asio::ip::tcp::socket& sock,
            char* buf,
            const boost::system::error_code& e,
            size_t rd)
{
   if ( e ) {
      throw std::runtime_error("readed(): " + e.message());
   }

   if ( rd != recv_buffer_size ) {
      std::cout
      << "readed(): " << buf << ", len: " << rd << std::endl;
   }

   static size_t idx = 0;
   size_t tmp = atoi(buf);
   
   if ( idx != tmp ) {
      std::cout
      << "expected: " << idx << ", get: " << tmp << ", buf: " << buf;
   }

   delete[] buf;

   answers++;
   ask_cnt++;

   ++idx;

   start_read(sock);
}

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

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

void start_write(boost::asio::ip::tcp::socket& sock) {
   static size_t idx = 0;
   requests++;
   req_cnt++;
   
   char* buf = new char[send_buffer_size];
   memset(buf, 0, send_buffer_size);
   sprintf(buf, "%9d\n", idx++);

   boost::asio::async_write(
      sock,
      boost::asio::buffer(buf, send_buffer_size),
      boost::bind(
         &writen,
         boost::ref(sock),
         buf,
         boost::asio::placeholders::error,
         boost::asio::placeholders::bytes_transferred
      )
   );
}

void writen(boost::asio::ip::tcp::socket& sock,
            char* buf,
            const boost::system::error_code& e,
            size_t wr)
{
   if ( e ) {
      throw std::runtime_error("writen(): " + e.message());
   }

   if ( wr != send_buffer_size ) {
      std::cout
      << "writen(): " << buf << ", len: " << wr << std::endl;
   }

   delete[] buf;

   if ( wsleep ) {
      boost::this_thread::sleep(boost::posix_time::microseconds(1000));
   }
   
   start_write(sock);
}

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

int main(int argc, char** argv) {
   try {
      if ( argc != 4 ) {
         std::cout << "client ip port 0/1 - sleed disabled/enabled" << std::endl;
         return 0;
      }

      if (init_wrappers()) {
         return -1;
      }
      std::string ip = argv[1];
      boost::uint16_t port = atoi(argv[2]);
      wsleep = (argv[3][0] == '1');
      std::cout << "sleep " << (wsleep?"enabled":"disabled") << std::endl;

      boost::thread thread(&timer_func);

      dbg::in = fopen("client_in.log", "wb");
      dbg::out= fopen("client_out.log", "wb");
      if ( !dbg::out || !dbg::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::socket socket(ios);
      socket.connect(endpoint);

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

      start_write(socket);
      start_read(socket);

      ios.run();

   } catch ( const std::exception& e ) {
      std::cout << "(exception): " << e.what() << std::endl;
   }
   fclose(dbg::in);
   fclose(dbg::out);
}

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


сервер:
Код


#include <iostream>
#include <boost/bind.hpp>
#include <boost/asio.hpp>
#include <boost/lexical_cast.hpp>

#include "header.hpp"

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

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

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

void writen(boost::asio::ip::tcp::socket& sock,
            char* buf,
            const boost::system::error_code& e,
            size_t wr)
{
   if ( e ) {
      throw std::runtime_error("writen(): " + e.message());
   }

   if ( wr != send_buffer_size ) {
      std::cout
      << "writen(): " << buf << ", len: " << wr << std::endl;
   }

   delete[] buf;
}

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

void start_read(boost::asio::ip::tcp::socket& sock) {
   char* buf = new char[recv_buffer_size];
   memset(buf, 0, recv_buffer_size);
   boost::asio::async_read(
      sock,
      boost::asio::buffer(buf, recv_buffer_size),
      boost::bind(
         &readed,
         boost::ref(sock),
         buf,
         boost::asio::placeholders::error,
         boost::asio::placeholders::bytes_transferred
      )
   );
}

void readed(boost::asio::ip::tcp::socket& sock,
            char* buf,
            const boost::system::error_code& e,
            size_t rd)
{
   if ( e ) {
      throw std::runtime_error("read handler: " + e.message());
   }

   if ( rd != recv_buffer_size ) {
      std::cout
      << "readed(): " << buf << ", len: " << rd << std::endl;
   }

   static size_t idx = 0;
   size_t tmp = atoi(buf);
   if ( idx != tmp ) {
      fprintf(stdout, "expected: %9d, get: %9d, buf: %s", idx, tmp, buf);
      fflush(stdout);
   }

   ++idx;

   start_write(sock, buf);
   start_read(sock);
}

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

int main(int argc, char** argv) {
   if ( argc != 3 ) {
      std::cout << "server ip port" << std::endl;
      return 0;
   }

   if ( init_wrappers() ) {
      return -1;
   }
   try {
      std::string ip = argv[1];
      boost::uint16_t port = atoi(argv[2]);

      dbg::in = fopen("server_in.log", "wb");
      dbg::out= fopen("server_out.log", "wb");
      if ( !dbg::out || !dbg::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);

      start_read(socket);

      ios.run();
   } catch ( const std::exception& e ) {
      std::cout << "(exception): " << e.what() << std::endl;
   }

   fclose(dbg::in);
   fclose(dbg::out);
}

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




Это сообщение отредактировал(а) boostcoder - 10.4.2011, 05:49

Присоединённый файл ( Кол-во скачиваний: 1 )
Присоединённый файл  asiotest2.zip 3,66 Kb
PM WWW   Вверх
boostcoder
Дата 10.4.2011, 06:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


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

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



я сделал это!!! smile 

ща расскажу..
PM WWW   Вверх
boostcoder
Дата 10.4.2011, 06:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


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

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



обратите внимание на этот код из сервера:
Код

void readed(boost::asio::ip::tcp::socket& sock,
            char* buf,
            const boost::system::error_code& e,
            size_t rd)
{
   ...

   start_write(sock, buf);
   start_read(sock); <<<<<<<<<<<<<<<<<<<<<<
}


последовательность такая:
readed() вызывается когда данные прочитаны. из него я запускаю операцию записи и операцию чтения. и тут ошибка! операцию чтения нужно запускать из хэндлера операции записи. т.е. мало того что в доке намекается на то, что нельзя выполнять две операции записи и чтения одновременно, так оказывается что выполнять чтение пока не завершена запись(и наоборот) тоже нельзя!

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

зы
немного о впечатлениях.
да, когда говорят что дока по бусту непонятная - правильно говорят. когда говорят что многое в бусте нелогично - правильно говорят. почему? да потому, что я за ночь прочел всю доку по asio от корки до корки, и не нашел ничего о том, что нельзя выполнять операцию на сокете до тех пор, пока предыдущая не завершилась!
единственное что как-то на это намекает, это цитаты:
Цитата

The program must ensure that the stream performs no other read operations (such as async_read, the stream's async_read_some function, or any other composed operations that perform reads) until this operation completes.

Цитата

The program must ensure that the stream performs no other write operations (such as async_write, the stream's async_write_some function, or any other composed operations that perform writes) until this operation completes.

но не в одной из цитат не говорится о том, что нельзя выполнять запись пока не завершилось чтение, и на оборот! а должно быть выделено красным, и вставлено на каждой странице доки!

эх... держите меня семеро smile 

MAKCimmesphprus, всем сильно благодарен за ваше терпение. всем спасибо. smile 


Это сообщение отредактировал(а) boostcoder - 10.4.2011, 06:58

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


pattern`щик
****


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

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



но мне все равно не понятно, каким образом операция чтения запущенная одновременно с операцией записи может портить данные которые записываются smile 
PM WWW   Вверх
boostcoder
Дата 10.4.2011, 07:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


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

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



удивительно... но использование канала наладилось. 94% smile 
Цитата

per sec requests: 205184
per sec answers : 201890
total requests  : 169479197
total answers   : 169425734

per sec requests: 250922
per sec answers : 235622
total requests  : 169730133
total answers   : 169661370

per sec requests: 181205
per sec answers : 194040
total requests  : 169911338
total answers   : 169855439

per sec requests: 209731
per sec answers : 196663
total requests  : 170121093
total answers   : 170052102



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


 




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


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

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