2013-07-09 69 views
0

我想設置基於套接字的服務器 - 客戶端通信。客戶端可以連接到服務器並從中接收不同的通知。這可以在客戶端如下基於套接字的事件循環

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

此代碼將在獨立的線程在客戶端上運行,並應處理各種通知從服務器來實現。但是,用戶還應該能夠通過發送請求與插座進行溝通,即

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

問題:如何實現這一目標?我不想中斷閱讀線程,但我應該收到對特定請求的響應。這是本地域基於流的unix套接字。

回答

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

在客戶端的接收者線程中,應該使用線程安全對象來推送和彈出消息。如果您有權訪問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>,以便您可以通過套接字發送/ recv普通舊數據並將其插入Message中並從中取出進行處理。

如果您需要關於啓動線程的幫助,請查看本教程。 http://solarianprogrammer.com/2011/12/16/cpp-11-thread-tutorial/