【问题标题】:Create an iostream using boost asio specifying ip and port使用 boost asio 指定 ip 和端口创建 iostream
【发布时间】:2011-05-15 13:45:12
【问题描述】:

我有一个关于 boost asio 库的问题。我成功地尝试在客户端和服务器之间创建一个套接字,这涉及创建解析器以指定服务器的 ip 和端口(服务器只需要端口)和其他对象,但最重要的是,必须使用writeread_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;

为了发送和接收。 我怎样才能做到这一点? 非常感谢。

【问题讨论】:

    标签: c++ client-server iostream boost-asio


    【解决方案1】:

    你引用的 boost asio 示例代码:

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

    使用“daytime”作为对服务表的查找(通常在 linux 系统上的 /etc/services 中),这将确定白天服务的端口是 13。

    如果您想连接到不是众所周知的服务之一的端口,您可以这样做:

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

    请注意,端口号是作为字符串提供的,而不是作为无符号短整数提供的。

    当然,“localhost”可以换成IP地址“127.0.0.1”

    【讨论】:

    • 这应该是选择的答案。
    • 除了 iostream 之后不应该有 () 否则你返回一个函数?
    • @CashCow - 哈哈!我刚刚从 OP 中复制并澄清了。但很好的收获!
    • 这有利于创建 iostream,但不幸的是,由于 iostream 本身的不良性质,这对流本身不利。因此,我建议使用一个归档对象来处理 2 路入站/出站,并且会阻塞直到完整的对象流入。
    【解决方案2】:

    让我们在这里解决所有 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 本身的一个缺陷。

    因此,答案是使用 boost 存档,您可以使用文本存档或二进制存档,只要您使用相同的两端即可。如果一侧使用 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;
    

    您可能会创建一个存档并在整个过程中使用它,尤其是用于出站。对于入站,如果您收到流式错误,您可能会遇到问题,因为它会破坏您的存档。

    您可以使用文本存档而不是二进制存档。

    boost 存档会自动放入标题信息,以便知道对象何时完成,并且只有在对象完整或损坏时才会返回给您。

    注意:原始类型,例如 std::string 甚至 vector 等都由存档自动处理。您自己的类将需要特殊的重载来了解如何流式传输它们。您应该阅读 boost::archive 文档。

    注意:您可以在打开流之前将存档对象连接到流。存档围绕 streambuf 对象工作,该对象不会根据流的成功打开而改变。

    在没有 no_header 的情况下创建将是一个问题,因为存档会立即尝试在构造时使用流(读取或写入其标题)

    【讨论】:

      【解决方案3】:

      我使用Boost.Asio 编写了一个客户端/服务器系统。源代码在GitHubClient.cppServer.cpp 上提供。将Boost.Serialization 与 Boost.Asio 一起使用,我可以通过网络发送任意数据结构。不得不说,真的很厉害!

      【讨论】:

      • 好的,马上去检查...谢谢
      • 如果您愿意,可以随时向我询问有关我的实施的问题。祝你好运!
      • 好吧,我正在尝试查看您的代码...我没有您那么有经验...好吧,问题即将到来,现在我只能说:惊人的代码!!!!!!
      • 谢谢 Lidstrom 先生...我可以使用流建立连接...嗯,我对结合 Asio 的序列化非常感兴趣。在你的项目中,你能告诉我在哪里可以找到序列化过程吗?我想这段代码是另一个文件(不是 server.cpp 或 client.cpp)。
      • @CashCow 这个被接受的答案,所以我想我做到了……
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-10-16
      • 2013-06-30
      • 1970-01-01
      • 1970-01-01
      • 2012-06-26
      • 1970-01-01
      相关资源
      最近更新 更多