Обычно я раньше решал эту проблему с помощью потоков. Я создал управляющий поток, который просматривает и выполняет административные операции, такие как: проверка соединения, проверка последнего пользовательского ввода, проверка запроса на отключение сервера и т. Д. Когда это было сделано, он спал в течение полсекунды и делал все заново.
У меня тогда был отдельный поток Socket, который был создан и просто обслуживал сетевой сокет. После этого соединение будет открываться и многократно проверяться на предмет входящих сообщений от того, к кому оно подключено. Если он найдет сообщение, он обработает его и сохранит в коллекции изменчивых объектов для использования потоком управления. Если что-то случится с соединением, оно автоматически попытается разрешить, а если не сможет, то перейдет в «мертвое» состояние. Поток управления на своей следующей итерации будет очищать мертвые потоки сокетов и создавать новые при необходимости.
Отладка была кошмаром, но она была на удивление стабильной после устранения ошибок. В одном случае он успешно работал более года с десятками тысяч подключений и сотнями одновременных подключений без необходимости перезапуска или технического обслуживания.