У меня есть клиент-серверное приложение TCP для связи с устройством Windows CE через соединение ActiveSync.И клиент, и сервер используют асинхронные сокеты (то есть функции Socket.Begin*
и Socket.End*
).Когда клиент и сервер работают на моем рабочем столе, все работает точно так, как ожидается, но когда клиент работает на устройстве Windows CE, подключенном через ActiveSync, я всегда получаю SocketException
на ReceiveCallback после вызова Socket.Shutdown
(когдаустройство инициирует отключение).Полное исключение:
System.Net.Sockets.SocketException: An error message cannot be displayed because an optional resource assembly containing it cannot be found
at System.Net.Sockets.Socket.ReceiveNoCheck()
at ReceiveAsyncRequest.doRequest()
at AsyncRequest.handleRequest()
at WorkerThread.doWork()
at WorkerThread.doWorkI()
at WorkItem.doWork()
at System.Threading.Timer.ring()
Кажется, что все также работает правильно, если сервер (запущенный на рабочем столе) инициирует отключение.У меня есть пара идей о том, как этого избежать, включая запрещение отключений, инициируемых устройством, и игнорирование всех исключений после инициации отключения.Тем не менее, я хотел бы знать, почему это происходит, и есть ли лучший способ справиться с этим.
Disconnect и ReceiveCallbacks (операционно идентичные как на сервере, так и на клиенте):
public bool Disconnect(StateObject state)
{
try{
if(state.isDisconnecting) return false;
state.isDisconnecting = true;
state.sock.Shutdown(SocketShutdown.Both);
//Wait for sending and receiving to complete, but don't wait more than 10 seconds
for(int i=0; i<100 && (state.isSending || state.isReceiving); i++){
System.Threading.Thread.Sleep(100);
}
/* Log the disconnect */
state.sock.Close();
return true;
} catch (Exception e){
/* Log the exception */
return false;
}
}
private void ReceiveCallback(IAsyncResult iar)
{
StateObject state = (StateObject)iar.AsyncState;
try{
//handle the new bytes in the buffer.
int recv = state.sock.EndReceive(iar);
//Handle the buffer, storing it somewhere and verifying complete messages.
if(recv > 0){
//start listening for the next message
state.sock.BeginReceive(state.recvBuffer, 0, StateObject.BUFFER_SIZE, SocketFlags.None, new AsyncCallback(ReceiveCallback), state);
} else {
state.isReceiving = false;
Disconnect(state);
}
} catch (Exception e){
/* Log the exception */
}
}
//For reference, A StateObject looks kinda like this:
public class StateObject
{
public const int BUFFER_SIZE = 1024;
public Socket sock = null;
public bool isSending = false;
public bool isReceiving = false;
public bool isDisconnecting = false;
public byte[] recvBuffer = new byte[BUFFER_SIZE];
public byte[] sendBuffer = new byte[BUFFER_SIZE];
//Other stuff that helps handle the buffers and ensure complete messages,
// even when TCP breaks up packets.
}