Цикл событий на основе сокетов

Я хочу настроить связь сервер-клиент на основе сокетов. Клиенты могут подключаться к серверу и получать от него различные уведомления. Это может быть реализовано на стороне клиента следующим образом

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

Этот код будет выполняться в отдельном потоке на стороне клиента и должен обрабатывать различные виды уведомлений, поступающих с сервера. Но клиенты также должны иметь возможность общаться с сокетом, отправляя запросы, т.е.

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

Вопрос: Как этого добиться? Я не хочу прерывать поток чтения, но я должен получить ответ на конкретный запрос. Это сокет unix на основе локального домена.

0

Решение

…::: 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> так что вы можете отправлять / извлекать обычные старые данные через сокеты и вставлять и извлекать из Message для обработки.

Если вам нужна помощь в запуске темы, ознакомьтесь с этим руководством. http://solarianprogrammer.com/2011/12/16/cpp-11-thread-tutorial/

1

По вопросам рекламы [email protected]