2012-03-30 2 views
1

Я работаю с приложением формы Windows на 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); 
     } 
    } 

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

+0

Это зависит от того, какие классы вы используете. Вам лучше разместить свой код здесь или дать нам больше информации. –

ответ

2

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

Для того, чтобы обнаружить неисправное соединение, вам необходим keepalive. Вам нужно либо:

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

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

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