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("rnn -------------------------------------------");
Debug.WriteLine("| The current Platform is " + Environment.OSVersion.Platform.ToString());
Debug.WriteLine("| The server socket reports Connected == " + m_serverSocket.Connected.ToString());
Debug.WriteLine(" -------------------------------------------rnn");
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?!
Something is very wrong here!
How can the Socket on WinCE report connected when you haven’t called EndAccept to actually accept the pending connection?!
I tried your code with AcceptRequest modified to the following:
private void AcceptRequest(IAsyncResult result)
{
Debug.WriteLine("rnn ——————————————-");
Debug.WriteLine("| The current Platform is " + Environment.OSVersion.Platform.ToString());
Debug.WriteLine("| The server socket reports Connected == " + m_serverSocket.Connected.ToString());
Socket s = ((Socket)result.AsyncState).EndAccept(result);
Debug.WriteLine("| The s socket reports Connected == " + s.Connected.ToString());
Debug.WriteLine(" ——————————————-rnn");
m_requestDoneEvent.Set();
}
And got the following results:
——————————————-
| The current Platform is Win32NT
| The server socket reports Connected == False
| The s socket reports Connected == True
——————————————-
——————————————-
| The current Platform is WinCE
| The server socket reports Connected == True
| The s socket reports Connected == True
——————————————-
The Win32NT result makes sense but the WinCE result really looks like a bug to me.
Regards,
Frank.
LikeLike
It is obviously not relevant to test if a listening socket is connected…
You should only test clientSocket or the socket resulting from Accept (of EndAccept in this asynchronous scenario).
However I agree we should have the same behavior with both platforms even if this is not really a problem in this case.
LikeLike
Hi
1.) Inserting new records on my PDA Windows Mobile Operating System 6.0
2.) I do a Full Sync on the PDA.
3.) A Date Time error happens on these records
(due to new Daylight Savings Time enacted in 2007).
Does anyone know of a DST (daylight savings time) Patch for the PDA 6.0 Windows
Operating System or where I can get this on the Microsoft site?
Thanks!
Dan
LikeLike
I observed the same socket behavior in CF 2.0 using BeginConnect also. No matter what the state of the connection, the socket.Connected state was always true.
I believe that I solved the problem by attempting to write a zero length byte array to the socket. After this write, the socket.Connected state was correct.
private void EndConnect(IAsyncResult iar)
{
try
{
Socket socket = (Socket)iar.AsyncState;
socket.EndConnect(iar);
socket.Send(new byte[0]);
}
catch (SocketException se)
{
try
{
if (_theSocket != null)_theSocket.Close();
}
catch { }
}
catch (Exception e)
{
try
{
if (_theSocket != null)_theSocket.Close();
}
catch { }
}
}
LikeLike
I observed the same socket behavior in CF 2.0 using BeginConnect also. No matter what the state of the connection, the socket.Connected state was always true.
I believe that I solved the problem by attempting to write a zero length byte array to the socket. After this write, the socket.Connected state was correct.
private void EndConnect(IAsyncResult iar)
{
try
{
Socket socket = (Socket)iar.AsyncState;
socket.EndConnect(iar);
socket.Send(new byte[0]);
}
catch (SocketException se)
{
try
{
if (_theSocket != null)_theSocket.Close();
}
catch { }
}
catch (Exception e)
{
try
{
if (_theSocket != null)_theSocket.Close();
}
catch { }
}
}
LikeLike
Its a common misconception that the Connected property returns the state of the underlying socket. It doesn’t, it returns true or false based upon the last operation performed on the socket.
Consider this:
Open a socket, Connected is true
Send some data, Connected is true
Close the remote end, Connected still is true
Send some data, a SocketException is thrown, Connected now returns false.
There are several bugs submitted to Microsoft about the confusing behaviour of the Connected and Available properties.
LikeLike