Я пытаюсь повторно использовать сокет в асинхронном HTTP-клиенте, но не могу подключиться к хосту во второй раз.Я в основном трактую свой асинхронный HTTP-клиент как конечный автомат со следующими состояниями:
- Доступен: сокет доступен для использования
- Соединение: сокет подключается к конечной точке
- Отправка: сокет отправляет данные в конечную точку
- Получение: сокет получает данные от конечной точки
- Сбой: произошел сбой сокета
- ОчиститьВверх: очистка состояния сокета
В состоянии соединения я вызываю BeginConnect
:
private void BeginConnect()
{
lock (_sync) // re-entrant lock
{
IPAddress[] addersses = Dns.GetHostEntry(_asyncTask.Host).AddressList;
// Connect to any available address
IAsyncResult result = _reusableSocket.BeginConnect(addersses, _asyncTask.Port, new AsyncCallback(ConnectCallback), null);
}
}
Метод обратного вызова изменяет состояние на Sending
после успешного подключениябыло установлено:
private void ConnectCallback(IAsyncResult result)
{
lock (_sync) // re-entrant lock
{
try
{
_reusableSocket.EndConnect(result);
ChangeState(EClientState.Sending);
}
catch (SocketException e)
{
Console.WriteLine("Can't connect to: " + _asyncTask.Host);
Console.WriteLine("SocketException: {0} Error Code: {1}", e.Message, e.NativeErrorCode);
ThreadPool.QueueUserWorkItem(o =>
{
// An attempt was made to get the page so perform a callback
ChangeState(EClientState.Failed);
});
}
}
}
При очистке я Shutdown
сокет и Disconnect
с флагом повторного использования:
private void CleanUp()
{
lock (_sync) // re-entrant lock
{
// Perform cleanup
if (_reusableSocket.Connected)
{
_reusableSocket.Shutdown(SocketShutdown.Both);
_reusableSocket.Disconnect(true);
}
ChangeState(EClientState.Available);
}
}
Последующие вызовы BeginConnect
приводят к тайм-ауту иисключение:
SocketException: попытка подключения не удалась, потому что подключенная сторона не ответила должным образом через определенный промежуток времени, или не удалось установить соединение, поскольку подключенный хост имеет faiпривело к ответу XX.XXX.XX.XX: 80
Код ошибки: 10060
Вот трассировка состояния:
Initializing...
Change State: Connecting
Change State: Sending
Change State: Receiving
Change State: CleanUp
Callback: Received data from client 0 // <--- Received the first data
Change State: Available
Change State: Connecting // <--- Timeout when I try to reuse the socket to connect to a different endpoint
Что у меня естьсделать, чтобы иметь возможность повторно использовать сокет для подключения к другому хосту?
Примечание: я не пытался повторно подключиться к тому же хосту, но Я предполагаю происходит то же самое (т.е. не удается подключиться).
Обновление
Я обнаружил следующее примечание в документации BeginConnect :
Если этот сокет ранее был отключен, то BeginConnect должен вызываться в потоке, который не завершится, пока операция не будет завершена.Это ограничение основного поставщика.Также конечная точка, которая используется, должна отличаться.
Я начинаю задумываться, не связана ли моя проблема с этим ... Я подключаюсь к другой EndPoint, но что они означают, что поток, из которого мы вызываем BeginConnect, не долженвыйти до завершения операции?
Обновление 2.0:
Я задал связанный вопрос и попытался использовать вызовы "Семейство асинхронных" вместо вызовов "Начать семейство", но яполучите ту же проблему !!!