Я хочу настроить связь сервер-клиент на основе сокетов. Клиенты могут подключаться к серверу и получать от него различные уведомления. Это может быть реализовано на стороне клиента следующим образом
...
Message* msg = NULL;
while ( msg = receiveMessage() )
handleMessage( msg );
...
Этот код будет выполняться в отдельном потоке на стороне клиента и должен обрабатывать различные виды уведомлений, поступающих с сервера. Но клиенты также должны иметь возможность общаться с сокетом, отправляя запросы, т.е.
Request requestMsg;
if ( sendMessage( requestMsg ) )
{
Message* response = receiveMessage();
if ( response->type() == REQUEST_REPLY )
...
}
Вопрос: Как этого добиться? Я не хочу прерывать поток чтения, но я должен получить ответ на конкретный запрос. Это сокет unix на основе локального домена.
…::: 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.
В потоке вашего получателя на клиенте вы должны использовать потокобезопасный объект для отправки и извлечения сообщений. Если у вас есть доступ к компилятору 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/