C++ 使用C++/boost::asio

C++ 使用C++/boost::asio,c++,networking,boost,boost-asio,C++,Networking,Boost,Boost Asio,使用g++和boost::asio,我试图格式化包含要传输的数据大小的网络消息帧: +----------------+------------------------+ | Length | Message string | | 4 bytes | n bytes | +----------------+------------------------+ 使用32字节Linux下asio阻塞tcp echo客户机/服

使用g++和boost::asio,我试图格式化包含要传输的数据大小的网络消息帧:

+----------------+------------------------+
|  Length        |  Message string        |
|        4 bytes |                n bytes |
+----------------+------------------------+
使用32字节Linux下asio阻塞tcp echo客户机/服务器的示例,我对在帧中传输正确的大小感到厌倦。客户端应该是一台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;
}
#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;
}

客户端无法解码长度,服务器似乎没有收到正确的irt。我遗漏了什么?

从您的代码中可以看出,您实际上没有发送网络字节顺序,您的send语句类似于:
boost::asio::write(s,boost::asio::buffer(char_len,4))
char\u len
看起来像是按主机顺序填写的


可能您应该提供日志语句的输出-这可能会让事情更清楚一些…

从我在代码中看到的,您实际上没有发送网络字节顺序,您的send语句类似于:
boost::asio::write(s,boost::asio::buffer(char_len,4))
char\u len
看起来像是按主机顺序填写的


可能您应该提供日志语句的输出-这可能会让事情更清楚一些…

一个问题似乎是客户端发送一些数据,然后希望接收一些数据并将其发送回服务器,但服务器执行两次读取,然后发送一些数据。因此,第二个read()可能会收到0个字节

此外,只要有一些字节可用,read()函数就会读取。在这种情况下,即使客户端执行2 write(),服务器也可以使用第一次读取()读取所有字节,第二次读取()仍将看到0字节。您必须根据协议处理存储在缓冲区中的数据

从len到char_len的转换将无法按预期工作。由于char_len数组包含char,因此无法尝试在屏幕上显示char,但任何低于32的值都无法显示。如果您想显示每个字符的ASCII值,就必须在将它们赋给cout之前将它们转换为int

您只需按原样发送“len”:

但我没有看到任何信息发送到您的样本。我只看到客户端和服务器之间交换了一些长度

这就是我根据代码所能说的


编辑:我把字节顺序留了下来,让响应保持简短。

一个问题似乎是客户端发送一些数据,然后想要接收一些数据并将其发送回服务器,但服务器进行了两次读取,然后发送一些数据。因此,第二个read()可能会收到0个字节

此外,只要有一些字节可用,read()函数就会读取。在这种情况下,即使客户端执行2 write(),服务器也可以使用第一次读取()读取所有字节,第二次读取()仍将看到0字节。您必须根据协议处理存储在缓冲区中的数据

从len到char_len的转换将无法按预期工作。由于char_len数组包含char,因此无法尝试在屏幕上显示char,但任何低于32的值都无法显示。如果您想显示每个字符的ASCII值,就必须在将它们赋给cout之前将它们转换为int

您只需按原样发送“len”:

但我没有看到任何信息发送到您的样本。我只看到客户端和服务器之间交换了一些长度

这就是我根据代码所能说的


编辑:我保留了字节顺序,以保持响应简短。

我终于找到了出错的地方

服务器代码的底部有一个剩余读取,这阻止了第二个读取正确的字节,如@PRouleau所说

正如@Nim所指出的,客户机也编写了错误的变量

服务器的错误检查不在正确的位置

最后,我得出以下结论:

客户:

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;

    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;
}
#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;
}
#包括
#包括
#包括
#包括
#包括
#包括
使用boost::asio::ip::tcp;
枚举{max_length=1024};
int main(int argc,char*argv[])
{
尝试
{
如果(argc!=3)
{
标准:cerr 16);
char_len[3]=(len>>24);

我终于找到了哪里出了问题

服务器代码的底部有一个剩余读取,这阻止了第二个读取正确的字节,如@PRouleau所说

正如@Nim所指出的,客户机也编写了错误的变量

服务器的错误检查不在正确的位置

最后,我得出以下结论:

客户:

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;

    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;
}
#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;
}
#包括
#包括
#包括
#包括
#包括
#包括
使用boost::asio::ip::tcp;
枚举{max_length=1024};
int main(int argc,char*argv[])
{
尝试
{
如果(argc!=3)
{
标准:cerr 16);
char_len[3]=(len>>24);

std::cout@John,字节转换例程存在于该标题中:那是Linux。我以为客户端应该是Windows,在这种情况下你想要吗?@John,是的,你是对的-我没有看到那一位-顺便说一句,nojhan,如果你想要访问这些转换例程的便携方式,你应该使用:boost/asio/detail/socket_ops.hpp。客户端是应该在Windozz上,但我以前用Linux客户端Linux做过测试。@John,字节转换例程存在于该标题中:那是Linux。我以为客户端应该是Windows,你想这样吗?@John,是的,你说得对-我没看到那一点-顺便说一句,nojhan,如果你需要,你应该使用:boost/asio/detail/socket_ops.hpp想要以可移植的方式访问这些转换例程..客户端应该在Windoz上,但我以前使用Linux客户端Linux进行过测试。我重新阅读了代码示例,最后看到了“message char”。因此我认为您要查找的长度是在第一次调用read()时填充的数据变量中。Yo