none
Accept call on a Socket in Listening state does not return upon closure of the socket, if a process is started with "UseShellExecute = false" option. RRS feed

  • Question

  • Hi All,

    I have encountered a very strange problem.

    I have reproduced the issue with a sample code.

    The code creates a socket, listens on it and it is waiting for incoming connections. It also starts a new process which would handle the processing of the socket communication, but in the sample code it is enough for it to do nothing. This process is started with UseShellExecute = false option, as the code will run as a service and shall not exhaust the desktop heap.

    There is a separate thread for the listening and after receiving one connection (which can be made for example by using the telnet localhost 12345 command), will signal the main thread to close the listening socket and wait until the listener thread exits and then exit the application. 

    My observation is that if the process is started after the socket has been created, the Accept call does not unblock with the System.Net.Sockets.SocketException (0x80004005): A blocking operation was interrupted by a call to WSACancelBlockingCall at System.Net.Sockets.Socket.Accept() exception, but remains in blocking mode until the started process exits/is killed, and just after that exits the blocking mode. And if the process is started before the socket creation, then everything is working as expected.

    Can someone explain this behavior?

    Many thanks,

    Zsolt

    My sample code looks like this:

    The listener source code:

    using System;
    using System.Diagnostics;
    using System.Net;
    using System.Net.Sockets;
    using System.Threading;
    
    namespace ListenerProcess
    {
        class Program
        {
            private static Socket _myListenSocket;
            private static AutoResetEvent _myStopEvent = new AutoResetEvent(false);
            private static AutoResetEvent _myExitEvent = new AutoResetEvent(false);
            private static Process _myProcess;
            static void Main(string[] args)
            {
                Console.WriteLine("1:Starting");
    
                //_myProcess = new Process
                //{
                //    StartInfo =
                //    {
                //        CreateNoWindow = true,
                //        UseShellExecute = false,
                //        FileName = "ExecutorProcess.exe"
                //    }
                //};
    
                //_myProcess.Start();
    
                // create socket
                IPEndPoint aEndPoint;
                if (!Socket.OSSupportsIPv6)
                {
                    _myListenSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                    aEndPoint = new IPEndPoint(IPAddress.Any, 12345);
                }
                else
                {
                    _myListenSocket = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp);
                    _myListenSocket.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only, 0);
                    aEndPoint = new IPEndPoint(IPAddress.IPv6Any, 12345);
                }
    
                _myProcess = new Process
                {
                    StartInfo =
                    {
                        //CreateNoWindow = true,
                        UseShellExecute = false,
                        FileName = "ExecutorProcess.exe"
                    }
                };
    
                _myProcess.Start();
    
                _myListenSocket.Bind(aEndPoint);
                _myListenSocket.NoDelay = true;
    
                Thread aListeningThread = new Thread(StartListener, 1);
                aListeningThread.Name = string.Format("Listener thread for '{0}'", aEndPoint);
                aListeningThread.Start();
    
                Console.WriteLine("1:Wait for stop event");
                _myStopEvent.WaitOne();
                Console.WriteLine("1:Stop event received");
                Console.WriteLine("1:Sleeping");
                Thread.Sleep(2000);
                Console.WriteLine("1:Closing socket");
                _myListenSocket.Close();
                Console.WriteLine("1:Wait for exit event");
                _myExitEvent.WaitOne();
                Console.WriteLine("1:Exit event received");
    
                Console.WriteLine("1:Exiting");
                if (!_myProcess.HasExited)
                {
                    _myProcess.Kill();
                }
            }
    
            private static void StartListener(object obj)
            {
                _myListenSocket.Listen(20);
                try
                {
                    while (true)
                    {
                        try
                        {
                            Console.WriteLine("Calling accept");
                            Socket aAcceptedSocket = _myListenSocket.Accept();
                            Console.WriteLine("2:Accepted socket with handle: {0}", aAcceptedSocket.Handle);
    
                            Console.WriteLine("2:Set the stop event");
                            _myStopEvent.Set();
                        }
                        catch (SocketException aSocketException)
                        {
                            Console.WriteLine("2:Got SocketException: {0} with error code: {1}", aSocketException.ToString(),
                                aSocketException.ErrorCode);
                            if (!_myListenSocket.IsBound)
                            {
                                Console.WriteLine("2:Closing socket");
                                _myListenSocket.Close();
                                throw;
                            }
                        }
                        finally
                        {
                            _myStopEvent.Set();
                        }
                    }
                }
                catch (Exception aException)
                {
                    Console.WriteLine("2:Got exception: {0}", aException.ToString());
                    Console.WriteLine("2:Set the exit event");
                    _myExitEvent.Set();
                }
    
    
            }
    
        }
    }

    The executor process source code:

    using System;
    
    namespace ExecutorProcess
    {
        class Program
        {
            static void Main(string[] args)
            {
                Console.WriteLine("Executor:Started executor");
                while (true)
                {
    
                }
            }
        }
    }


    Thursday, August 11, 2016 12:16 PM

All replies

  • Hi Bartha,

    >> the Accept call does not unblock with the System.Net.Sockets.SocketException (0x80004005): A blocking operation was interrupted by a call to WSACancelBlockingCall at System.Net.Sockets.Socket.Accept() exception, but remains in blocking mode until the started process exits/is killed, and just after that exits the blocking mode

    What do you mean with this? I am not familiar with Socket, if there is any wrong in my post, please feel free to let me know.

    Did you get any error or is your Socket blocked? I made a test with your code, and I could get below result no matter where I place _myProcess.

    //process is started after the socket creation
    1:Starting
    1:Wait for stop event
    Calling accept
    Executor:Started executor
    //process is started before the socket creation
    1:Starting
    Executor:Started executor
    1:Wait for stop event
    Calling accept

    Is there any steps I need to do except launch ListenerProcess project?

    Best Regards,

    Edward


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.


    Friday, August 12, 2016 10:57 AM
  • Hi Edward,

    After starting the application in another command prompt (if Telnet Client windows feature is enabled), execute the "telnet localhost 12345" command in order to have an incoming connection to the listener socket.

    In one case the sample program will exit as supposed to, in the other case the Accept call will remain in blocking mode (will not throw the expected exception) and the program will not exit. I am interested why is it behaving like this.

    Thanks,

    Zsolt

    Friday, August 12, 2016 12:45 PM
  • Hi Zsolt,

    Thanks for more information. I made a test with your description, and I could reproduce your issue. To be honesty, I am not sure how this happened. I'm trying to involve some senior engineers into this issue and it will take some time. Your patience will be greatly appreciated.

    Sorry for any inconvenience and have a nice day!

    Best Regards,

    Edward


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.


    Monday, August 15, 2016 10:53 AM
  • Hi Edward,

    Did you receive any answer from the senior engineers on this topic?

    Many thanks,

    Zsolt

    Tuesday, October 4, 2016 7:54 AM
  • Hi Zsolt,

    It is sad that I did not receive any answer. I will come soon once I got any updates.

    Sorry for any inconvenient.

    Best Regards,

    Edward


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.


    Thursday, October 6, 2016 6:20 AM