Итак, я знаю, что есть много статей по этой теме, и я прочитал много из них, я бы сказал, но по какой-то причине я уверен, что мой код не делает то, что должен делать.

Я хочу закрыть соединение между моим сервером и моим клиентом. Теперь на стороне сервера я запускаю отключение с помощью этого кода

public void shutdown()
    {
        _socket.Shutdown(SocketShutdown.Both);
        _socket.Close();
    }

И на стороне клиента у меня есть некоторые проблемы с пониманием того, как я добираюсь до отключения, что, как я считаю, происходит следующим образом: в моем асинхронном обратном вызове получения я должен получить сообщение об ошибке, так как сервер запустил последовательность отключения, и я должен обработать это (верно ???), поэтому мой код для клиента выглядит так: ReceiveCallback:

private void ReceiveCallback(IAsyncResult result)
    {
        int bytesRecieved = 0;
        byte[] tempBuff;

        //Try to receive But if a Socket error occures disconnect otherwise start Receiving again
        try
        {
            bytesRecieved = _socket.EndReceive(result);
        }
        catch (SocketException sockEx)
        {
            Disconnect(sockEx);
            return;
        }
        catch (ObjectDisposedException disposeEx)
        {
            Disconnect(disposeEx);
            return;
        }
        catch (Exception ex)
        {
            StartReceive();
            return;
        }

        if (bytesRecieved == 0)
        {
            StartReceive();
            return;
        }

        tempBuff = new byte[bytesRecieved];
        Buffer.BlockCopy(_buffer, 0, tempBuff, 0, bytesRecieved);
        StartReceive();
        _packHandler.handlePacket(tempBuff);

    }

Отключить:

public void Disconnect()
    {
        if (!_socket.Connected)
        {
            return;
        }
        _socket.BeginDisconnect(false, DisconnectCallback, null);
    }

DisconnectCallback

private void DisconnectCallback(IAsyncResult result)
    {
        _socket.EndDisconnect(result);
        _socket.Close();
    }

(Метод Disconnect перегружен, поэтому, если я получаю исключение, он создает messageBox, а затем также вызывает Disconnect. Просто чтобы я знал, что произошло.)

В чем я ошибаюсь и что можно улучшить?

Я попробовал код, и, похоже, он работал, но затем я посмотрел с помощью netstat, все ли сокеты закрыты, а клиентский - нет. Это было в FIN_WAIT_2, что означает, что он (или сервер ???) еще не отправил пакет FIN, верно? О, а потом я попробовал еще раз, изменив эту строку:

if (bytesRecieved == 0)
        {
            StartReceive();
            return;
        }

К

if (bytesRecieved == 0)
        {
            Disconnect;
            return;
        }

Который затем вызвал исключение на стороне сервера, а на стороне клиента клиент сказал, что соединение было закрыто сервером ???

РЕДАКТИРОВАТЬ: Даже когда я закрыл обе программы, Netstat все еще показывает порт в состоянии ОЖИДАНИЕ. что это мне говорит?

1
D4rth B4n3 19 Сен 2014 в 15:46

2 ответа

Лучший ответ

Важно:

  • Если сервер запускает последовательность выключения, вам НЕОБХОДИМО обработать это
  • Обе стороны должны вызвать отключение на своем сокете.
  • Вам нужен способ заметить отключение (это не дает вам ошибки или, по крайней мере, не для меня)

Поэтому я создал свой собственный класс customSocket, который наследуется от Socket

public class customSocket : Socket
{
    #region Properties
    private readonly Timer _timer;
    private const int _interval = 1000;

    private bool Connected
    {
        get
        {
            bool part1 = Poll(1000, SelectMode.SelectRead);
            bool part2 = (Available == 0);
            if (part1 && part2)
                return false;
            else 
                return true;
        }
    }

    public bool EventsEnabled
    {
        set
        {
            if (value)
            {
                _timer.Start();
            }
            else
                _timer.Stop();
        }
    }

    #endregion

    #region Constructors

    public customSocket(AddressFamily addressFamily, SocketType sockType, ProtocolType protocolType)
        : base(addressFamily, sockType, protocolType)
    {
        _timer = new Timer { Interval = _interval };
        _timer.Elapsed += TimerTick;
    }

    public customSocket(SocketInformation sockInfo)
        : base(sockInfo)
    {
        _timer = new Timer { Interval = _interval };
        _timer.Elapsed += TimerTick;
    }

    #endregion

    #region Events

    public event EventHandler<EventArgs> Socket_disconected;
    public void Raise_Socket_disconnected()
    {
        EventHandler<EventArgs> handler = Socket_disconected;
        if (handler != null)
        {
            handler(this,new EventArgs());
        }
    }

    private void TimerTick(object sender, EventArgs e)
    {
        if (!Connected)
        {
            Raise_Socket_disconnected();
        }
    }

    #endregion
}

Эта версия сокета имеет Событие для отключения. Теперь, если вы создаете экземпляр своего класса сокета, вам нужно подключить обработчик и установить для EventsEnabled значение true.

Затем этот обработчик вызывает завершение работы, и ваш сокет не остается в FIN_WAIT_2

1
D4rth B4n3 22 Сен 2014 в 11:16

У вашего обычного отключения есть выключение, которое очищает сокет, чтобы он мог правильно отключиться, но ваш асинхронный стиль никогда не вызывает выключение. Я добавил его в удобном месте ниже.

public void Disconnect()
{
    if (!_socket.Connected)
    {
        return;
    }
    _socket.Shutdown(SocketShutdown.Both); // Make sure to do this
    _socket.BeginDisconnect(false, DisconnectCallback, null);
}

РЕДАКТИРОВАТЬ:

Судя по звукам, у вас нет причин использовать асинхронный метод? Асинхронные методы позволяют отправлять данные в отдельном потоке выполнения, освобождая поток, например, для выполнения некоторой обработки данных, пока это происходит.

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

public void Disconnect()
{
    if (!_socket.Connected)
    {
        return;
    }
    shutdown(); //Your standard disconnect that you showed up top.  Scoping might be required.
}

Немного данных об Async можно найти здесь: http://msdn.microsoft.com/en-us/library/38dxf7kt(v=vs.110).aspx

1
Carter 19 Сен 2014 в 13:16