我正在尝试编写一个服务器来处理协议B之上的协议A。
协议A是HTTP或RTSP,协议B是二进制数据包的简单序列:
[packet length][...encrypted packet data...]所以我想用这样的东西:
boost::asio::async_read_until(socket, inputBuffer, "\r\n\r\n", read_handler);但是,使用一些连接到协议B处理程序的伪套接字来代替socket。
我有一些想法:
async_read、async_read_until等,为A和B编写两个状态机。async_read_*,A的状态机。我不喜欢(1)和(2),因为
(3)看起来很丑:-)
所以问题是:我如何实现这一点?
发布于 2016-04-21 12:14:44
我以前做过类似于您的答案(2)的事情--首先使用async_read调用读取标题,然后使用另一个async_read读取长度,并将剩余的内容转发给手写状态机。但我不一定建议您这样做--您可能因此获得协议B的零拷贝IO,但是当您知道始终有数据在后面时,执行IO调用读取4-8字节的头是非常浪费的。问题是,您对这2层的网络抽象将是不同的-所以您提到的解耦问题确实存在。
使用固定长度的缓冲区,只调用async_read,然后使用2个嵌套状态机处理数据(就像您在应答(1)中提出的那样),效果很好。您的状态机将简单地被推送一些新的接收数据(直接从套接字或从较低的状态机)并处理这些数据。这意味着A不会在这里耦合到B,因为如果输入/输出数据格式匹配,您可以从asio直接将数据推送到A状态机。
与此类似的是Netty和Facebook next库中使用的模式,其中有处理程序从管道中的较低处理程序中推送数据,根据输入执行它们的操作,并将解码的数据输出到下一个处理程序。这些处理程序可以是状态机,但取决于协议的复杂性,不一定非得是状态机。你可以从中得到一些启示,例如,看看一些Wangle:https://github.com/facebook/wangle/blob/master/tutorial.md
如果您不想将数据从一个协议处理程序推送到另一个协议处理程序,而是积极地读取它(很可能是异步的),您也可以设计一些接口(比如实现ByteReader (.)的接口。方法或PacketReader,它允许读取完整的消息而不是字节),通过代码实现它们(也可以通过asio实现它们),并在更高级别上使用它们。因此,您将从数据处理的推送方法转向拉式方法,这有一些优点和缺点。
发布于 2016-04-15 09:22:45
我不会重温boost::asio,因为这似乎更像是一种设计模式,而不是网络模式。我会用状态模式。这样你就可以随时改变协议了。
class net_protocol {
protected:
socket sock;
public:
net_protocol(socket _sock) : sock(_sock) {}
virtual net_protocol* read(Result& r) = 0;
};
class http_protocol : public net_protocol {
public:
http_protocol(socket _sock) : net_protocol(_sock) {}
net_protocol* read(Result& r) {
boost::asio::async_read_until(socket, inputBuffer, "\r\n\r\n", read_handler);
// set result, or have read_handler set it
return this;
}
};
class binary_protocol : public net_protocol {
public:
binary_protocol(socket _sock) : net_protocol(_sock) {}
net_protocol* read(Result& r) {
// read 4 bytes as int size and then size bytes in a buffer. using boost::asio::async_read
// set result, or have read_handler set it
// change strategy example
//if (change_strategy)
// return new http_strategy(sock);
return this;
}
};初始化起始协议时,
std::unique_ptr<net_protocol> proto(new http_protocol(sock));然后你会读到:
//Result result;
proto.reset(proto->read(result));编辑: if()返回的新策略实际上是一个状态机
如果您关心这些异步读取,因此无法判断哪些返回策略,则让策略类在它们的read_handler中调用一个通知方法
class caller {
std::unique_ptr<net_protocol> protocol;
boost::mutex io_mutex;
public:
void notify_new_strategy(const net_protocol* p) {
boost::unique_lock<boost::mutex> scoped_lock(mutex);
protocol.reset(p);
}
void notify_new_result(const Result r) { ... }
};如果不需要动态更改已使用的协议,则不需要状态,因此read()将返回Result (或者,无效并调用caller::notify_new_result(const Result) (如果异步))。尽管如此,您仍然可以使用相同的方法(2个具体类和一个虚拟类),而且它可能非常接近战略模式
https://stackoverflow.com/questions/36581082
复制相似问题