【问题标题】:Asynchronous Sockets blocking UI thread异步套接字阻塞 UI 线程
【发布时间】:2014-03-26 08:22:05
【问题描述】:

有关上下文,请参阅我之前的问题:Asynchronous socket calls freezing UI Thread

问题出在客户端,连接到服务器或发送没有问题,但是当调用“OnReceive”方法时,整个客户端停止响应。(它不会 100% 停止它偶尔会响应,但在一个荒谬的响应之后时间为 30 秒+)。其余的调用运行良好,但 UI 不会响应。服务器响应也很好。

StateObject 类:

 class StateObject
    {
        // Client socket.
        public Socket workSocket = null;
        // Size of receive buffer.
        public const int BufferSize = 256;
        // Receive buffer.
        public byte[] buffer = new byte[BufferSize];
        // Received data string.
        public StringBuilder sb = new StringBuilder();
    }

OnConnect 方法:

private void OnConnect(IAsyncResult ar)
        {
            StateObject state = new StateObject();
            try
            {
                Socket client = (Socket)ar.AsyncState;
                client.EndConnect(ar);
               // StateObject state = new StateObject();
                state.workSocket = client;
                //We are connected so we login into the server
                Data msgToSend = new Data();
                msgToSend.cmdCommand = Command.Login;
                msgToSend.strName = textBox2.Text;
                msgToSend.strMessage = null;

                byte[] b = msgToSend.ToByte();

                //Send the message to the server
                //HERE - Starts freezing the UI thread, continues to do background operations
                state.workSocket.BeginSend(b, 0, b.Length, SocketFlags.None, new AsyncCallback(OnSend), state.workSocket);

                //byte[] byteBuffer = new byte[1024];
                state.workSocket.BeginReceive(state.buffer,
                                       0,
                                       state.buffer.Length,
                                       SocketFlags.None,
                                       new AsyncCallback(OnReceive),
                                       state);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "SGSclient", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

            panel4.Visible = false;
            panel1.Visible = true;
        }

OnReceive 方法:

public void OnReceive(IAsyncResult ar)
        {
            try
            {
                StateObject state = (StateObject)ar.AsyncState;
                Socket client = state.workSocket;
                client.EndReceive(ar);

                Data msgReceived = new Data(state.buffer);
                //Accordingly process the message received
                switch (msgReceived.cmdCommand)
                {
                    case Command.Login:
                        //lstChatters.Items.Add(msgReceived.strName);
                        break;

                    case Command.Logout:
                        //lstChatters.Items.Remove(msgReceived.strName);
                        break;

                    case Command.Message:
                        break;

                    case Command.List:
                        MessageBox.Show(msgReceived.strName);
                        //contacts.Add(msgReceived.strName);
                        needUpdate = true;
                        //lstChatters.Items.AddRange(msgReceived.strMessage.Split('*'));
                        //lstChatters.Items.RemoveAt(lstChatters.Items.Count - 1);
                        //txtChatBox.Text += "<<<" + strName + " has joined the room>>>\r\n";

                        break;
                }

                state.buffer = new byte[256];

               /* client.BeginReceive(byteData,
                                          0,
                                          byteData.Length,
                                          SocketFlags.None,
                                          new AsyncCallback(OnReceive),
                                          client);*/

            }
            catch (ObjectDisposedException)
            { }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "SGSclientTCP: " + strName, MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

        }

【问题讨论】:

    标签: c# multithreading sockets


    【解决方案1】:

    每当您尝试在 gui 上修改某些内容时,请使用 Invoke 或 BeginInvoke。 我试图更新你的代码,也许我在 vs 中编辑时留下了一些评论。

    private void OnConnect(IAsyncResult ar)
        {
            StateObject state = new StateObject();
            try
            {
                Socket client = (Socket)ar.AsyncState;
                client.EndConnect(ar);
                // StateObject state = new StateObject();
                state.workSocket = client;
                //We are connected so we login into the server
                Data msgToSend = new Data();
                msgToSend.cmdCommand = Command.Login;
                msgToSend.strName = textBox2.Text;
                msgToSend.strMessage = null;
    
                byte[] b = msgToSend.ToByte();
    
                //Send the message to the server
                //HERE - Starts freezing the UI thread, continues to do background operations
                state.workSocket.BeginSend(b, 0, b.Length, SocketFlags.None, new AsyncCallback(OnSend),
                    state.workSocket);
    
                state.workSocket.BeginReceive(state.buffer,
                    0,
                    state.buffer.Length,
                    SocketFlags.None,
                    new AsyncCallback(OnReceive),
                    state);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "SGSclient", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
    
            //use this when you want to update the gui
            this.BeginInvoke(new MethodInvoker(() =>
            {
                //panel4.Visible = false;
                //panel1.Visible = true;
            }));
    
        }
    
        public void OnReceive(IAsyncResult ar)
        {
            String content = String.Empty;
            try
            {
                StateObject state = (StateObject)ar.AsyncState;
                Socket handler = state.workSocket;
    
                // Read data from the client socket. 
                int bytesRead = handler.EndReceive(ar);
    
                if (bytesRead > 0)
                {
                    // There  might be more data, so store the data received so far.
                    state.sb.Append(Encoding.ASCII.GetString(
                        state.buffer, 0, bytesRead));
    
                    // Check for end-of-file tag. If it is not there, read 
                    // more data.
                    content = state.sb.ToString();
                    if (content.IndexOf("<EOF>") > -1)
                    {
                        // All the data has been read from the 
                        // client. Display it on the console.
                        //do something with the data, if you update gui use BeginInvoke:
    
                        //all your bytes are in state.sb
    
    
                        Data msgReceived = new Data(state.buffer);
                        //Accordingly process the message received
                        switch (msgReceived.cmdCommand)
                        {
                            case Command.Login:
                                //lstChatters.Items.Add(msgReceived.strName);
                                break;
    
                            case Command.Logout:
                                //lstChatters.Items.Remove(msgReceived.strName);
                                break;
    
                            case Command.Message:
                                break;
    
                            case Command.List:
                                MessageBox.Show(msgReceived.strName);
                                //contacts.Add(msgReceived.strName);
                                needUpdate = true;
    
    //Here you can use BeginInvoke or invoke   
    //lstChatters.Items.AddRange(msgReceived.strMessage.Split('*'));
                        //        //lstChatters.Items.RemoveAt(lstChatters.Items.Count - 1);
                        //        //txtChatBox.Text += "<<<" + strName + " has joined the room>>>\r\n";
    
                        //        break;
                        //}
                    }
                } else {
                // Not all data received. Get more.
                handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
                new AsyncCallback(OnReceive), state);
            }
    
            }
            catch (ObjectDisposedException)
            { }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "SGSclientTCP: " + strName, MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
    
        }
    

    【讨论】:

    • 效果很好,非常感谢。你保存了我的任务 :) 希望你有一个美好的一天。
    • 很高兴我能帮上忙。谢谢你!
    猜你喜欢
    • 2017-07-07
    • 1970-01-01
    • 2012-04-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-20
    • 1970-01-01
    • 2014-07-22
    相关资源
    最近更新 更多