C# TcpListener与MySqlConnection运行一段时间后停止接受连接
C#异步Socket服务器网络失效故障排查
我使用C#编写了一个异步Socket服务器,部署在运行Amazon Linux的Lightsail服务器上。该服务器通过TcpListener接受连接,当有客户端连接时启动新线程监听,完成SSL连接初始化后作为在线游戏服务器运行。
服务器正常运行约一天后,会突然出现网络完全失效的情况,故障出现间隔从22小时到一周不等,具体症状如下:
- 已连接的客户端会突然停止收发数据,日志显示无活动检测代码最终因未收到心跳包将其踢下线。
- 服务器无法连接本地运行的MySQL数据库(此时仍可通过PHPMyAdmin访问该数据库)。
- 服务器仍可向文件和控制台写入内容,日志功能正常。
我的代码与常规实现类似,已尝试参考Stack Overflow相关问题的优化方案,但服务器仍在约24小时后出现故障。故障发生前无任何异常日志,导致排查困难。
主循环代码
public void ListenLoop() { TcpListener listener = new TcpListener(IPAddress.Any, 26000); listener.Start(); while (true) { try { if (listener.Pending()) { listener.BeginAcceptTcpClient(new AsyncCallback(AcceptConnection), listener); Logger.Write(Logger.Level.INFO, "continuing the main loop"); } // Yield so we're not stuck in a busy-loop Thread.Sleep(5); } catch (Exception e) { Logger.Write(Logger.Level.ERROR, $"Error while waiting for listeners: {e.Message}\n{e.StackTrace}"); } } }
连接接受相关代码
/// <summary> /// Finish an async callback but spawn a new thread to handle it if necessary /// </summary> /// <param name="ar"></param> private void AcceptConnection(IAsyncResult ar) { if (ar.CompletedSynchronously) { // Force the accept logic to run async, to keep our listening // thread free. Action accept = () => AcceptCallback(ar); accept.BeginInvoke(accept.EndInvoke, null); } else { AcceptCallback(ar); } } private void AcceptCallback(IAsyncResult ar) { try { TcpListener listener = (TcpListener) ar.AsyncState; TcpClient client = listener.EndAcceptTcpClient(ar); // If the SSL connection takes longer than 5s we have a problem, and should stop client.Client.ReceiveTimeout = 5000; // Attempt to get the IP address of the client we're connecting to IPEndPoint ipep = (IPEndPoint)client.Client.RemoteEndPoint; string ip = ipep.Address.ToString(); Logger.Write(Logger.Level.INFO, $"Connection begun to {ip}"); // Authenticate and begin communicating with the client SslStream stream = new SslStream(client.GetStream(), false); try { stream.AuthenticateAsServer( serverCertificate, enabledSslProtocols: System.Security.Authentication.SslProtocols.Tls12, clientCertificateRequired: false, checkCertificateRevocation: true ); stream.ReadTimeout = 3600000; stream.WriteTimeout = 3600000; NetworkPlayer player = new NetworkPlayer(); player.Name = ip; player.Connection.Stream = stream; player.Connection.Connected = true; player.Connection.Client = client; stream.BeginRead(player.Connection.Buffer, 0, 1024, new AsyncCallback(ReadCallback), player); } catch (Exception e) { Logger.Write(Logger.Level.ERROR, $"Error while starting the connection to {ip}: {e.Message}"); // The following code just calls stream.Close(); and client.Close(); but sends exceptions to my logger. CloseConnectionSafely(client, stream); } } catch (Exception e) { Logger.Write(Logger.Level.ERROR, $"Error while starting a connection to an unknown user: {e.Message}"); } }
内容的提问来源于stack exchange,提问作者OrdiNeu
相关产品推荐
相关产品推荐

