2011-09-26 2 views
0

Использование г ++ и повышение :: ASIO, я пытаюсь форматировать сообщение по сети кадров содержит размер данных, которые будут Передано:INT/символ преобразования в сети кадров с C++/повышение :: ASIO

+----------------+------------------------+ 
| Length  | Message string  | 
|  4 bytes |    n bytes | 
+----------------+------------------------+ 

Используя примеры asio-блокировки tcp echo client/server под 32-байтовым Linux, я получил возможность передать правильный размер в кадре. Предполагается, что клиент будет машиной Windows.

КЛИЕНТ:

#include <cstdlib> 
#include <cstring> 
#include <iostream> 
#include <boost/asio.hpp> 
#include <stdint.h> 
#include <arpa/inet.h> 

using boost::asio::ip::tcp; 

enum { max_length = 1024 }; 

int main(int argc, char* argv[]) 
{ 
    try 
    { 
    if (argc != 3) 
    { 
     std::cerr << "Usage: blocking_tcp_echo_client <host> <port>\n"; 
     return 1; 
    } 

    boost::asio::io_service io_service; 

    tcp::resolver resolver(io_service); 
    tcp::resolver::query query(tcp::v4(), argv[1], argv[2]); 
    tcp::resolver::iterator iterator = resolver.resolve(query); 

    tcp::socket s(io_service); 
    s.connect(*iterator); 

    std::cout << "sizeof uint32_t=" << sizeof(uint32_t) << std::endl; 

    uint32_t len = 1234; 
    std::cout << "len=" << len << std::endl; 

    // uint => char 4 
    char char_len[4]; 
    char_len[0] = (len >> 0); 
    char_len[1] = (len >> 8); 
    char_len[2] = (len >> 16); 
    char_len[3] = (len >> 24); 

    std::cout << "char[4] len=[" 
     << char_len[0] << ',' << char_len[1] << ',' 
     << char_len[2] << ',' << char_len[3] << ']' 
     << std::endl; 

    // char 4 => uint 
    uint32_t uint_len = *(reinterpret_cast<uint32_t *>(char_len)); 
    std::cout << "uint len=" << uint_len << std::endl; 

    // network bytes order 
    uint32_t net_len = htonl(len); 
    std::cout << "net_len=" << net_len << std::endl; 

    // uint => char 4 
    char net_char_len[4]; 
    net_char_len[0] = (net_len >> 0); 
    net_char_len[1] = (net_len >> 8); 
    net_char_len[2] = (net_len >> 16); 
    net_char_len[3] = (net_len >> 24); 

    std::cout << "net char[4] len=[" 
     << net_char_len[0] << ',' << net_char_len[1] << ',' 
     << net_char_len[2] << ',' << net_char_len[3] << ']' 
     << std::endl; 

    boost::asio::write(s, boost::asio::buffer(char_len, 4)); 

    char reply[max_length]; 
    size_t reply_length = boost::asio::read(s, 
     boost::asio::buffer(reply, 1)); 
    std::cout << "Reply is: "; 
    std::cout.write(reply, reply_length); 
    std::cout << "\n"; 
    } 
    catch (std::exception& e) 
    { 
    std::cerr << "Exception: " << e.what() << "\n"; 
    } 

    return 0; 
} 

SERVER:

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

using boost::asio::ip::tcp; 

const int max_length = 1024; 

typedef boost::shared_ptr<tcp::socket> socket_ptr; 

void session(socket_ptr sock) 
{ 
    try 
    { 
    for (;;) 
    { 
     char data[max_length]; 

     boost::system::error_code error; 
     size_t length = sock->read_some(boost::asio::buffer(data), error); 
     if (error == boost::asio::error::eof) 
     break; // Connection closed cleanly by peer. 
     else if (error) 
     throw boost::system::system_error(error); // Some other error. 

     uint32_t net_len; 
     size_t len_len = sock->read_some(boost::asio::buffer(reinterpret_cast<char*>(&net_len), 4), error); 
     std::clog << "net len=" << net_len << std::endl; 
     uint32_t len = ntohl(net_len); 
     std::clog << "uint len=" << len << std::endl; 

     char char_len = (char)len; 
     std::clog << "char len=" << len << std::endl; 

     boost::asio::write(*sock, boost::asio::buffer(&char_len, size_t(1))); 
    } 
    } 
    catch (std::exception& e) 
    { 
    std::cerr << "Exception in thread: " << e.what() << "\n"; 
    } 
} 

