実際の問題領域を覆い隠すことなく、できるだけ多くのコードを省略しようとしました。完全なコードを表示する必要がある場合は、お知らせください。
そのため、データベース接続を軽減し、単一ノードからのすべてのインバウンド データベース リクエストを処理する非常にシンプルな TCP アプリケーションを構築しました。このコードは、約 200,000 の接続 (要求と応答) を処理し、その後、要求を受信すると BinaryFormatter.Deserialize メソッドでランダムにどこかでハングします。なぜこれが起こっているのか、誰にも考えがありますか?
例外は生成されず、無期限にハングします。
サーバーコード:
public class TCPServer
{
/// <summary>
/// The listener which listens for inbou nd requests.
/// </summary>
private TcpListener _tcpListener;
/// <summary>
/// The thread the inbound listener operates on.
/// </summary>
private Thread _listenerThread;
private static object _lockObject = new object();
public TCPServer()
{
_tcpListener = new TcpListener( IPAddress.Any, 19926 );
_listenerThread = new Thread( new ThreadStart( ListenForClients ) );
_listenerThread.Start();
//Get the server's ip so that the server can connect to its own database.
DAL.ServerIP = GetLocalIP();
}
/// <summary>
/// Waits for new clients to communicate. When a new client request is heard,
/// the connection is given its own processing thread.
/// </summary>
private void ListenForClients()
{
_tcpListener.Start();
while( true )
{
TcpClient client = _tcpListener.AcceptTcpClient();
Thread clientThread = new Thread( delegate()
{
//Pass in the Current Thread Number so that it can be locked in
HandleClientComm( client );
} );
clientThread.Start();
}
}
/// <summary>
/// Handles all of the connections for requests. After a request is recieved, the
/// TcpClient is passed to this method in its own thread for processing. This is
/// where all of the magic happens. Here we deserialize the NetworkStream and
/// use the resulting object to determine which request the client is making, and
/// respond appropriately.
/// </summary>
/// <param name="client"></param>
private void HandleClientComm( object client )
{
lock( _lockObject )
{
Response response = new Response();
TcpClient tcpClient = (TcpClient) client;
try
{
NetworkStream clientStream = tcpClient.GetStream();
IFormatter formatter = new BinaryFormatter();
object result = formatter.Deserialize( clientStream );
//Determine which type of request this is
Response response = new Response();
//Code Omitted, Determine which type of request, and use that to formulate the response.
RespondToClient( tcpClient, response );
}
catch( Exception e )
{
response = new Response();
response.ErrorMessage = e.ToString();
RespondToClient( tcpClient, response );
}
}
}
private void RespondToClient( TcpClient client, Response response )
{
try
{
IFormatter formatter = new BinaryFormatter();
NetworkStream stream = client.GetStream();
formatter.Serialize( stream, response );
stream.Close();
client.Close();
}
catch( Exception e )
{
throw e;
}
}
}
クライアントコード:
public class TCPClient
{
public static string ServerIP = "192.168.2.200";
private static Response RequestTCP<T>(T request)
{
try
{
TcpClient client = new TcpClient();
IPEndPoint serverEndPoint = new IPEndPoint( IPAddress.Parse( ServerIP ), 19926 );
client.Connect( serverEndPoint );
NetworkStream stream = client.GetStream();
IFormatter formatter = new BinaryFormatter();
formatter.Serialize( stream, request );
Response response = ( Response ) formatter.Deserialize( stream );
return response;
}
catch( Exception e )
{
return new Response( "Error with the Response: " + e.ToString() );
}
}
}