【问题标题】:Socket based event loop基于套接字的事件循环
【发布时间】:2013-07-07 14:23:20
【问题描述】:

我想设置基于套接字的服务器-客户端通信。客户端可以连接到服务器并从中接收不同的通知。这可以在客户端实现如下

...
Message* msg = NULL;
while ( msg = receiveMessage() )
    handleMessage( msg );
...

此代码将在客户端的单独线程中运行,并应处理来自服务器的不同类型的通知。但是客户端也应该能够通过发送请求与套接字进行通信,即

Request requestMsg;
if ( sendMessage( requestMsg ) )
{
    Message* response = receiveMessage();
    if ( response->type() == REQUEST_REPLY )
    ...
}

问题:如何做到这一点?我不想中断阅读线程,但我应该收到对特定请求的响应。这是基于本地域流的 unix 套接字。

【问题讨论】:

    标签: c++ sockets unix event-loop


    【解决方案1】:

    ...::: 下面的 ASCII 内容 :::...

    如果你讨厌艺术,或者 ASCII 到此为止。

    下面的示意图不会阻塞服务器和客户端。
    许多 MMORPGS 使用它来保护连接并使协议更难破解。

         [================ ~~ Server ~~ ================]
         [ Select / Poll ]*4             5*[ Dispatcher ]
            ||      /\                             ||
            ||      ||                             ||
         *1 ||      ||2*                         *3||
            ||      ||                             ||
            \/      ||                             \/
         [ Thread 1 Basic IO ]       [ Thread 2 Listener]
         [=============== ~~ Client ~~ =================]
    
     *1 // send
     *2 // recv
    
     *3 // bind listen accept recv OR they will communicate using UDP
        // to a different port
    
     *4 // the server will process the clients normally
        // using select / poll / epoll / kqueue / `/dev/poll`
    
     *5 // The client will either setup a temporary server to process
        // the servers opcodes
     OR
        // It will accept UDP packets using recvfrom()
    
     *5 // I'd recommend using UDP so that the server can loop through the existing
        // connections and sendto() the opcodes which will be provided via a message
        // queue.
    

    【讨论】:

      【解决方案2】:

      在客户端的接收线程中,您应该使用线程安全对象来推送和弹出消息。如果您可以访问 C++11 编译器,您可以考虑使用std::vector<std::shared_ptr<Messsage>>。这是一个线程安全对象的简单实现,可能适合您的需求。

      class MessageQueue
      {
      public:
        typedef std::shared_ptr<Message> SpMessage;
      
        bool empty() const {
          std::lock_guard<std::mutex> lock(mutex_);
          return messages_.empty();
        }
      
        SpMessage pop() {
          std::lock_guard<std::mutex> lock(mutex_);
          SpMessage msg(messages_.front());
          messages_.pop_front();
          return msg;
        }
      
        void push(SpMessage const& msg)
          std::lock_guard<std::mutex> lock(mutex_);
          messages_.push_back(msg);
        }
      
      private:
        MessageQueue(const MessageQueue&);  // disable 
        MessageQueue& operator=(const MessageQueue&);  // disable
        std::vector<SpMessage> messages_;
        std::mutex mutex_;
      };
      
      typedef std::shared_ptr<MessageQueue> SpMessageQueue;
      

      此时,您有一个可共享的、线程安全的队列。在主线程和套接字线程之间共享此队列。如果您希望发送也位于单独的线程上,也可以使用两个,例如,从一个消息队列中弹出,处理它,然后在另一个队列中排队响应。

      你可以在你的服务器上使用同样的东西。

      消息类应该能够存储std::vector&lt;char&gt;,以便您可以通过套接字发送/接收普通旧数据,并将内容放入和拉出Message进行处理。

      如果您在启动线程方面需要帮助,请查看本教程。 http://solarianprogrammer.com/2011/12/16/cpp-11-thread-tutorial/

      【讨论】:

      • 能否有一个使用这个 MessageQueue 类的完整示例?
      猜你喜欢
      • 1970-01-01
      • 2018-06-14
      • 2021-11-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-08-13
      • 2016-09-01
      • 1970-01-01
      相关资源
      最近更新 更多