2013-04-22 4 views
0

Я экспериментирую в создании небольшого IRC-сервера, чтобы изучить некоторые новые концепции программирования (и другие, которых я не использовал в течение веков). Первым шагом является получение базового клиента, подключающегося через TCP, для отправки команд открытого текста на сервер.Как определить, когда клиент telnet неправильно закрыт на tcp-сервере?

Для прослушивания для подключения У меня есть следующий код:

public NetworkClient(Server server, TcpClient socket, int id) 
{ 
    _socket = socket; 
    _id = id; 
    _server = server; 
} 

private async void ListenForClients() 
{ 
    int numClients = 0; 
    while (IsRunning) 
    { 
     var tcpClient = await _listener.AcceptTcpClientAsync(); 
     var netClient = new NetworkClient(this, tcpClient, numClients); 
     netClient.Start(); 
     Console.WriteLine("Client Connected"); 

     numClients++; 
    } 
} 

Тогда в моем NetworkClient классе мой Start() метод выглядит следующим образом:

public async void Start() 
{ 
    using (var reader = new StreamReader(_socket.GetStream())) 
    { 
     while (_server.IsRunning) 
     { 
      var line = await reader.ReadLineAsync(); 
      Console.WriteLine("Client {0} wrote: {1}", _id, line); 
     } 
    } 
} 

Это хорошо работает в то время как клиент телнет подключен, однако как только я закрываю своего клиента telnet reader.ReadLineAsync(); постоянно возвращает null. Я бы добавил чек, чтобы узнать, line == null, но я не уверен, что это правильный способ определить, отключен ли клиент.

Чтобы усугубить ситуацию, _socket.Connected постоянно возвращается к истине, пока нули получат «полученные» от reader.ReadLineAsync().

Каков правильный способ обнаружения, когда клиенты tcp были отключены?

ответ

5

Чтение в сокете TCP/IP возвращает 0 байт, когда соединение было изящно закрыто. This situation causes ReadLineAsync to return null. Итак, да, вы должны проверить на null и рассматривать его как изящное закрытие гнезда.

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

Ох и TcpClient.Connected (например, Socket.Connected) практически бесполезны; it only tells you whether the socket was connected, not whether it is connected. Просто притворись, что собственности не существует.

Наконец, пару заметок:

  • Избегайте async void. Если ваши методы возвращают Task, тогда у вас есть «дескриптор», чтобы увидеть, когда они завершатся (и подняли ли они исключения). Мой recent MSDN article объясняет, почему async void не рекомендуется.
  • Лучше периодически отправлять данные по соединению, чтобы определить, по-прежнему ли он жизнеспособен. Я написал TCP/IP .NET sockets FAQ, что covers this in more detail.
+0

Отлично, спасибо за ресурсы! Я новичок в «async/await» и сокетах, поэтому они обязательно пригодится. – KallDrexx