1 байт идентификатор (семантическое значение данных)
unsigned int (количество байтов в данных, так как некоторые фрагменты данных могут изменять размер)
полезная нагрузка
Глядя на пример кода в документации, я немного запутался в том, как я должен извлекать байт, не говоря уже о беззнаковом целом из начального и конечного итераторов. Я создал свои итераторы как typedef boost::asio::buffers_iterator<
boost::asio::streambuf::const_buffers_type> iterator;
но даже тогда я не уверен, что это за тип, так как я не знаю, что такое const_buffers_type. Я перешел по некоторым ссылкам в документации и обнаружил, что это "определена реализацией", но я думаю, что могу ошибаться. Итак, два моих конкретных вопроса:
как я могу использовать эти два итератора для чтения беззнакового целого числа?
на какой тип указывают эти итераторы?
Спасибо!
Можете ли вы четко указать, как вы определяете конец пакета? Kornel Kisielewicz 03.01.2010
Пример функции сопоставления представлен в документации.
std::pair<iterator, bool>
match_whitespace(iterator begin, iterator end)
{
iterator i = begin;
while (i != end)
if (std::isspace(*i++))
return std::make_pair(i, true);
return std::make_pair(i, false);
}
Разыменование i здесь извлекает один байт. Вам нужно вытащить достаточно байтов, чтобы соответствовать int.
Однако помните, что обратный вызов - не единственный вариант для read_until. На самом деле он самый сложный. Вы уверены, что недостаточно использовать регулярное выражение?
В любом случае, учитывая, что ваше чтение не ограничено, гораздо лучше было бы использовать async_read_some, пока вы не прочитаете размер, а затем async_read_some хотя бы с чтением.
Ответ 2 · рейтинг 1 · Fire Lancer
У меня формат сообщения очень похож на ваш (16-битная длина полезной нагрузки, 8-битный идентификатор/тип пакета, за которым следует полезная нагрузка для меня). Я сделал это с трехфазным чтением и массивом указателей на функции для обработки разных вещей. Я использовал boost::asio::async_read для чтения известных сумм за раз.
Это упрощенная версия моего кода:
//call this to start reading a packet/message
void startRead(boost::asio::ip::tcp::socket &socket)
{
boost::uint8_t *header = new boost::uint8_t[3];
boost::asio::async_read(socket,boost::asio::buffer(header,3),
boost::bind(&handleReadHeader,&socket,header,
boost::asio::placeholders::bytes_transferred,boost::asio::placeholders::error));
}
void handleReadHeader(boost::asio::ip::tcp::socket *socket,
boost::uint8_t *header, size_t len, const boost::system::error_code& error)
{
if(error)
{
delete[] header;
handleReadError(error);
}
else
{
assert(len == 3);
boost::uint16_t payLoadLen = *((boost::uint16_t*)(header + 0));
boost::uint8_t type = *((boost::uint8_t*) (header + 2));
delete[] header;
//dont bother calling asio again if there is no payload
if(payLoadLen > 0)
{
boost::uint8_t *payLoad = new boost::uint8_t[payLoadLen];
boost::asio::async_read(*socket,boost::asio::buffer(payLoad,payLoadLen),
boost::bind(&handleReadBody,socket,
type,payLoad,payLoadLen,
boost::asio::placeholders::bytes_transferred,boost::asio::placeholders::error));
}
else handleReadBody(socket,type,0,0,0,boost::system::error_code());
}
}
void handleReadBody(ip::tcp::socket *socket,
boost::uint8_t type, boost::uint8_t *payLoad, boost::uint16_t len,
size_t readLen, const boost::system::error_code& error)
{
if(error)
{
delete[] payLoad;
handleReadError(error);
}
else
{
assert(len == readLen);
//passes the packet to the appropriate function for the type
//you could also use a switch statement or whatever
//to get the next packet you must call StartRead again
//personally I choose to do this from the actaul handler
//themselves
handlePacket(type,payLoad,len,error);
}
}