У меня есть два приложения 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 (). Я знаю, что это блокирующий вызов, но в таком случае почему он не представляет проблемы для 1-го приложения?
Использование этого класса не может быть проще, например. для инструмента командной строки:
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( );
}
}
Независимо от того, подключены клиенты или нет, не имеет значения, второе приложение всегда зависает.
Я нашел потенциальное решение (закомментированные строки), проверив TcpListener.Pending () перед вызовом .AcceptSocket (), но это сразу же влияет на загрузку ЦП, поэтому необходимо включить что-то вроде Thread.Sleep (.). В целом, хотя я бы предпочел избегать такого подхода, если это возможно, из-за дополнительного времени ожидания соединения и загрузки ЦП (хотя бы небольшого).
Тем не менее, главный вопрос: что может заставить один и тот же точный код выполняться по-разному? Оба приложения скомпилированы в .NET 4 Client Profile, x86 (32-разрядная версия), без особых оптимизаций. Заранее спасибо за хорошие идеи!