Соединения через сокет TCP

У меня есть служба Windows, которая, помимо прочего, прослушивает входящие данные с удаленного устройства, используя библиотеку .NET System.Net.Sockets. В приведенном ниже примере только одно удаленное устройство отправляет данные каждые 60 секунд.

Время от времени эта служба останавливается, и в журналах Windows сервера появляется сообщение (показанное ниже).

The process was terminated due to an unhandled exception. 
   Exception Info: System.Net.Sockets.SocketException Stack: 
   at System.Net.Sockets.Socket.EndReceive(System.IAsyncResult) 
   at Uk.Co.RCID.MoteServer.Server.SocketListener.ReceiveCallback(System.IAsyncResult) 
   at System.Net.LazyAsyncResult.Complete(IntPtr)
   at System.Net.ContextAwareResult.CompleteCallback(System.Object) 
   at System.Threading.ExecutionContext.runTryCode(System.Object) 
   at System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode, CleanupCode, System.Object) 
   at System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object) 
   at System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean) 
   at System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object) 
   at System.Net.ContextAwareResult.Complete(IntPtr) at System.Net.LazyAsyncResult.ProtectedInvokeCallback(System.Object, IntPtr) 
   at System.Net.Sockets.BaseOverlappedAsyncResult.CompletionPortCallback(UInt32, UInt32, System.Threading.NativeOverlapped*) 
   at System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32, UInt32, System.Threading.NativeOverlapped*)  

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

2011-05-20 13:39:19,545 [6] INFO  Uk.Co.RCID.MoteServer.Server.SocketListener [(null)] - Waiting for a connection...
2011-05-20 13:39:19,545 [10] INFO  Uk.Co.RCID.MoteServer.Server.SocketListener [(null)] - Connection established on [10.64.128.60:11000]
2011-05-20 13:40:20,982 [6] INFO  Uk.Co.RCID.MoteServer.Server.SocketListener [(null)] - Waiting for a connection...
2011-05-20 13:40:20,982 [5] INFO  Uk.Co.RCID.MoteServer.Server.SocketListener [(null)] - Connection established on [10.64.128.60:11000]

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

http://msdn.microsoft.com/en-us/library/5w7b7x5f.aspx

Любая помощь приветствуется.


Всем привет,

Спасибо за ваши ответы.

Я добавил больше протоколирования и обработки исключений в функцию ReceiveCallback и сегодня утром обнаружил в своем файле журнала следующее...

2011-05-25 04:52:26,816 [5] INFO  Uk.Co.RCID.MoteServer.Server.SocketListener [(null)] - Waiting for a connection...
2011-05-25 04:52:26,816 [10] INFO  Uk.Co.RCID.MoteServer.Server.SocketListener     [(null)] - Connection established on [10.64.128.60:11000]
2011-05-25 04:53:26,841 [10] WARN  Uk.Co.RCID.MoteServer.Server.SocketListener [(null)] - SocketException thrown in ReceiveCallback
2011-05-25 04:53:26,841 [10] WARN  Uk.Co.RCID.MoteServer.Server.SocketListener [(null)] - ErrorCode: [10054]
2011-05-25 04:53:26,841 [10] WARN  Uk.Co.RCID.MoteServer.Server.SocketListener [(null)] - System.Net.Sockets.SocketException (0x80004005): An existing connection was forcibly closed by the remote host at System.Net.Sockets.Socket.EndReceive(IAsyncResult asyncResult) at Uk.Co.RCID.MoteServer.Server.SocketListener.ReceiveCallback(IAsyncResult ar)

Итак, ключ (как указано в некоторых ответах выше) состоит в том, чтобы перехватывать исключения внутри функции ReceiveCallback и решать, достаточно ли они серьезны, чтобы убить ваше приложение.


person user767428    schedule 24.05.2011    source источник
comment
Есть ли внутреннее исключение в свойстве InnerException исключения, которое вы перехватываете? Я думаю, что в вашем коде может быть что-то брошено, когда вы получаете данные из сокета.   -  person Nick    schedule 24.05.2011
comment
К сожалению, у меня нет этой информации. Поскольку ошибка возникает нечасто, потребуется некоторое время, чтобы воссоздать проблему с дополнительным протоколированием. Я попытаюсь воссоздать его с помощью имитации удаленного устройства.   -  person user767428    schedule 24.05.2011


Ответы (4)


EndAccept может генерировать и генерирует исключения, когда клиентские соединения не могут перейти из полуоткрытого в полностью открытое состояние. Также обратите внимание, что он выдаст ObjectDisposedException после выключения прослушивателя, поэтому вам нужно фактически посмотреть на исключение и определить, что делать, основываясь на том, что пошло не так.

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

person Yaur    schedule 24.05.2011
comment
Я добавил больше логов в функцию ReceiveCallback и прошлой ночью обнаружил в своем лог-файле следующее... - person user767428; 25.05.2011

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

int read = handler.EndReceive(ar);

в функции ReceiveCallback, потому что это может быть что-то такое же простое, как закрытие соединения сокета, пока вы пытаетесь получить.

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

person Nick    schedule 24.05.2011
comment
Это предложение представляется возможным, поскольку удаленное устройство является встроенным электронным устройством, и вполне возможно, что оно может разорвать соединение в это время. Спасибо. - person user767428; 24.05.2011

Вы всегда должны catch (Exception err) во всех методах обратного вызова. НЕОБХОДИМО зарегистрировать исключение.

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

Вы должны обрабатывать любое исключение в обратных вызовах сокета, как если бы клиент отключился. Конечно, вы можете получить фатальные исключения, такие как OutOfMemoryException, которые должны завершить ваше приложение. Но в большинстве случаев это маловероятно.

person jgauffin    schedule 24.05.2011

Первое, что я бы сделал, это проверил значение свойства ErrorCode в брошенном SocketException. Найдите это значение в списке кодов ошибок winsock. для некоторых указателей на то, что может пойти не так.

Если вы опубликуете код ошибки, я мог бы помочь дальше.

person Andy Johnson    schedule 24.05.2011
comment
Спасибо за советы. Я собираюсь добавить больше журналов для получения запрошенной информации. - person user767428; 24.05.2011