首页 新闻 会员 周边

c# Socket开发,出现客户端一关闭,服务端CPU占用100%的情况,有没有高手分析一下?

0
悬赏园豆:10 [已解决问题] 解决于 2014-10-29 13:30

问题要么在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();
11ge的主页 11ge | 初学一级 | 园豆:11
提问于:2014-10-23 09:37
< >
分享
最佳答案
1

客户端在关闭的时候,会发送空数组到服务端,你在服务端接收事件里面加上代码,

判断如果接收空数组,那么就断开这个客户端连接,释放该客户端的所有资源。

收获园豆:10
高高高高高手不是我 | 菜鸟二级 |园豆:221 | 2014-10-24 17:14

确实是客户端关闭的问题,由于某些原因()服务器未检测到,导致CPU100%

11ge | 园豆:11 (初学一级) | 2014-10-29 13:28

客户端在关闭的时候,会发送什么样的数据呢?

11ge | 园豆:11 (初学一级) | 2014-10-29 13:31

@11ge: 会发送空数组啊,这时你服务器接收数据线程会接收到空数组。所以如果你看到接收到的东西为空就直接退出客户端线程就行了。

高高高高高手不是我 | 园豆:221 (菜鸟二级) | 2014-10-29 13:32
其他回答(5)
0

将CloseSocket中的代码一行一行注释进行测试,看究竟是哪行代码引起的?

dudu | 园豆:31003 (高人七级) | 2014-10-23 09:49

我试试看看,不过在正式环境中出现问题,调试却没有出现

支持(0) 反对(0) 11ge | 园豆:11 (初学一级) | 2014-10-23 10:34
0

异步socket还需要loop? 有点费解

Jaws | 园豆:316 (菜鸟二级) | 2014-10-23 09:52

哪里有loop?监听吗

支持(0) 反对(0) 11ge | 园豆:11 (初学一级) | 2014-10-23 10:22
0

其它的我不知道,但是在 APM 中,AsyncCallback 中第一个调用方法应该是 EndXXX。

Launcher | 园豆:45045 (高人七级) | 2014-10-23 09:52
0

读取的流模块有问题。要及时关闭

需要格局 | 园豆:2145 (老鸟四级) | 2014-10-23 14:24
0

受益匪浅啊~

来自夏尔 | 园豆:204 (菜鸟二级) | 2014-11-20 01:23
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册