TcpListener.AcceptSocket()行为:在终止时卡在一个应用程序中,但在另一个应用程序中没有?

时间:2011-10-03 22:27:16

标签: c#-4.0 tcplistener

我有两个基于相同代码的TCP服务器应用程序,但由于某种原因表现出不同的行为,我已经准备好试图找出原因。代码模式如下:

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
        }
    }
}

为简洁起见,我在Start / Stop方法中省略了异常处理。行为的变化是在程序终止期间:一个应用程序几乎立即关闭,而另一个应用程序停留在oTcpListnr.AcceptSocket()调用中。我知道这是一个阻止调用,但在这种情况下,为什么它不会出现第一个应用程序的问题?

这个类的用法不能更简单,例如对于命令行工具:

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( );
    }
}

是否有任何客户端连接没有任何影响,第二个应用程序总是卡住。

我通过在.AcceptSocket()调用之前检查TcpListener.Pending()找到了一个潜在的解决方案(注释行),但这会立即影响CPU利用率,因此必须包含像Thread.Sleep(。)这样的smth。总而言之,我宁可避免这种方法,因为额外的连接等待时间和CPU利用率(尽管很小)。

但是,主要问题是:什么可能导致相同的确切代码执行不同?这两个应用程序都是在.NET 4 Client Profile,x86(32位)上编译的,没有特定的优化。提前感谢您的好主意!

1 个答案:

答案 0 :(得分:1)

终于找到了根本原因:我错过了Stop()方法中隐藏在#region中的几条重要线条,这些线条开始滚动。以下是它的外观:

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( );
        }
    }

对TcpListener.Stop()的调用在.AcceptSocket()中启动了等待循环,其中“阻塞操作被调用WSACancelBlockingCall”中断,然后“通常被忽略”(检查SocketError.Interrupted )通过我原来的代码。