Достаточно, чтобы клиент выделил только один сокет (и подключил одно TCP-соединение), при условии, что у вас есть четко определенный протокол обмена сообщениями между вашим клиентом и сервером.
В частности, я подозреваю, что вы ощущаете потребность во втором соединении с сокетом TCP в первую очередь потому, что вы не уверены в том, как решение с одним сокетом сможет обрабатывать несколько различных видов операций (например, вызовы RPC и асинхронных уведомлений) правильно, без одного типа операций, мешающего функционированию другого.
В чисто схеме передачи сообщений обработка всего через один сокет проста - когда ваш клиент хочет отправить сообщение на сервер, он вызывает вашу функцию SendMessage()
(или как вы ее называете), и ваш код ставит в очередь байты для отправки через сокет; и наоборот, когда сервер отправляет сообщение вашему клиенту, ваш код ввода-вывода получает байты, и, если все байты сообщения были получены, он анализирует их и вызывает соответствующую функцию обратного вызова (MessageReceived()
или что-то еще) реагировать на них соответствующим образом. Поскольку ваш клиент никогда нигде не блокируется (за исключением, возможно, некоторых вызовов типа WaitForNextEvent()
, таких как select()
или poll()
), интеграция нескольких одновременных задач не является проблемой.
В общем, я рекомендую не использовать семантику в стиле RPC (т. Е. Когда ваш клиентский код вызывает вызов функции, которая скрывает сетевую операцию, а вызов функции не возвращается до тех пор, пока ответ не будет получен обратно с сервера), потому что он оставляет вашего клиента во власти сервера и подключения к сети - в частности, он заставит ваш клиентский поток зависать (блокироваться при вызове RPC) всякий раз, когда происходит временное отключение сети, что не очень хороший пользователь опыт.
Тем не менее, если вы должны использовать семантику в стиле RPC, асинхронные уведомления все еще возможны только с одним сокетом; вам просто нужно включить код в ваши RPC-функции, который дает им возможность вызывать соответствующую функцию обратного вызова (т. е. SomeAsynchronousEventOccured()
или как вы хотите ее вызывать), когда они получают сообщение об асинхронном событии, произошедшем из сокета. Обратите внимание, что это означает, что функция асинхронного обратного вызова может быть вызвана до того, как ваша RPC-функция вернет свой сетевой результат, что может быть немного удивительно для некоторых программистов, поэтому обязательно документируйте, что это возможно. (По крайней мере, он по-прежнему вызывается в том же потоке, поэтому условия гонки не будут проблемой, хотя могут возникнуть проблемы с повторным входом)