Форум программистов, компьютерный форум CyberForum.ru

Баг asio? или баг TCP стека? - C++

Войти
Регистрация
Восстановить пароль
 
Рейтинг: Рейтинг темы: голосов - 82, средняя оценка - 4.87
niXman
Эксперт C++
 Аватар для niXman
3133 / 1445 / 49
Регистрация: 09.08.2009
Сообщений: 3,441
Записей в блоге: 2
08.04.2011, 14:50     Баг asio? или баг TCP стека? #1
всем привет.

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

на стороне клиента, сохраняю отправляемые массивы в файл, чтоб убедится в том, что массивы не портятся.
так и есть. массивы не искаженны:
Название: 1.png
Просмотров: 620

Размер: 3.8 Кб

на стороне сервера, так же, сохраняю принятые массивы.
но тут, массив приходит искаженным:
Название: 2.png
Просмотров: 603

Размер: 4.1 Кб

от снифф этого участка, tcpdump`ом, на стороне клиента:
Баг asio? или баг TCP стека?

а это на стороне сервера:
Название: 4.png
Просмотров: 594

Размер: 3.7 Кб



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

еще более странно то, что если третьим аргументом клиенту передать "1" - то между асинхронными записями будет использоваться sleep() в 1мс - что полностью решает проблему. но такое решение не подходит.

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

клиент:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
#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:%8dn", 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/15c1e7...1eebe7e08564a7

сервер:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#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/0a8e2c...31f28c46ddf9e2

общий хидер:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
#ifndef _header_hpp_included_
#define _header_hpp_included_
 
#include <iostream>
#include <cstdio>
#include <boost/bind.hpp>
#include <boost/asio.hpp>
#include <boost/thread.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/9f9e4f...d44f5074181215

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

зы
во вложении, архив с исходниками и Makefile`ом. проверено на gcc-linux и на mingw32.
asiotest2.zip
Лучшие ответы (1)
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
08.04.2011, 14:50     Баг asio? или баг TCP стека?
Посмотрите здесь:

баг или что-то другое? Visual C++
C++ помогите определить баг или недочёт в программе.
Баг компилятора? Или я чего то не догоняю? C++
C++ Builder Баг или особенность?
C++ Ошибка или баг в Dev C++?
C++ Builder XE3 баг или кривые руки?
C++ Баг или фича
C++ Ввод/вывод баг или нет?
C++ std::regex : баг на сайте или баг компилятора?
баг компилятора, или беда с типами данных? C++ Builder
C++ Баг VS или как? Функция в многофайловом приложении
Ошибка или баг Visual Studio 2015? C++

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
niXman
Эксперт C++
 Аватар для niXman
3133 / 1445 / 49
Регистрация: 09.08.2009
Сообщений: 3,441
Записей в блоге: 2
08.04.2011, 15:29  [ТС]     Баг asio? или баг TCP стека? #2
при помощи strace обнаружил, что для ввода-вывода используются sendmsg() и recvmsg(), а не send() и recv() как предполагал.
g_u_e_s_t
1258 / 649 / 30
Регистрация: 06.02.2011
Сообщений: 1,724
08.04.2011, 16:15     Баг asio? или баг TCP стека? #3
По поводу sendxxx - по крайней мере на линуксе send() и sendto() это обертки вокруг sendmsg()
niXman
Эксперт C++
 Аватар для niXman
3133 / 1445 / 49
Регистрация: 09.08.2009
Сообщений: 3,441
Записей в блоге: 2
08.04.2011, 17:28  [ТС]     Баг asio? или баг TCP стека? #4
Цитата Сообщение от g_u_e_s_t Посмотреть сообщение
на линуксе send() и sendto() это обертки вокруг sendmsg()
ну хз... pthrace вообще говорит что таких функций не вызывается.
niXman
Эксперт C++
 Аватар для niXman
3133 / 1445 / 49
Регистрация: 09.08.2009
Сообщений: 3,441
Записей в блоге: 2
08.04.2011, 22:48  [ТС]     Баг asio? или баг TCP стека? #5
вот что еще странно...
в один прекрасный момент, сервер принимает это:
Баг asio? или баг TCP стека?

в первой строке сверху - все хорошо.
во второй и третьей строке, вместо завершающего нуля, вставлен символ c
в четвертой строке, символа c вначале, попросту нет.


у кого-то есть мысли по этому поводу?
niXman
Эксперт C++
 Аватар для niXman
3133 / 1445 / 49
Регистрация: 09.08.2009
Сообщений: 3,441
Записей в блоге: 2
09.04.2011, 20:03  [ТС]     Баг asio? или баг TCP стека? #6
Сообщение было отмечено автором темы, экспертом или модератором как ответ
баг распознан и ликвидирован.
как оказалось, это вовсе не баг, а неправильное использование функций asio.

в примечании к async_write() есть такое:
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.
я все время под этим понимал то, что одна из перечисленных функций не должна вызываться одновременно из другого потока, пока эта на завершиться.
а оказалось, что их нельзя вызывать до тех пор, пока не будет вызван хэндлер предыдущей.

всем спасибо.
Yandex
Объявления
09.04.2011, 20:03     Баг asio? или баг TCP стека?
Ответ Создать тему
Опции темы

Текущее время: 14:44. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru