Search code examples
c#socketsasyncsocket

After stopping the thread, can I cancel the listen operation with a variable?


I listen to a port in a thread with the following method. While waiting in WaitOne method, I stop the thread (I am doing IsCancellationRequested true) and I can not close the listener object. Then I get an error when I want to listen to the same port.

Can I bind a listener object to a variable? If that variable is false, it will do an automatic shutdown.

I do not want to check that the thread is stopped with a separate thread and close the listener.

public void StartListening(Connection connection)
{
    // There are codes here..
    try
    {
        listener.Bind(localEndPoint);
        listener.Listen(2);

        while (connection.CancellationTokenSource.IsCancellationRequested == false)
        {                
            allDone.Reset();                    
            listener.BeginAccept(new AsyncCallback(AcceptCallback), listener);
            allDone.WaitOne(); // While I'm waiting here, I'm making the 'IsCancellationRequested' variable true.
        }

        listener.Close();
    }
    catch (Exception e)
    {
        // There are codes here..
    }

    // There are codes here..
}

Note: The Connection class is a class I created that contains theSystem.Threading.CancellationTokenSource CancellationTokenSource property.


Solution

  • I don't know the precise structure of the connection, but...

    You could try waiting on two handles. (untested)

    var handles = new EventWaitHandle[] 
    { 
        allDone, 
        connection.CancellationTokenSource.Token.WaitHandle 
    };
    
    int index = EventWaitHandle.WaitAny(handles);
    

    WaitAny returns the index of the waithandle whois set. So determine if you want to break your while or not.


    Maybee something like:

    public void StartListening(Connection connection)
    {
        // There are codes here..
        try
        {
            listener.Bind(localEndPoint);
            listener.Listen(2);
    
            var handles = new EventWaitHandle[] 
            { 
                allDone, 
                connection.CancellationTokenSource.Token.WaitHandle 
            };
    
            do
            {                
                allDone.Reset();                    
                listener.BeginAccept(new AsyncCallback(AcceptCallback), listener);
            }
            while(EventWaitHandle.WaitAny(handles) == 0);
    
            listener.Close();
        }
        catch (Exception e)
        {
            // There are codes here..
        }
    
        // There are codes here..
    }
    

    A way to cancel the listener. Can't make up something nicer at the moment. If someone has a better way... feel free ;-)

    ManualResetEvent _listenerTerminated = new ManualResetEvent(false);
    
    // <snip>
    
    listener.BeginAccept(new AsyncCallback(AcceptCallback), listener);
    
    private void AcceptCallback(IAsyncResult ar)
    {
        // before calling EndAccept, check an event.
        if(_listenerTerminated.WaitOne(0))
            return;
    
        var clientSocket = listener.EndAccept(asyncResult);
    }
    
    // <snip>
    
    do
    {                
        allDone.Reset();                    
        listener.BeginAccept(new AsyncCallback(AcceptCallback), listener);
    }
    while(EventWaitHandle.WaitAny(handles) == 0);
    
    _listenerTerminated.Set();
    
    listener.Close();