Я пытаюсь построить несколько клиентов - одну структуру сервера. Каждый клиент устанавливает соединение с сервером, и сервер поддерживает это соединение.
Клиент имеет два потока (thread1, thread2), работающих асинхронно и совместно использующих 1 сокет для отправки, получения. Два потока каждый содержит несколько функций отправки, получения. Чтобы сервер обслуживал каждого клиента, он также должен создать два клиентских обработчика с одним сокетом.
Я хочу, чтобы мой сервер создавал подпрограмму обработки клиента (асинхронную задачу) только тогда, когда их сокет (каждый клиент) готов к чтению для сохранения ресурса. Я пытаюсь реализовать эту функцию, используя метод Socket.Select.
Вот моя предполагаемая реализация подпрограммы выбора на стороне сервера с использованием кода, близкого к c #.
server.selectRoutine(){
while(!serverSocket.closed())
{
checkReadList client_connect_socket_list_copy=new ArrayList<Socket>(client_connect_socket_list) ;
Socket.Select(client_connect_socket_list_copy, null,null) ;
foreach(Socket s in client_connect_socket_list_copy)
{
client_connect_info info=client_connect_info_dict.Items[s] ;
if(!info.is_client_thread1_handler_active)
{
info.is_client_thread1_active=true ;
clServerEntranceHandler handler=new clServerEntranceHandler() ;
Task.Run(handler.run()) ;
}
if(!info.is_client_thread2_handler_active)
{
info.is_client_thread2_active=true ;
clServerExitHandler handler=new clServerExitHandler() ;
Task.Run(handler.run()) ;
}
}
Код Объяснение
- Client_connect_socket_list: содержит подключенных в данный момент клиентов
- client_connect_info_dict: клиентский информационный словарь подключения, сопоставленный для каждого сокета в качестве ключа.
- client_connect_info: состоит из (is_client_thread1_Handler_Active, is_client_thread2_Handler_Active)
- Выберите только те сокеты, которые готовы для чтения после Socket.Select
- Запустить обработчик для тех сокетов, где обработчик в данный момент не создан,
info.is_client_thread1_Handler_Active=false
. И установить info.is_client_thread1_Handler_Active=true
. Это связано с тем, что внутри уже созданного обработчика будет несколько recv
функций, и они будут в режиме блокировки. Поэтому, когда клиент отправляет сообщение на сервер, предназначенный для функции recv
, заблокированной в уже созданном обработчике, Socket.Select также будет считать этот сокет готовым для чтения и в итоге создаст новый обработчик. Чтобы избежать этого, мне нужно проверить, активен ли обработчик. После того, как обработчик завершит работу, он установит info.is_client_thread1_Handler_Active= false
внутри. То же самое для обработчика client_thread2.
Я думаю, что теперь мне нужно синхронизировать эту процедуру с каждым уже созданным обработчиком. Например, избегайте ситуации, подобной функции recv
внутри обработчика P рывка сообщения A внутри очереди сообщений сокета обработчика P после Socket.Select пильного сообщения A внутри очереди сообщений. Затем обработчик P завершится и установит info.is_Handler_Active=false
. Затем selectRoutine
снова создаст новый обработчик для сообщения A, уже прочитанного обработчиком P, и возникнет проблема.
Я хочу знать, есть ли серьезные проблемы с этой схемой, что я не должен использовать ее. А если так, то я хочу знать, как лучше реализовать несколько клиентов - один сервер с возможностью масштабирования.