首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何用boost::asio实现嵌套协议?

如何用boost::asio实现嵌套协议?
EN

Stack Overflow用户
提问于 2016-04-12 18:16:26
回答 2查看 762关注 0票数 2

我正在尝试编写一个服务器来处理协议B之上的协议A。

协议A是HTTP或RTSP,协议B是二进制数据包的简单序列:

代码语言:javascript
复制
[packet length][...encrypted packet data...]

所以我想用这样的东西:

代码语言:javascript
复制
boost::asio::async_read_until(socket, inputBuffer, "\r\n\r\n", read_handler);

但是,使用一些连接到协议B处理程序的伪套接字来代替socket

我有一些想法:

  1. 忘记async_readasync_read_until等,为A和B编写两个状态机。
  2. 混合方法:协议B的async_read_*,A的状态机。
  3. 制作内部代理服务器。

我不喜欢(1)和(2),因为

  • 很难将A与B分离(我希望能够禁用协议B)。
  • 丑陋。

(3)看起来很丑:-)

所以问题是:我如何实现这一点?

EN

回答 2

Stack Overflow用户

发布于 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实现它们),并在更高级别上使用它们。因此,您将从数据处理的推送方法转向拉式方法,这有一些优点和缺点。

票数 1
EN

Stack Overflow用户

发布于 2016-04-15 09:22:45

我不会重温boost::asio,因为这似乎更像是一种设计模式,而不是网络模式。我会用状态模式。这样你就可以随时改变协议了。

代码语言:javascript
复制
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;
    }
};

初始化起始协议时,

代码语言:javascript
复制
std::unique_ptr<net_protocol> proto(new http_protocol(sock));

然后你会读到:

代码语言:javascript
复制
//Result result;
proto.reset(proto->read(result));

编辑: if()返回的新策略实际上是一个状态机

如果您关心这些异步读取,因此无法判断哪些返回策略,则让策略类在它们的read_handler中调用一个通知方法

代码语言:javascript
复制
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个具体类和一个虚拟类),而且它可能非常接近战略模式

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/36581082

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档