我使用TcpListener和SocketClient构建了一个基本的.NET服务器 - 客户端基础结构。 它是多线程和异步的。问题是,当一次连接超过30个客户端时,服务器在某些时候崩溃。
虽然我确实使用了很多Try-Catch块来确保记录所有异常情况,但我还无法找到崩溃的原因。
所以我在想,我可能在服务器代码中从概念上做错了。我希望你们能帮助我找到那些崩溃的原因。代码如下:
启动服务器并侦听连接:
public void StartServer()
{
isConnected = true;
listener.Start();
connectionThread = new Thread(new ThreadStart(ListenForConnection));
connectionThread.Start();
}
private void ListenForConnection()
{
while (isConnected)
{
try
{
TcpClient client = listener.AcceptTcpClient();
ClientConnection connection = new ClientConnection(this, client);
connections.Add(connection);
}
catch (Exception ex)
{
log.Log("Exception in ListenForConnection: " + ex.Message, LogType.Exception);
}
}
}
ClientConnection类:
public class ClientConnection : IClientConnection
{
private TcpClient client;
private ISocketServer server;
private byte[] data;
private object metaData;
public TcpClient TcpClient
{
get { return client; }
}
internal ClientConnection(ISocketServer server, TcpClient client)
{
this.client = client;
this.server = server;
data = new byte[client.ReceiveBufferSize];
lock (client.GetStream())
{
client.GetStream().BeginRead(data, 0, client.ReceiveBufferSize, ReceiveMessage, null);
}
}
internal void ReceiveMessage(IAsyncResult ar)
{
int bytesRead;
try
{
lock (client.GetStream())
{
bytesRead = client.GetStream().EndRead(ar);
}
if (bytesRead < 1)
return;
byte[] toSend = new byte[bytesRead];
for (int i = 0; i < bytesRead; i++)
toSend[i] = data[i];
// Throws an Event with the data in the GUI Dispatcher Thread
server.ReceiveDataFromClient(this, toSend);
lock (client.GetStream())
{
client.GetStream().BeginRead(data, 0, client.ReceiveBufferSize, ReceiveMessage, null);
}
}
catch (Exception ex)
{
Disconnect();
}
}
public void Disconnect()
{
// Disconnect Client
}
}
将数据从服务器发送到一个或所有客户端:
public void SendDataToAll(byte[] data)
{
BinaryWriter writer;
try
{
foreach (IClientConnection connection in connections)
{
writer = new BinaryWriter(connection.TcpClient.GetStream());
writer.Write(data);
writer.Flush();
}
}
catch (Exception ex)
{
// Log
}
}
public void SendDataToOne(IClientConnection client, byte[] data)
{
BinaryWriter writer;
try
{
writer = new BinaryWriter(client.TcpClient.GetStream());
writer.Write(data);
writer.Flush();
}
catch (Exception ex)
{
// Log
}
}
在某些时候服务器崩溃,我真的没有起点甚至可以找到问题。如果需要,我可以提供更多代码。
非常感谢任何帮助:-) 安德烈
答案 0 :(得分:1)
您应该访问连接字段线程安全。
在SendData中,您正在迭代连接并向每个客户端发送数据。如果在执行foreach循环时新客户端连接,您将收到一条异常,其中显示消息“集合已被修改;枚举操作可能无法执行”,因为在您对其进行迭代时修改了集合,这是不允许的。
将SendDataToAll中的行修改为
foreach (IClientConnection connection in connections.ToList())
使问题消失(解决方案是Collection was modified; enumeration operation may not execute)。
答案 1 :(得分:0)
ClientConnection.ReceiveMessage方法的catch块中的Disconnect调用可能抛出异常,然后从catch中传出并且未处理。
要确保捕获所有异常并记录它们,请尝试向AppDomain.CurrentDomain.UnhandledException事件注册事件处理程序。此外,如果您将服务器作为Windows服务运行,则应用程序事件日志中可能存在.NET异常条目。