Создайте iostream, используя boost asio, указав ip и порт - PullRequest
6 голосов
/ 25 ноября 2010

У меня проблема с буст-библиотеками asio. Я успешно попытался создать сокет между клиентом и сервером, это включает создание распознавателей, чтобы указать ip и порт на сервер (серверу нужен только порт) и другие объекты, но, самое главное, необходимо использовать write и read_some как функции для чтения и записи из / в сокет. Я был бы очень признателен за использование потока, и это возможно в boost asio, но это странно ... Почти во всех примерах, использующих потоки, для создания сервера необходимо предоставить порт, хорошо, давайте поговорим о клиенте ... на стороне клиента, необходимо использовать конструктор iostream, чтобы указать координаты для подключения потока, вот код :

tcp::iostream() s(argv[1], "daytime");

Ну, я не очень понимаю, что передается в первом параметре, и действительно не знаю, что может представлять дневное время ... По сути, здесь я говорю: «Эй, поток, ты должен подключиться к этому серверу ...», но как я могу указать ip и порт этого сервера? Обратите внимание, что, напротив, все почти ясно, на стороне сервера:

boost::asio::io_service io_s;
tcp::acceptor acc(io_s, tcp::endpoint(tcp::v4(), 1950));
for (;;) {
   tcp::iostream stream;
   acc.accept(*stream.rdbuf());
   stream << "Message" << std::endl;
}

Используя эту модель, я бы хотел использовать

stream << mymessage_to_send << std::endl;
stream >> a_string_containing_my_message;

для отправки и получения. Как я могу это сделать? Большое спасибо.

Ответы [ 3 ]

18 голосов
/ 18 октября 2013

Пример расширенного кода asio, который вы цитировали:

tcp::iostream s(argv[1], "daytime");

использует «дневное время» для поиска в таблице служб (обычно в / etc / services в системе linux), которая идентифицирует этот портдля дневной службы - 13.

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

tcp::iostream s("localhost", "57002"); 

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

Конечно, «localhost» можно заменить на IP-адрес «127.0.0.1»

1 голос
/ 25 ноября 2010

Я написал систему клиент / сервер, используя Boost.Asio . Источник доступен на GitHub : Client.cpp и Server.cpp . Использование Boost.Serialization вместе с Boost.Asio позволяет мне отправлять произвольные структуры данных по проводам. Надо сказать, это довольно впечатляюще!

0 голосов
/ 19 июля 2017

Давайте решим все 3 вопроса здесь:

Создание iostream на стороне клиента сокета .

Это действительно просто:

boost::asio::ip::tcp::iostream socketStream;
socketStream.connect( hostname, std::to_string( port ) );

Вы должны проверить состояние потока, чтобы увидеть, успешно ли он подключен.

Создание iostream на стороне сервера сокетов .

Предположим, у вас есть объект-акцептор, и он связан и слушает ..

boost::asio::ip::tcp::iostream connectionSocketStream; // from the connection object
acceptor.accept( *connectionSocketStream.rdbuf() );

// или

acceptor.async_accept( *connectionSocketStream.rdbuf(), callback );

где обратный вызов - это функция, которая принимает код ошибки.

Потоковые объекты

Теперь для самой потоковой передачи, и здесь ваша проблема заключается в том, что при потоковой передаче строки «Message» клиентская сторона должна знать, где начинается и заканчивается это сообщение, и обычный iostream не будет писать ничего, чтобы указать это. Это недостаток самого iostream.

Поэтому ответом является использование буст-архива, и вы можете использовать текстовый или бинарный архив, если вы используете одни и те же оба конца. Даже не имеет значения, использует ли одна сторона 64-битный байтовый код, а другая - 32-битный байтовый или другой микс.

Используя бинарный архив, вы отправите сообщение следующим образом:

boost::archive::binary_oarchive oarch( socketStream, boost::archive::no_header );
oarch << "Message";

Не забудьте очистить поток (socketStream, а не oarch) после завершения отправки всего, что вы хотите отправить на этом этапе.

и получите сообщение

boost::archive::binary_iarchive iarch( socketStream, boost::archive::no_header );
iarch >> message;

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

Вы можете использовать текстовый архив вместо бинарного.

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

Примечание: примитивные типы, например, std :: string и даже vector и т. Д., Автоматически обрабатываются архивом. Ваши собственные классы будут нуждаться в специальных перегрузках относительно того, как их передавать. Вам следует прочитать документацию boost :: archive.

Примечание. Вы можете подключить объект архива к потоку до его открытия. Архив работает вокруг объекта streambuf, который не изменяется в зависимости от успешного открытия потока.

Создание без no_header было бы проблемой, хотя архивы сразу пытаются использовать поток при построении (для чтения или записи своего заголовка)

...