4

I have a TCP client/server app to communicate with a Windows CE device over an ActiveSync connection. Both the client and server utilize Asynchronous sockets (i.e. the Socket.Begin* and Socket.End* functions). When both the client and server are running on my desktop everything functions exactly as expected, but when the client is running on the Windows CE device that's connected over ActiveSync, I always get a SocketException on the ReceiveCallback after calling Socket.Shutdown (when the device is initiating the disconnect). The full exception is:

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()

Everything also seems to work correctly if the server (running on the desktop) initiates the disconnect. I have a couple ideas on how to avoid this, including disallowing device initiated disconnects and ignoring all exceptions after initiating a disconnect. However, I'd like to know why this is happening and if there's a better way of handling it.

The Disconnect and ReceiveCallbacks (operationally identical on both the server and client) are:

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.
}
chezy525
  • 4,025
  • 6
  • 28
  • 41
  • 2
    Never assume that the CF and full framework will behave identically. http://blog.opennetcf.com/ctacke/2008/10/02/BehavioralDifferencesBetweenTheCFAndFFx.aspx – ctacke Apr 12 '11 at 19:23
  • @ctacke, yeah, I'm really starting to figure that out, as painful as it is... – chezy525 Apr 12 '11 at 20:59
  • do you get the exception while debugging? (is there a remote debugger for WinCE?) also is there an InnerException with more detail? – user1859022 Jul 04 '14 at 11:41

2 Answers2

0

If a message connot be shown on your device, because the message is not installed on your device. You have to install a netcf.messages.cab. You will find it here:

C:\Program Files (x86)\Microsoft.NET\SDK\CompactFramework\v3.5\WindowsCE\Diagnostics

After installing this CAB-File, run your application again and post the new error you get.

etalon11
  • 895
  • 2
  • 13
  • 36
0

It in order to get the actual exception maybe try figure out which library it needs and deploy it?

oleksii
  • 35,458
  • 16
  • 93
  • 163