使用Boost Asio创建一个iostream,并指定IP和端口。

6

我有一个关于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;

为了发送和接收信息,我该怎么做呢?非常感谢。

3个回答

19

你引用的boost asio示例代码:

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

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

如果您想连接到不是众所周知的服务之一的端口,可以使用类似下面的命令:

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

请注意,端口号应该被提供为字符串,而不是无符号短整数,尽管人们可能会尝试这样做。

当然,"localhost" 可以替换为 IP 地址 "127.0.0.1"。


6
这应该是被选中的答案。 - Talia
1
除了iostream后面不应该有(),否则你会返回一个函数之外,还有什么问题吗? - CashCow
@CashCow - 哈哈!我只是从原帖中复制并澄清了一下。但你发现得真好! - Arunas
这对于创建iostream很好,但不幸的是,由于iostream本身的质量较差,对于流本身并不好。因此,我建议使用一个处理双向入站/出站的存档对象,并将阻塞直到完整对象被流式传输。 - CashCow

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 );

其中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创建,将会出现问题,因为归档文件会立即尝试在构造过程中使用流(读取或写入其标头)。

1

好的,我马上去检查一下...谢谢。 - Andry
谢谢Lidstrom先生...我能够使用流建立连接...好的,我对结合Asio的序列化非常感兴趣。在您的项目中,您能告诉我在哪里可以找到序列化过程吗?我猜这段代码在另一个文件中(不是server.cpp或client.cpp)。 - Andry
太好了!看一下这些命令。例如,FetchCommand和SyncCommand2。它们在Server.cpp和Client.cpp中使用。 - Daniel Lidström
并非每个人都能使用GitHub。有些公司会屏蔽它。回答问题时不应该依赖于从GitHub下载某些内容。这是一个糟糕的回答。请直接回答问题。 - CashCow
1
@CashCow 这是被接受的答案,所以我想我做对了... - Daniel Lidström
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接