void server(boost::asio::io_service& io_service, short port) 
{ 
    tcp::acceptor a(io_service, tcp::endpoint(tcp::v4(), port)); 
    for (;;) 
    { 
    socket_ptr sock(new tcp::socket(io_service)); 
    a.accept(*sock); 
    boost::thread t(boost::bind(session, sock)); 
    } 
} 

int main(int argc, char* argv[]) 
{ 
    try 
    { 
    if (argc != 2) 
    { 
     std::cerr << "Usage: blocking_tcp_echo_server <port>\n"; 
     return 1; 
    } 

    boost::asio::io_service io_service; 

    std::cout << "Started" << std::endl; 
    std::cout << "sizeof uint32_t=" << sizeof(uint32_t) << std::endl; 
    using namespace std; // For atoi. 
    server(io_service, atoi(argv[1])); 
    } 
    catch (std::exception& e) 
    { 
    std::cerr << "Exception: " << e.what() << "\n"; 
    } 

    return 0; 
} 

Если компилировать с помощью простого скрипта:

g++ -o client -I/usr/include/boost -L/usr/lib -lboost_system -lboost_thread-mt client.cpp 
g++ -o server -I/usr/include/boost -L/usr/lib -lboost_system -lboost_thread-mt server.cpp 

Клиент не может декодировать длину и сервер не кажется для получения права irt. Что мне не хватает?

+0

Что такое ? –

+0

@John, в этом заголовке существуют процедуры преобразования байтов: http://linux.die.net/man/3/ntohl – Nim

+0

Это Linux. Я думал, что клиент должен быть Windows, и в таком случае вы хотите ? –

ответ

0

Наконец-то мне удалось найти, что пошло не так.

В нижней части кода сервера было остаточное число, которое предотвращало чтение второго правильного байта, как показано в @PRouleau.

Клиент также писал неправильную переменную, как указал @Nim.

Проверка ошибки sevrer была не в нужном месте.

Наконец я получаю следующее outpout:

Клиент:

sizeof uint32_t=4 
len=1234 
uint len=1234 
net_len=3523477504 
net char[4] len=[0,0,4,-46] 

Сервер:

Started 
sizeof uint32_t=4 
net len=3523477504 
uint len=1234 

С помощью следующего кода:

КЛИЕНТ:

#include <cstdlib> 
#include <cstring> 
#include <iostream> 
#include <boost/asio.hpp> 
#include <stdint.h> 
#include <arpa/inet.h> 

using boost::asio::ip::tcp; 

enum { max_length = 1024 }; 

int main(int argc, char* argv[]) 
{ 
    try 
    { 
    if (argc != 3) 
    { 
     std::cerr << "Usage: blocking_tcp_echo_client <host> <port>\n"; 
     return 1; 
    } 

    boost::asio::io_service io_service; 

    tcp::resolver resolver(io_service); 
    tcp::resolver::query query(tcp::v4(), argv[1], argv[2]); 
    tcp::resolver::iterator iterator = resolver.resolve(query); 

    tcp::socket s(io_service); 
    s.connect(*iterator); 

    std::cout << "sizeof uint32_t=" << sizeof(uint32_t) << std::endl; 

    uint32_t len = 1234; 
    std::cout << "len=" << len << std::endl; 

    // uint => char 4 
    char char_len[4]; 
    char_len[0] = (len >> 0); 
    char_len[1] = (len >> 8); 
    char_len[2] = (len >> 16); 
    char_len[3] = (len >> 24); 

    std::cout << "char[4] len=[" 
     << char_len[0] << ',' << char_len[1] << ',' 
     << char_len[2] << ',' << char_len[3] << ']' 
     << std::endl; 

    // char 4 => uint 
    uint32_t uint_len = *(reinterpret_cast<uint32_t *>(char_len)); 
    std::cout << "uint len=" << uint_len << std::endl; 

    // network bytes order 
    uint32_t net_len = htonl(len); 
    std::cout << "net_len=" << net_len << std::endl; 

    // uint => char 4 
    char net_char_len[4]; 
    net_char_len[0] = (net_len >> 0); 
    net_char_len[1] = (net_len >> 8); 
    net_char_len[2] = (net_len >> 16); 
    net_char_len[3] = (net_len >> 24); 

    std::cout << "net char[4] len=[" 
     << net_char_len[0] << ',' << net_char_len[1] << ',' 
     << net_char_len[2] << ',' << net_char_len[3] << ']' 
     << std::endl; 

    std::cout << "net char[4] len=[" 
     << (int)net_char_len[0] << ',' << (int)net_char_len[1] << ',' 
     << (int)net_char_len[2] << ',' << (int)net_char_len[3] << ']' 
     << std::endl; 


    boost::asio::write(s, boost::asio::buffer(net_char_len, 4)); 

    /* 
    char reply[max_length]; 
    size_t reply_length = boost::asio::read(s, boost::asio::buffer(reply, 1)); 

    std::cout << "Reply is: "; 
    std::cout.write(reply, reply_length); 
    std::cout << "\n"; 
    */ 
    } 
    catch (std::exception& e) 
    { 
    std::cerr << "Exception: " << e.what() << "\n"; 
    } 

    return 0; 
} 

