【发布时间】:2016-05-22 08:31:58
【问题描述】:
我大约在 10 年前使用过 ASIO(我记得当时还有一个 boost.netwrok 库在很短的时间内),从那时起我一直在使用我自己的网络代码或其他一些实现或语言(例如ACE、nodejs 等)。现在我想使用 ASIO 编写简单的代码,但我无法用足够的语言来形容我有多讨厌它。
首先,我想要的是简单的同步代码,它只有几行 BSD/winsock 代码,而且使用 asio 完全是一团糟。不仅所有的代码看起来都像是满嘴乱七八糟的东西,掩盖了真实的逻辑,它还迫使我使用一些我真正想避免的东西,比如瘟疫。
所以,首先,我描述了我需要做的事情: 1) 连接到 mymagichost.com 上的服务器:1234 在 ASIO 中,这部分虽然看起来像是满口的命名空间谈话,但或多或少都可以:
#include <boost/asio.hpp>
// I'm scared what the code would look like without this one.
using boost::asio::ip::tcp;
int main()
{
boost::asio::io_service io_service;
tcp::socket sock(io_service);
tcp::resolver resolver(io_service);
boost::asio::connect(sock, resolver.resolve(
tcp::resolver::query(tcp::v4(), "mymagichost.com", "1234")));
}
我根本不明白我怎么可能无法将 1234 作为 int 传递,这是否意味着在这里传递一个字符串会将整个巨大的服务名称列表拉入我的二进制文件中,以便能够弄清楚我需要端口 1234?!什么鬼?
连接后,我需要与服务器进行简单的对话:
// when I start talking I say PING\n to the server
"PING\n"
// it replies back with 64-bit unsigned int id
"PONG <connection id>\n"
// I ask server to execute command, where <cmd id>
// is an int and connection id is that number that
// server sent to me in PONG.
"COMMAND <cmd id>:<connection id>\n"
// server executes my command
"OK <message id>\n<binary data until remote closes socket>"
使用阻塞 bsd 袜子就像 10-20 行代码:
void talk(int sock) // consider it pseudo-code
{
char buf[1024];
int cmd_id = 1234;
send(sock, "PING\n", 5, 0);
unsigned long long connection_id, msg_id;
recv(sock, buf, sizeof(buffer), 0);
sscanf(buf, "PONG %llu\n", &connection_id);
int n = sprintf(buf, "COMMAND %u:llu\n", cmd_id, connection_id);
send(sock, buf, n, 0);
vector<char> data;
for (; (n = recv(sock, buf, sizeof(buf), 0)) > 0;)
data.insert(data.end(), buf, buf+n);
sscanf(buf, "OK %llu\n%n", &msg_id, &n);
char *binary_data = buf.data()+n;
int binary_data_size = data.size()-n;
}
那么,如何在同步 asio 中做到这一点? 在我的 BSD 代码中,我有很多缺点:在收到回复时,我可能收到了部分回复,例如我需要循环接收,直到收到尾随的 '\n' (这个简单的例子可能不会发生)。 在许多接收数据的函数中,有一个正是这样做的:
boost::asio::read_until(sock, buf, '\n');
但是,与 boost::asio::read 不同,read_until 只接受 streambuf(我真的想避免像瘟疫一样)。我只是不明白,为什么它不允许我使用自己的固定缓冲区,是因为 asio dev 决定阻止我的脚射击吗?我仍然可以尊重空指针是我想要的。无论如何,没什么大不了的,我可以使用 streambuf,但这里的事情变得非常丑陋。 根据文档,在服务器 OK 回复缓冲区中的 read_until last '\n' 实际上可能包含更多数据之后,here's what the docs say:“在成功的 read_until 操作之后,streambuf 可能包含超出分隔符的其他数据。应用程序通常会离开streambuf 中的数据供后续的 read_until 操作检查。"。 现在在处理了来自服务器的最后一个 OK 回复之后,我真的别无选择,只能继续使用可怕的 streambuf 来读入所有剩余的数据(它的兆),即使我更喜欢循环并附加到我的最终缓冲区(字符串或向量)。当我读完数据后,所有从流 buf 中获取数据的方法都非常糟糕:多次复制数据或使用 istream_iterator/istreambuf_iterator 将其附加到我的容器中。在我看来,这两个都非常慢,我的视觉工作室实际上挂了几秒钟(顺便说一下,我没有收到数据)。
那么,用 asio 处理它的正确方法是什么?
【问题讨论】:
-
请教一个问题。咆哮只会让你看起来不耐烦,不值得费心去解释。 “其他”库可能是
cppnetlib并且仍然存在。现在还有很多其他的。 -
@sehe 我知道它们存在,但我想完全使用 boost 编写一些测试项目,这就是重点。否则我永远不会碰 asio。
标签: c++ boost network-programming boost-asio