我有两个基于相同代码的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位)上编译的,没有特定的优化。提前感谢您的好主意!
答案 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 )通过我原来的代码。