Выбор дизайна для автоматического переподключения клиента сокета - PullRequest
1 голос
/ 30 марта 2012

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

Вот код моего класса 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);
        }
    }

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

1 Ответ

2 голосов
/ 30 марта 2012

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

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

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

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

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

...