基于套接字的事件循环

时间:2013-07-09 20:16:12

标签: c++ sockets unix event-loop

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

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

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

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

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

2 个答案:

答案 0 :(得分: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.

答案 1 :(得分:1)

在客户端的接收器线程中,您应该使用线程安全对象来推送和弹出消息。如果您可以访问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<char>,以便您可以通过套接字发送/接收普通旧数据,然后填充Message以进行处理。

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