One of the things we tend to take for granted and assume to be true is that identical code will produce identical behaviors across different platforms. It only seems sensible that if we write some C# code that compiles and runs for the full framework as well as the compact framework that the resulting behavior, provided the code isn't obviously platform dependent, should behave the same. Right?
Apparently not.
While porting some networking code today from the device to the desktop, I was having failures in code that I was certain worked. It turns out that sockets don't behave the same. Since a Socket class is an abstraction of something that is pretty damned standard, the fact that we have this disparity surprises and alarms me. It smells an awful lot like a bug.
Want to try it yourself? I put together some pretty basic repro code:
class Program
{
private Socket m_serverSocket;
private ManualResetEvent m_requestDoneEvent = new ManualResetEvent(false);
public static void Main()
{
Program p = new Program();
p.Run();
}
public void Run()
{
IPEndPoint localEndpoint = new IPEndPoint(IPAddress.Any, 90);
m_serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
m_serverSocket.Bind(localEndpoint);
Thread serverThread = new Thread(ServerThreadProc);
serverThread.IsBackground = true;
serverThread.Priority = ThreadPriority.AboveNormal;
serverThread.Start();
Thread.Sleep(100);
Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
EndPoint ep = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 90);
clientSocket.Connect(ep);
m_requestDoneEvent.WaitOne(10000, false);
}
private void ServerThreadProc()
{
m_serverSocket.Listen(10);
m_requestDoneEvent.Reset();
m_serverSocket.BeginAccept(AcceptRequest, m_serverSocket);
// wait for the async accept to complete
m_requestDoneEvent.WaitOne(10000, false);
}
private void AcceptRequest(IAsyncResult result)
{
Debug.WriteLine("\r\n\n -------------------------------------------");
Debug.WriteLine("| The current Platform is " + Environment.OSVersion.Platform.ToString());
Debug.WriteLine("| The server socket reports Connected == " + m_serverSocket.Connected.ToString());
Debug.WriteLine(" -------------------------------------------\r\n\n");
m_requestDoneEvent.Set();
}
}
And the outputs:
On the desktop:
-------------------------------------------
| The current Platform is Win32NT
| The server socket reports Connected == False
-------------------------------------------
On the device:
-------------------------------------------
| The current Platform is WinCE
| The server socket reports Connected == True
-------------------------------------------
WTF?!