Поведение Socket.AsyncSend, когда удаленный клиент перестает получать - PullRequest
0 голосов
/ 06 марта 2011

Я столкнулся с проблемой, когда у меня происходит множество AsyncSends с десятками клиентских сокетов, и в тот момент, когда какой-либо удаленный клиент прекращает получать, но на самом деле не отключается, приложение быстро отключает всеSocketAsyncEventArgs (также известный как sae) Я предварительно выделил, потому что они не выпущены, так как SendAsync не завершается.Очевидное решение этого заключается в реализации очереди отправки для каждого клиента, что звучит достаточно просто, но мне неясно, каковы особенности.У меня есть одно sae, выделенное для получения клиентом, которое работает идеально, и в идеале я хотел бы выделить одно sae для асинхронных отправок клиента.

Я понимаю, что я захожу и задаю вопрос, который является скрытойна решение «дай мне код» смотрят свысока, но я, честно говоря, не смог найти много, ни для методов .XAsync, для которых у Microsoft ужасно плохой пример, ни для очереди отправки в целом.

Правка для @ JN

Я забыл упомянуть об этом, но я - на самом деле - использую кучу предварительно выделенных sae, хранящихся в управляющем классе, который внутренне использует ConcurrentBag.При одном соединении в тестовом сценарии, когда 20 небольших сообщений отправляются в секунду (это чуть более чем вдвое превышает количество сообщений, которые фактически будут отправлены на рабочем сервере), сервер съедает 500 предварительно выделенных пакетов sae за несколько секунд.Если я реализую код «create if empty», число sae быстро возрастает до тысяч.

Я понимаю функциональность, которую предоставляют асинхронные методы класса Socket, но если есть сбой сети или что-то подобное, этопроблема будет сразу бомбить сервер в течение нескольких секунд.Очередь отправки звучит как отличное решение, но я понятия не имею, стоит ли это делать в высокопроизводительной рабочей среде или нет.

Тем не менее, основная проблема заключается в том, что при дюжине сообщений в секундудля каждого отправляемого клиента любая перегрузка сети или другой фактор, который задерживает соединение, но не отсоединяет его, быстро превратится в запаздывающий беспорядок.один sae используется для отправки до тех пор, пока не будет достигнут обратный вызов завершения, где этот sae затем разблокируется и затем повторно используется для отправки любых ожидающих данных.Реальная реализация этого ускользает от меня.

1 Ответ

0 голосов
/ 06 марта 2011

Прежде чем начать читать, убедитесь, что вы поиграли и поняли Socket.SendTimeout.

Я бы предложил два разных подхода:

  • Во-первых, вы можете попробовать с бассейном sae. Лучший класс для этого - ConcurrentBag (думаю, вам нужна безопасность потоков). Мы сделали это для пула буферов в моей компании, мы сделали небольшую оболочку вокруг ConcurentBag, которая создает новый объект, если случайно пул пуст. В вашем случае вы должны считать, что клиент отключен. Конечно, вам нужно иметь один такой пул для каждого соединения, поэтому я бы предложил использовать словарь, индексированный по сокету. Это немного некрасиво, но работает.

  • Во-вторых, вы можете реализовать собственную очередь отправки, но вы будете дублировать асинхронную функциональность в .Net (и, вероятно, ухудшить ее). Вам нужен собственный поток и очередь (синхронизированная) сообщений для отправки. Когда вы отправляете сообщение, вам нужно отправить сообщение в очередь. Фоновая отправка будет периодически проверять состояние очереди и, если не пусто, выдавать несколько сообщений и отправлять их синхронно. Я бы рекомендовал использовать AutoResetEvent каждый раз, когда вы добавляете что-то в очередь для пробуждения фонового потока.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...