none
Problem when sending data over a socket RRS feed

  • Question

  • 		static void Main(string[] args)
    		{
    			try
    			{
    				var listenerThread = new Thread(ListenerThreadEntry);
    				listenerThread.Start();
    
    				Thread.Sleep(TimeSpan.FromSeconds(1));
    
    				using (var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP))
    				{
    					socket.Connect("localhost", Port);
    
    					var rawStream = new NetworkStream(socket);
    					using (var sslStream = new SslStream(rawStream, false, VerifyServerCertificate))
    					{
    						var certificate = new X509Certificate(CertsPath + @"test.cer");
    						var certificates = new X509CertificateCollection(new[] { certificate });
    						sslStream.AuthenticateAsClient("localhost", certificates, SslProtocols.Tls, false);
    
    						Thread.Sleep(TimeSpan.FromSeconds(1));
    
    						using (var writer = new StreamWriter(sslStream))
    						{
    							writer.WriteLine("TEST");
    							writer.Flush();
    
    							Thread.Sleep(TimeSpan.FromSeconds(10));
    						}
    					}
    
    					socket.Shutdown(SocketShutdown.Both);
    					socket.Disconnect(false);
    				}
    
    				Console.WriteLine("Success! Well, not really.");
    			}
    			catch (Exception exc)
    			{
    				Console.WriteLine(exc);
    			}
    		}
    
    		private static bool VerifyServerCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
    		{
    			return true;
    		}
    
    		static void ListenerThreadEntry()
    		{
    			try
    			{
    				var listener = new TcpListener(IPAddress.Any, Port);
    				listener.Start();
    
    				var client = listener.AcceptTcpClient();
    				var serverCertificate = new X509Certificate2(CertsPath + @"\test.pfx");
    				var sslStream = new SslStream(client.GetStream(), false);
    				sslStream.AuthenticateAsServer(serverCertificate, false, SslProtocols.Tls, false);
    
    				client.Close();  // terminate the connection
    
    				// this code will fail
    				using (var reader = new StreamReader(sslStream))
    				{
    					var line = reader.ReadLine();
    					Console.WriteLine("> " + line);
    				}
    			}
    			catch (Exception exc)
    			{
    				Console.WriteLine(exc);
    			}
    		}
    

    In this sample application, a socket connection is established and then terminated immediately after the handshake. A strange thing is that the client "succeeds" sending data, despite the connection was terminated from another side before the attempt to send data started.

    Is such behavior of the Socket object correct?

    Tuesday, August 25, 2015 7:25 PM

Answers

  • Hi Andrey_F,

    You could use below IsConnected method to check whether the connection has been closed on server side.

    public static bool IsConnected(Socket socket)
    {
        return !(socket.Poll(1, SelectMode.SelectRead) && socket.Available == 0);
    }
    

    If it return true, you could write content to stream.

    if(IsConnected(socket))
    {
        using (var writer = new StreamWriter(rawStream))
        {
            writer.WriteLine("TEST");
            writer.Flush();
            Thread.Sleep(TimeSpan.FromSeconds(2));
        }
    }
    Best Regards,
    Li Wang
    Thursday, August 27, 2015 5:21 AM
    Moderator

All replies

  • Hi Andrey_F,

    -->Is such behavior of the Socket object correct?

    Yes, The TcpClient Close method will not close the underlying TCP connection. So the client could "succeeds" sending data. To resolve this problem, close the associated NetworkStream object that the TcpClient GetStream method returns.

    For more information about this issue, link below is for your reference.
    https://support.microsoft.com/en-us/kb/821625

    Best Regards,
    Li Wang

    Wednesday, August 26, 2015 8:44 AM
    Moderator
  • Are you sure it's enough? I've replaced the closing code with this:

    				var stream = client.GetStream();
    				var sslStream = new SslStream(stream, false);
    				sslStream.AuthenticateAsServer(serverCertificate, false, SslProtocols.Tls, false);
    
    				sslStream.Close();
    				stream.Close();
    				client.Close();  // terminate the connection

    but I'm still getting the "false success" message.


    • Edited by Andrey_F Wednesday, August 26, 2015 9:36 AM
    Wednesday, August 26, 2015 9:34 AM
  • Hi Andrey_F,

    You could use below IsConnected method to check whether the connection has been closed on server side.

    public static bool IsConnected(Socket socket)
    {
        return !(socket.Poll(1, SelectMode.SelectRead) && socket.Available == 0);
    }
    

    If it return true, you could write content to stream.

    if(IsConnected(socket))
    {
        using (var writer = new StreamWriter(rawStream))
        {
            writer.WriteLine("TEST");
            writer.Flush();
            Thread.Sleep(TimeSpan.FromSeconds(2));
        }
    }
    Best Regards,
    Li Wang
    Thursday, August 27, 2015 5:21 AM
    Moderator
  • Thanks, that's useful. There is a race condition in such code, though.
    Friday, August 28, 2015 8:44 AM