none
Не работает алгоритм определения состояния соединения клиент-сервер для сокета (см. в MSDN Socket.Connected) RRS feed

  • Общие обсуждения

  • До сего момента сам не программировал для сокетов TCP (только UDP), так что опыта в этом мало. Использую .NET 4.5.1 в Visual Studio 2013 Pro. За основу (куда подглядеть) взял этот пример от Микрософта.

    Открываю MSDN про Socket.Connected - свойство и читаю совершенно однозначное утверждение:

    Если необходимо определить текущее состояние подключения, выполните неблокирующий вызов Send с нулевым числом байтов. Успешное выполнение запроса или создание исключения с кодом ошибки WAEWOULDBLOCK (10035) указывает на то, что сокет по-прежнему подключен; в противном случае, сокет уже не подключен.

    По факту этот алгоритм не работает. Далее привожу куски кода. Пока никакой "работы" ни сервер, ни клиент не делают, только коннектятся и дисконнектятся. Этот цикл крутится в потоке сервера, когда он уже в состоянии прослушивания:

    while (true)
    {
    	EventAcceptCallback.Reset();
    	listener.BeginAccept(new AsyncCallback(AcceptCallback), listener);
    	while (!EventAcceptCallback.WaitOne(1000))
    		CheckingClientStatus();
    }

    Функция CheckingClientStatus как раз делает "опрос" по вышеуказанному алгоритму ранее подключившихся клиентов. Приведу основную часть её - цикл опроса:

    foreach (KeyValuePair<Socket, IPEndPoint> kvp in Clients)
    {
    	Socket socket = kvp.Key;
    	IPEndPoint ipEndPoint = kvp.Value;
    	bool blockingState = socket.Blocking;
    	try
    	{
    		socket.Blocking = false;
    		socket.Send(new byte[1], 0, SocketFlags.None);
    		// оказались здесь, значит клиент подключен
    	}
    	catch (SocketException ex)
    	{	// ошибка 10035 (WSAEWOULDBLOCK) означает, что клиент ещё подключен, иначе - нет
    		if (!ex.NativeErrorCode.Equals(10035))
    		{	// клиент отключен, добавим в список удаляемых
    			if (!socket.Connected)
    				clientsToRemove.Add(socket, ipEndPoint);
    		}
    	}
    	finally
    	{
    		socket.Blocking = blockingState;
    	}
    }

    Основной код взят из той же MSDN. Так вот, если клиент ранее был подключен, то что бы с ним не происходило потом - отключился (Socket.Disconnect), закрыл сокет, закрылось приложение, этот код никогда не попадает в блок catch. Это означает, что клиент считается всегда подключённым. В чём трабл?

    Но стоит только значение второго аргумента функции Send задать равным 1, так сразу всё начинает работать как задумано. Это и понятно, состояние коннекта определяется по результату последней операции передачи или приёма. Если я передаю 1 байт, то это реальная передача данных. В случае отключения клиента, естественно, она не получится. В алгоритме из MSDN якобы передаётся 0 байт, может поэтому, раз нет реальной передачи, алгоритм не работает? Но что тогда написано в MSDN, это уже устарело или просто ошибка? Или всё-таки чего-то не хватает, например, какой-то настройки сокета?

    Спасибо



    17 января 2014 г. 10:37

Все ответы