问题要么在socket,要么在写日志
public class ServerSocket { public ManualResetEvent m_listenEvent = new ManualResetEvent(false); public List<ClientModel> m_ClientList = new List<ClientModel>(); private string m_ip = string.Empty; private int m_port = 0; private int m_buffsize; public int m_index = 0; public Queue<RecvData> m_Quene = new Queue<RecvData>(); public object locker = new object(); public ServerSocket(string ip,int port,int buffsize = 1024) { m_ip = ip; m_port = port; m_buffsize = buffsize; } ~ServerSocket() { CloseSocket(); } public void ListenProc() { Socket listener = null; try { IPAddress ipAddress = IPAddress.Parse(m_ip); IPEndPoint localEndPoint = new IPEndPoint(ipAddress, m_port); listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); listener.Bind(localEndPoint); listener.Listen(100); } catch (Exception e) { Log.log("网络故障,请检查配置文件:" + e.Message, true); return; } Log.log(string.Format("服务器开始监听:ip={0},{1}", m_ip, m_port), true); while (true) { try { m_listenEvent.Reset(); listener.BeginAccept(new AsyncCallback(AcceptCallback), listener); m_listenEvent.WaitOne(); //等待连接 } catch { Log.log("监听异常.", true); } } } private void AcceptCallback(IAsyncResult ar) { string s_ip = string.Empty; try { Socket listener = (Socket)ar.AsyncState; Socket client = listener.EndAccept(ar); m_listenEvent.Set();//设置信号 IPAddress ip = ((System.Net.IPEndPoint)client.RemoteEndPoint).Address; s_ip = ip.ToString(); int port = ((System.Net.IPEndPoint)client.RemoteEndPoint).Port; if (!IsValidIP(s_ip)) { Log.log(string.Format("拒绝非法Client:IP={0}", s_ip), true); client.Close(); } else { Log.log(string.Format("Client连接成功:IP={0}", s_ip), true); ClientModel model = m_ClientList.FirstOrDefault(x => x.ip == s_ip && x.port == port); if ( model == null ) { model = new ClientModel(); model.socket = client; model.ip = s_ip; model.port = port; model.name = string.Empty;//未认证状态 model.status = (int)ConnectEnum.NoAuth; m_ClientList.Add(model); } else { model.socket = client; model.ip = s_ip; model.port = port; if (model.status == (int)ConnectEnum.NoConnected) { model.status = (int)ConnectEnum.NoAuth; model.name = string.Empty; } } RecvMessage recMsg = new RecvMessage(m_buffsize); recMsg.workSocket = client; client.BeginReceive(recMsg.buffer, 0, recMsg.MaxSize, 0, new AsyncCallback(ReceiveCallback), recMsg); } } catch { Log.log(string.Format("接受Client连接失败:ip={0}", s_ip), true); } } /*接受消息函数*/ private void ReceiveCallback(IAsyncResult ar) { string s_ip = string.Empty; int bytesRead = 0; try { RecvMessage recMsg = (RecvMessage)ar.AsyncState; Socket client = recMsg.workSocket; if (!CheckConnect(client)) { client.Shutdown(SocketShutdown.Both); client.Close(); Log.log("关闭连接.", true); return; } IPAddress ip = ((System.Net.IPEndPoint)client.RemoteEndPoint).Address; s_ip = ip.ToString(); bytesRead = client.EndReceive(ar); if (bytesRead == 0) { } else if (bytesRead == recMsg.MaxSize) { // 可能数据不是一次获取,分批保存 recMsg.lstByte.AddRange(recMsg.buffer.ToList()); /* 重新接收消息 */ } else // 所有字符收到 { for (int i = 0; i < bytesRead; i++) { recMsg.lstByte.Add(recMsg.buffer[i]); } int port = ((System.Net.IPEndPoint)client.RemoteEndPoint).Port; var clientModel = m_ClientList.FirstOrDefault(x => x.ip == s_ip && x.port == port); if (clientModel == null)//应该不会发生 { clientModel = new ClientModel(); clientModel.socket = client; clientModel.ip = s_ip; clientModel.port = port; clientModel.name = "自动创建?"; clientModel.status = (int)ConnectEnum.NoAuth; } RecvData MSG = new RecvData(); MSG.client = clientModel; MSG.data = recMsg.lstByte.ToArray(); lock (locker) { m_Quene.Enqueue(MSG); } recMsg.lstByte.Clear(); } client.BeginReceive(recMsg.buffer, 0, recMsg.MaxSize, 0, new AsyncCallback(ReceiveCallback), recMsg); } catch(Exception e) { Log.log(string.Format("接收Client数据失败,ip={0},err={1}", s_ip,e.Message), true); return; } } /*发送消息*/ public void Send(Socket client, byte[] byteData) { string s_ip = string.Empty; if (!CheckConnect(client)) { IPAddress ip = ((System.Net.IPEndPoint)client.RemoteEndPoint).Address; s_ip = ip.ToString(); Log.log(string.Format("客户断开,ip={0),connected={1}", s_ip, client.Connected), true); return; } try { client.BeginSend(byteData, 0, byteData.Length, 0, new AsyncCallback(SendCallback), client); } catch { Log.log(string.Format("发送数据至Client失败,ip={0}", s_ip), true); } } /*发送完成*/ private void SendCallback(IAsyncResult ar) { string s_ip = string.Empty; try { Socket client = (Socket)ar.AsyncState; IPAddress ip = ((System.Net.IPEndPoint)client.RemoteEndPoint).Address; s_ip = ip.ToString(); int bytesSent = client.EndSend(ar); } catch { Log.log(string.Format("发送至Client失败:ip={0}", s_ip)); } } private bool CheckConnect(Socket s) { if ( s == null || !s.Connected) { return false; } if (s.Poll(-1, SelectMode.SelectWrite) || s.Poll(-1, SelectMode.SelectRead)) { return true; } else if (s.Poll(-1, SelectMode.SelectError)) { return false; } return true; } private void CloseSocket() { int count = m_ClientList.Count; for(int i=0;i<count;i++) { Socket socket = m_ClientList[i].socket; if (CheckConnect(socket)) { socket.Shutdown(SocketShutdown.Both); socket.Close(); } m_ClientList[i].status = (int)ConnectEnum.NoConnected; } } private bool IsValidIP(string ip) { return true; } }
服务端启动
m_serSocket = new ServerSocket(ip, port); Thread t = new Thread(new ThreadStart(m_serSocket.ListenProc)); t.Start();
客户端在关闭的时候,会发送空数组到服务端,你在服务端接收事件里面加上代码,
判断如果接收空数组,那么就断开这个客户端连接,释放该客户端的所有资源。
确实是客户端关闭的问题,由于某些原因()服务器未检测到,导致CPU100%
客户端在关闭的时候,会发送什么样的数据呢?
@11ge: 会发送空数组啊,这时你服务器接收数据线程会接收到空数组。所以如果你看到接收到的东西为空就直接退出客户端线程就行了。
将CloseSocket中的代码一行一行注释进行测试,看究竟是哪行代码引起的?
我试试看看,不过在正式环境中出现问题,调试却没有出现
异步socket还需要loop? 有点费解
哪里有loop?监听吗
其它的我不知道,但是在 APM 中,AsyncCallback 中第一个调用方法应该是 EndXXX。
读取的流模块有问题。要及时关闭
受益匪浅啊~