Выбор дизайна для автоматического повторного подключения клиента сокета

Я работаю с приложением формы Windows на С#. Я использую клиент сокета, который асинхронно подключается к серверу. Я хотел бы, чтобы сокет попытался немедленно переподключиться к серверу, если соединение по какой-либо причине прервано. Какой дизайн лучше всего подходит для решения проблемы? Должен ли я создать поток, который постоянно проверяет, не потеряно ли соединение, и пытается повторно подключиться к серверу?

Вот код моего класса XcomClient, который обрабатывает связь через сокет:

        public void StartConnecting()
    {
        socketClient.BeginConnect(this.remoteEP, new AsyncCallback(ConnectCallback), this.socketClient);
    }

    private void ConnectCallback(IAsyncResult ar)
    {
        try
        {
            // Retrieve the socket from the state object.
            Socket client = (Socket)ar.AsyncState;

            // Complete the connection.
            client.EndConnect(ar);

            // Signal that the connection has been made.
            connectDone.Set();

            StartReceiving();

            NotifyClientStatusSubscribers(true);
        }
        catch(Exception e)
        {
            if (!this.socketClient.Connected)
                StartConnecting();
            else
            { 

            }
        }
    }

    public void StartReceiving()
    {
        StateObject state = new StateObject();
        state.workSocket = this.socketClient;
        socketClient.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(OnDataReceived), state);
    }

    private void OnDataReceived(IAsyncResult ar)
    {
        try
        {
            StateObject state = (StateObject)ar.AsyncState;
            Socket client = state.workSocket;

            // Read data from the remote device.
            int iReadBytes = client.EndReceive(ar);
            if (iReadBytes > 0)
            {
                byte[] bytesReceived = new byte[iReadBytes];
                Buffer.BlockCopy(state.buffer, 0, bytesReceived, 0, iReadBytes);
                this.responseList.Enqueue(bytesReceived);
                StartReceiving();
                receiveDone.Set();
            }
            else
            {
                NotifyClientStatusSubscribers(false);
            }
        }
        catch (SocketException e)
        {
            NotifyClientStatusSubscribers(false);
        }
    }

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


person Francesco    schedule 30.03.2012    source источник
comment
Это зависит от того, какие классы вы используете. Вам лучше опубликовать свой код здесь или дать нам больше информации.   -  person Rafael Colucci    schedule 30.03.2012


Ответы (1)


Если ваше приложение получает данные только через сокет, то в большинстве случаев вы никогда не обнаружите разрыв соединения. Если вы не получаете никаких данных в течение длительного времени, вы не знаете, связано ли это с разрывом соединения или с тем, что другой конец просто не отправлял никаких данных. Вы, конечно, обнаружите (как EOF на сокете) соединения, закрытые другим концом, несмотря на это.

Чтобы обнаружить разрыв соединения, вам нужен keepalive. Вам нужно либо:

  • сделайте так, чтобы другой конец гарантировал, что он будет отправлять данные по установленному расписанию, и вы истечете время ожидания и закроете соединение, если вы его не получите, или,
  • время от времени отправляйте зонд на другой конец. В этом случае ОС позаботится о том, чтобы заметить разрыв соединения, и вы получите сообщение об ошибке при чтении сокета, если он нарушен, либо быстро (соединение сброшено узлом), либо в конечном итоге (время ожидания соединения истекло).

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

Вы также можете включить опцию поддержки активности TCP для сокета, но поддержка активности на уровне приложения обычно считается более надежной.

person Celada    schedule 30.03.2012