1

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

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

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

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

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

4

2 回答 2

2

...::: 下面的 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.
于 2013-07-09T20:50:28.487 回答
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;

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

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

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

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

于 2013-07-09T21:18:16.363 回答