SERVER:

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

using boost::asio::ip::tcp; 

const int max_length = 1024; 

typedef boost::shared_ptr<tcp::socket> socket_ptr; 

void session(socket_ptr sock) 
{ 
    try 
    { 
    for (;;) 
    { 
     char data[max_length]; 

     boost::system::error_code error; 

     uint32_t net_len; 
     size_t len_len = sock->read_some(boost::asio::buffer(reinterpret_cast<char*>(&net_len), 4), error); 

     if (error == boost::asio::error::eof) 
     break; // Connection closed cleanly by peer. 
     else if (error) 
     throw boost::system::system_error(error); // Some other error. 

     std::cout << "net len=" << net_len << std::endl; 

     uint32_t len = ntohl(net_len); 
     std::cout << "uint len=" << len << std::endl; 

     //char reply = '1'; 
     //std::cout << "char len=" << char_len << std::endl; 
     //boost::asio::write(*sock, boost::asio::buffer(&reply, size_t(1))); 
    } 
    } 
    catch (std::exception& e) 
    { 
    std::cerr << "Exception in thread: " << e.what() << "\n"; 
    } 
} 

void server(boost::asio::io_service& io_service, short port) 
{ 
    tcp::acceptor a(io_service, tcp::endpoint(tcp::v4(), port)); 
    for (;;) 
    { 
    socket_ptr sock(new tcp::socket(io_service)); 
    a.accept(*sock); 
    boost::thread t(boost::bind(session, sock)); 
    } 
} 

int main(int argc, char* argv[]) 
{ 
    try 
    { 
    if (argc != 2) 
    { 
     std::cerr << "Usage: blocking_tcp_echo_server <port>\n"; 
     return 1; 
    } 

    boost::asio::io_service io_service; 

    std::cout << "Started" << std::endl; 
    std::cout << "sizeof uint32_t=" << sizeof(uint32_t) << std::endl; 
    using namespace std; // For atoi. 
    server(io_service, atoi(argv[1])); 
    } 
    catch (std::exception& e) 
    { 
    std::cerr << "Exception: " << e.what() << "\n"; 
    } 

    return 0; 
} 
1

Из того, что я могу видеть в вашем коде, вы на самом деле не посылает сетевой порядок байт, ваш отправить заявление как: boost::asio::write(s, boost::asio::buffer(char_len, 4)); и char_len выглядит он заполнен, чтобы хост ...

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

1

Одна из проблем заключается в том, что клиент отправляет некоторые данные, а затем хочет что-то получить и отправить их обратно на сервер, но сервер делает 2 чтения, а затем отправляет что-то. Таким образом, 2-й read(), вероятно, получит 0 байт.

Кроме того, функция read() считывает, пока есть несколько доступных байтов. В этом случае, даже если клиент делает 2 write(), сервер может читать все байты с первым read(), а 2nd read() все равно будет видеть 0 байтов. Вы должны обрабатывать данные, хранящиеся в буфере, на основе вашего протокола.

Ваше преобразование из len в char_len не будет работать должным образом. Поскольку массив char_len содержит символы, cout пытается отобразить символ на экране, но любое значение ниже 32 не отображается. Если вы хотите отобразить значение ASCII для каждого символа, вы должны указать их в int перед тем, как дать их cout.

Вы должны просто послать «Леном» как есть:

boost::asio::write(s, boost::asio::buffer(&len, 4)); 

Но я не видел ни сообщение, отправленное в вас образец. Я вижу только некоторую длину обмена между клиентом и сервером.

Это все, что я могу сказать, основываясь на этом коде.

Редактировать: я оставил байтовый заказ, чтобы держать ответ коротким.

+0

Я перечитал образец кода, и я наконец увидел «сообщение char» в конце. Поэтому я думаю, что длина, которую вы ищете, находится в переменной данных, которую вы заполняете первым вызовом read(). Вы не используете его позже в коде. – PRouleau

Смежные вопросы