开发者

TcpListener.AcceptSocket( ) behavior: gets stuck in one app upon termination, but does not in another?

I have two TCP-server apps that are based on the same code, but for some reason exhibit different behavior and i'm ready to pull my hair out trying to figure out why. The code pattern is as follows:

public class TcpServer
{
    public static void Start( bool bService )
    {
        ..
        oTcpListnr= new TcpListener( ip, iOutPort );
        aTcpClient= new ArrayList( );
        bListen=    true;
        oTcpListnr.Start( );
        thOutComm=  new Thread( new ThreadStart( AcceptTcpConn ) );
        thOutComm.Name= "App-i.AcceptTcpConn";
        thOutComm.Start( );
        ..
    }
    public static void      Stop( )
    {
        bListen=    false;

        if(  thOutComm != null  )
        {
            thOutComm.Join( iTimeout );
            thOutComm=  null;
        }
        if(  oTimer != null  )
        {
            oTimer.Change( Timeout.Infinite, Timeout.Infinite );
            oTimer.Dispose( );
        }
    }
    public static void      AcceptTcpConn( )
    {
        TcpState    oState;
        Socket      oSocket=    null;

        while(  bListen  )
        {
            try
            {
        //      if(  oTcpListnr.Pending( )  )
                {
                    oSocket=    oTcpListnr.AcceptSocket( );
                    oState=     new TcpState( oSocket );

                    if(  oSocket.Connected  )
                    {
                        Utils.PrnLine( "adding tcp: {0}", oSocket.RemoteEndPoint.ToString( ) );
                        Monitor.Enter( aTcpClient );
                        aTcpClient.Add( oState );
                        Monitor.Exit( aTcpClient );

                        oSocket.SetSocketOption( SocketOptionLevel.IP, SocketOptionName.DontFragment, true );
                        oSocket.SetSocketOption( SocketOptionLevel.Socket, SocketOptionName.DontLinger, true );

            //  /       oSocket.BeginReceive( oState.bData, 0, oState.bData.Length, SocketFlags.None,   //  no need to read
            //  /                               new AsyncCallback( AsyncTcpComm ), oState );            //  for output only
                    }
                    else
                    {
                        Utils.PrnLine( "removing tcp: {0}", oSocket.RemoteEndPoint.ToString( ) );
                        Monitor.Enter( aTcpClient );
                        aTcpClient.Remove( oState );
                        Monitor.Exit( aTcpClient );
                    }
                }
        //      Thread.Sleep( iTcpWake );
            }
            #region catch
            catch( Exception x )
            {
                bool    b=  true;
                SocketException se= x as SocketException;
                if(  se != null  )
                {
                    if(  se.SocketErrorCode == SocketError.Interrupted  )
                    {
                        b=  false;
                        if(  oSocket != null  )
                            Utils.PrnLine( "TcpConn:\tclosing tcp: {0} ({1})", oSocket.RemoteEndPoint.ToString( ), se.SocketErrorCode );
                    }
                }
                if(  b  )
                {
                    Utils.HandleEx( x );
                }
            }
            #endregion
        }
    }
}

I omitted exception handling in Start/Stop methods for brevity. Variation in behavior is during program termination: one app shuts down almost immediately while the other gets stuck in oTcpListnr.AcceptSocket( ) call. I know that this is a blocking call, but in that case why does it not present an issue for the 1st app?

Usage of this class cannot be any simpler, e.g. for a command-line tool:

开发者_如何学Python
class   Program
{
    public static void  Main( string[] args )
    {
        TcpServer.Start( false );
        Console.Read( );
        Console.WriteLine( "\r\nStopping.." );
        TcpServer.Stop( );
        Console.WriteLine( "\r\nStopped.  Press any key to exit.." );
        Console.Read( );
    }
}

Whether any clients have connected or not does not make a difference, 2nd app always gets stuck.

I found a potential solution (commented lines) by checking TcpListener.Pending( ) prior to .AcceptSocket( ) call, but this immediately affects CPU utilization, therefore an inclusion of smth like Thread.Sleep(.) is a must. Altogether though I'd rather avoid this approach if possible, because of extra connection wait times and CPU utilization (small as it is).

Still, the main question is: what may cause the same exact code to execute differently? Both apps are compiled on .NET 4 Client Profile, x86 (32-bit), no specific optimizations. Thank you in advance for good ideas!


Finally found the root cause: I missed a couple of important lines [hidden in a #region] in the Stop( ) method, which starts the ball rolling. Here's how it should look:

public static void      Stop( )
{
        bListen=    false;

        if(  thOutComm != null  )
        {
            try
            {
                oTcpListnr.Stop( );
            }
            catch( Exception x )
            {
                Utils.HandleEx( x );
            }
            thOutComm.Join( iTimeout );
            thOutComm=  null;
        }
        if(  oTimer != null  )
        {
            oTimer.Change( Timeout.Infinite, Timeout.Infinite );
            oTimer.Dispose( );
        }
    }

The call to TcpListener.Stop( ) kicks out the wait-cycle inside .AcceptSocket( ) with "A blocking operation was interrupted by a call to WSACancelBlockingCall" exception, which is then "normally ignored" (check for SocketError.Interrupted) by the code that i originally had.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