Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ C++;设计:多个TCP客户端、boost asio和观察器_C++_Design Patterns_Boost Asio - Fatal编程技术网

C++ C++;设计:多个TCP客户端、boost asio和观察器

C++ C++;设计:多个TCP客户端、boost asio和观察器,c++,design-patterns,boost-asio,C++,Design Patterns,Boost Asio,在我的系统中,我有一大堆TCP客户机,我对如何设计它有点困惑[我的大部分经验都是用C编写的,因此不安全]。我正在使用boost ASIO管理连接。这些是我拥有的组件 TCPStream类:boost asio上的薄包装器 IPC协议,通过TCP实现协议: 基本上,每条消息都以类型和长度字段开头 因此,我们可以从流中读取单个消息 处理消息的连接类 监视连接的观察者类 我编写的是伪C++代码,简洁。我想你会明白的 class TCPStream { boost::asio::socket

在我的系统中,我有一大堆TCP客户机,我对如何设计它有点困惑[我的大部分经验都是用C编写的,因此不安全]。我正在使用boost ASIO管理连接。这些是我拥有的组件

  • TCPStream类:boost asio上的薄包装器
  • IPC协议,通过TCP实现协议: 基本上,每条消息都以类型和长度字段开头 因此,我们可以从流中读取单个消息
  • 处理消息的连接类
  • 监视连接的观察者类
我编写的是伪C++代码,简洁。我想你会明白的

class TCPStream {
   boost::asio::socket socket_;
public:

   template <typename F>
   void connect (F f)
   {
       socket_.connect(f);
   }

   template <typename F>
   void read (F f)
   {
      socket_.read(f);
   }
};

class IpcProtocol : public TCPStream {
public:
    template <typename F
    void read (F f)
    {
        TCPStream::read(
              [f] (buffer, err) {

                while (msg = read_indvidual_message(buffer)) {
                      // **** this is a violation of how this pattern is 
                      // supposed to work. Ideally there should a callback 
                      // for individual message. Here the same callback
                      // is called for N no. of messages. But in our case  
                      // its the same callback everytime so this should be      
                      // fine - just avoids some function calls.
                      f(msg);
                };
              };
         )
    }
};
类tcp流{
boost::asio::socket-socket;
公众:
模板
空连接(F)
{
插座连接(f);
}
模板
无效读取(F)
{
插座读数(f);
}
};
IPC类协议:公共TCPStream{
公众:
模板连接();});
读(
[self=shared_from_this()](消息,错误){
如果(!err)
自我->过程(msg);
}否则{
self->error();
}   
});
}
空连接()
{
observer.notify_connected(从_this()共享_);
}
无效错误()
{
observer.notify_error(从_this()共享_);
}
};
此模式以这种或那种方式对所有连接重复。 消息由连接类本身处理。但它会让你知道的 其他事件[连接,错误]到观察者。原因-

  • 每次断开连接时,请重新启动连接
  • 一群人需要知道是否建立了联系,这样他们才能 向服务器发送初始请求/配置
  • 根据多个连接的连接状态,需要执行一些操作 如果建立了连接1和连接2,则启动连接3等
  • 我添加了一个中间观察者类,这样每次重新启动连接时,观察者都必须直接连接到该连接。每次连接中断时,都会删除连接类并创建新的连接类

     class Listeners {
    public:
        virtual void notify_error(shared_ptr<Connection>) = 0;
        virtual void notify_connect(shared_ptr<Connection>) = 0;
        virtual void interested(int type) = 0;
    };
    
    
    class Observer {
       std::vector<Listeners *> listeners_;
    public:
    
       void notify_connect(shared_ptr<Connection> connection)
       {
            for (listener : listeners_) {
                if (listener->interested(connection->type())) {
                    listener->notify_error(connection);
                }
            }       
       }
    };
    
    类侦听器{
    公众:
    虚拟无效通知错误(共享ptr)=0;
    虚拟void notify_connect(共享_ptr)=0;
    虚空(int类型)=0;
    };
    类观察员{
    std::向量侦听器;
    公众:
    无效通知连接(共享ptr连接)
    {
    for(侦听器:侦听器){
    如果(侦听器->感兴趣(连接->类型()){
    侦听器->通知错误(连接);
    }
    }       
    }
    };
    
    现在是这个作品的一个粗略的原型。但是我想知道这个课程设计 好的。有多个流式服务器将持续生成状态并将其发送到我的模块,以h/w格式编程状态。这需要扩展,因为将来将添加更多客户端

    穿线
    遗留代码每个TCP连接有一个线程,这很好。在这里,我试图处理同一线程上的多个连接。仍然会有多个线程调用ioservice。因此,观察器将在多个线程上运行。我计划为每个侦听器设置一个互斥锁,这样侦听器就不会同时获得多个事件。

    HTTP通过TCP实现一个协议,因此HTTP服务器是您设计的一个良好起点,特别是:
    HTTP服务器2
    HTTP服务器3
    HTTP服务器4


    注意:连接生存期可能是一个问题,特别是因为您打算将类成员函数用作处理程序,请参见此处的问题和答案:。

    HTTP通过TCP实现协议,因此HTTP服务器是您设计的良好起点,尤其是:
    HTTP服务器2
    HTTP服务器3
    HTTP服务器4


    注意:连接生存期可能是一个问题,特别是因为您打算将类成员函数用作处理程序,请参阅此处的问题和答案:。

    查看HTTP示例确实有帮助。谢谢你的指点。至于生命时间。连接在执行异步操作时为自身提供共享ptr,以使其保持活动状态,直到调用异步完成处理程序为止。你看到这里面有漏洞吗?是的@MGH我确实看到漏洞,特别是:内存和资源泄漏。我希望服务器或客户端拥有共享ptr,并使用“非”成员(或“静态”)函数回调将弱ptr传递给连接。例如,查看连接类。我查看了
    类连接。我认为我现在所做的只有几点不同。创建共享指针的静态
    create
    例程。我认为这个想法是为了强制连接总是作为共享指针创建的?(不确定为什么在
    create()
    中使用
    make_shared
    )-好的。但是我的是一个伪代码,用来显示类关系,我跳过了细节。在异步回调中,您为self提供弱ptr,正如我为self提供共享ptr一样。考虑到在任何一种情况下我们都需要关闭套接字,我认为共享ptr是好的,它避免了
    弱ptr.lock()
    ==共享指针副本,但我看不到资源泄漏。您可能是对的,
    弱ptr
    不是必需的。但是,它们允许连接类遵循
    RAII
    习惯用法,因此它们是异常安全的。异常可能导致
    shared\u ptr
    s的资源泄漏。查看HTTP示例确实有所帮助。谢谢你的指点。至于生命时间。连接在执行异步操作时为自身提供共享ptr,以使其保持活动状态,直到调用异步完成处理程序为止。你看到这里面有漏洞吗?是的@MGH我确实看到漏洞,特别是:内存和资源泄漏。我希望服务器或客户机拥有共享ptr,并使用“非”成员(或“st”)将弱ptr传递给连接
     class Listeners {
    public:
        virtual void notify_error(shared_ptr<Connection>) = 0;
        virtual void notify_connect(shared_ptr<Connection>) = 0;
        virtual void interested(int type) = 0;
    };
    
    
    class Observer {
       std::vector<Listeners *> listeners_;
    public:
    
       void notify_connect(shared_ptr<Connection> connection)
       {
            for (listener : listeners_) {
                if (listener->interested(connection->type())) {
                    listener->notify_error(connection);
                }
            }       
       }
    };