异步Socket调用冻结UI线程 [英] Asynchronous socket calls freezing UI Thread

查看:182
本文介绍了异步Socket调用冻结UI线程的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经工作一个客户端到服务器的聊天信使上我遇到了关于异步调用的一些问题。我一直在努力,但没有成功,解决这些问题了一段时间。

I have been working on a client to server chat messenger and I have run into some issues regarding asynchronous calls. I have been trying, with no success, to fix them for a while.

问题是与客户,还有连接到服务器没有问题,但一旦第一'BeginSend方法被调用整个客户端停止响应(它不会停止100%偶尔响应但经过一个可笑的回应30秒+)的时间。呼叫的其余工作正常,但UI不会作出回应。服务器响应罚款为好。

The issue is with the client, there is no problem connecting to the server but once the first 'BeginSend' method is called the whole client stops responding.(It doesn't stop 100% it occasionally responds but after a ridiculous response time of 30 seconds+). The rest of the calls operate fine but the UI wont respond. The server responds fine as well.

下面是code,我评论过这儿,客户端首先冻结。

Here is the code, I have commented HERE where the client first freezes.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Windows.Forms.VisualStyles;
using System.Net.Sockets;
using System.Net;

namespace Client_GUI_Design_Test
{
    public partial class Login : Form
    {
        public Socket clientSocket;
        public string strName;
        public byte[] byteData = new byte[1024];
        public List<String> contacts = new List<String>();
        public Boolean needUpdate = true;
       // public Panel globalPanel;
        public Login()
        {
            InitializeComponent();
        }

        public struct Contact
        {
            public string strName;
        }


        public int num1 = 0;
        public void addContact(String contactName, String message, int status, int imageNum)
        {
            //MessageBox.Show(this.Size.Width.ToString());
            panel1.HorizontalScroll.Enabled = false;
            panel1.HorizontalScroll.Visible = false;
            if (num1 >= panel1.Size.Height - 47)
            {
                panel1.Size = new Size(257, 514);
                this.Size = new Size(277, this.Size.Height);
                panel1.AutoScroll = true;
                panel1.HorizontalScroll.Enabled = false;
                panel1.HorizontalScroll.Visible = false;
                panel1.VerticalScroll.Visible = true;
            }
            panel1.VerticalScroll.Value = 0;
            //Contact Panel
            Panel contactPanel = new Panel();
            contactPanel.Size = new Size(249, 47);
            contactPanel.Margin = new System.Windows.Forms.Padding(0, 0, 0, 0);

            //Name Label
            Label name = new Label();
            //Font
            float size = 12.00f;
            name.Font = new Font("Microsoft Sans Serif", size, FontStyle.Bold);
            //Location
            name.Location = new Point(29, 3);
            //Size
            name.Size = new Size(112, 20);
            name.Text = contactName;
            //Events
            #region
            name.MouseEnter += delegate
            {
                contactPanel.BackColor = Color.Gainsboro;
            };
            name.MouseLeave += delegate
            {
                contactPanel.BackColor = System.Drawing.SystemColors.Control;
            };
            #endregion
            contactPanel.Controls.Add(name);

            //Image Box
            PictureBox image = new PictureBox();
            //Image
            image.Image = imageList1.Images[imageNum];
            //Size
            image.Size = new Size(56, 42);
            //Location
            image.Location = new Point(187, 4);
            //Events
            #region
            image.MouseEnter += delegate
            {
                contactPanel.BackColor = Color.Gainsboro;
            };
            image.MouseLeave += delegate
            {
                contactPanel.BackColor = System.Drawing.SystemColors.Control;
            };
            #endregion
            contactPanel.Controls.Add(image);

            //Status
            PictureBox statusPic = new PictureBox();
            //Image
            statusPic.Image = imageList2.Images[status];
            //Size
            statusPic.Size = new Size(20, 20);
            //Location
            statusPic.Location = new Point(3, 3);
            //Events
            #region
            statusPic.MouseEnter += delegate
            {
                contactPanel.BackColor = Color.Gainsboro;
            };
            statusPic.MouseLeave += delegate
            {
                contactPanel.BackColor = System.Drawing.SystemColors.Control;
            };
            #endregion
            contactPanel.Controls.Add(statusPic);

            //Message Label
            Label messageL = new Label();
            //Font
            float sizem = 11.25f;
            messageL.Font = new Font("Microsoft Sans Serif", sizem, FontStyle.Bold);
            messageL.ForeColor = Color.Gray;
            //Location
            messageL.Location = new Point(29, 23);
            //Size
            messageL.Size = new Size(153, 18);
            //Text
            messageL.Text = message;
            //Events
            #region
            messageL.MouseEnter += delegate
            {
                contactPanel.BackColor = Color.Gainsboro;
            };
            messageL.MouseLeave += delegate
            {
                contactPanel.BackColor = System.Drawing.SystemColors.Control;
            };
            messageL.MouseHover += delegate
            {
                ToolTip tip = new ToolTip();
                tip.Tag = messageL.Text;
                tip.Show(messageL.Text, messageL, 1, 1, 750);
            };
            #endregion

            contactPanel.Controls.Add(messageL);

            contactPanel.Paint += new PaintEventHandler(contactPanel_Paint);
            {


            };
            contactPanel.MouseEnter += delegate
            {
                contactPanel.BackColor = Color.Gainsboro;
            };
            contactPanel.MouseLeave += delegate
            {
                contactPanel.BackColor = System.Drawing.SystemColors.Control;
            };
            contactPanel.Location = new Point(0, num1);
            //globalPanel = contactPanel;
            //panel1.Controls.Add(contactPanel);
            addPanel(contactPanel);
            num1 += 47;


        }

        public delegate void UpdatePanelCallBack(Panel panel);
        private void addPanel(Panel panel)
        {
            if (InvokeRequired)
            {
                object[] pList = { panel };
                panel1.BeginInvoke(new
                   UpdatePanelCallBack(OnUpdatePanel), pList);
            }

            else
            {
                OnUpdatePanel(panel);
            }
        }

        private void OnUpdatePanel(Panel panel)
        {
            panel1.Controls.Add(panel);
        }

        VisualStyleRenderer renderer = new VisualStyleRenderer(VisualStyleElement.Button.PushButton.Normal);
        void contactPanel_Paint(object sender, PaintEventArgs e)
        {
            renderer.DrawEdge(e.Graphics, panel1.ClientRectangle,
                Edges.Top,
                EdgeStyle.Bump, EdgeEffects.Flat);
        }

        private void button3_Click(object sender, EventArgs e)
        {
            try
            {
                clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

                //IPAddress ipAddress = IPAddress.Parse(txtServerIP.Text);
                //Server is listening on port 43594
                IPEndPoint ipEndPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 43594);

                //Connect to the server
                clientSocket.BeginConnect(ipEndPoint, new AsyncCallback(OnConnect), null);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "SGSclient", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }


        }

        private void OnSend(IAsyncResult ar)
        {
            try
            {
                Socket client = (Socket)ar.AsyncState;
                client.EndSend(ar);
                //clientSocket.EndSend(ar);
               //strName = textBox2.Text;
               // DialogResult = DialogResult.OK;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "SGSclient", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void OnConnect(IAsyncResult ar)
        {
            try
            {
                clientSocket.EndConnect(ar);

                //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
                clientSocket.BeginSend(b, 0, b.Length, SocketFlags.None, new AsyncCallback(OnSend), clientSocket);

                clientSocket.BeginReceive(byteData,
                                       0,
                                       byteData.Length,
                                       SocketFlags.None,
                                       new AsyncCallback(OnReceive),
                                       clientSocket);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "SGSclient", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

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

        public void OnReceive(IAsyncResult ar)
        {
            try
            {
                clientSocket.EndReceive(ar);

                Data msgReceived = new Data(byteData);
                //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;
                }

                byteData = new byte[1024];

                clientSocket.BeginReceive(byteData,
                                          0,
                                          byteData.Length,
                                          SocketFlags.None,
                                          new AsyncCallback(OnReceive),
                                          clientSocket);

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

        }

        private void Login_Load(object sender, EventArgs e)
        {
            CheckForIllegalCrossThreadCalls = false;
            //backgroundWorker1.RunWorkerAsync();

        }

        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            while (true)
            {
                if(needUpdate){

                }
            }
        }


        private void Login_DoubleClick(object sender, EventArgs e)
        {
            MessageBox.Show("");
            foreach (string s in contacts)
            {
                addContact(s, "Random Message", 0, 1);
                needUpdate = false;
            }
        }
    }
}

固定的问题在其他类,但是在的onReceive仍然有问题(可能有助于更快地识别问题)

Fixed the problem in the other classes, however still having issues in OnReceive (Might help to faster identify the issue)

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

                Data msgReceived = new Data(byteData);
                //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;
                }

                byteData = new byte[1024];

               /* 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);
            }

        }

我知道这是一个很多code,我很抱歉,但是这是我最后的选择,我完全被卡住。任何帮助将大大AP preciated:)

I know it is a lot of code, I am sorry but this is my last option I am completely stuck. Any help would be greatly appreciated :)

推荐答案

您正在访问来自不同的线程ClientSocket的。

You are accessing clientSocket from different thread.

button3_Click 通话 BeginConnect 通过你的插座是这样的:

Inside button3_Click call BeginConnect passing your socket like this:

//Connect to the server
clientSocket.BeginConnect(ipEndPoint, new AsyncCallback(OnConnect), clientSocket);

的onReceive 得到AsyncState插座(这里经过时调用 BeginConnect

Inside OnReceive get the socket from AsyncState (passed here when called BeginConnect):

Socket client = (Socket)ar.AsyncState;
client.EndReceive(ar);

从MSDN <一个href=\"http://msdn.microsoft.com/en-us/library/system.net.sockets.socket.endconnect%28v=vs.110%29.aspx\"相对=nofollow> EndConnect

EndConnect是完成异步远程主机的连接请求在BeginConnect方法启动一个阻塞方法

调用BeginConnect之前,你需要创建一个实现AsyncCallback委托的回调方法。此回调方法执行在一个单独的线程和由系统调用BeginConnect返回之后。回调方法必须接受BeginConnect方法作为参数返回的IAsyncResult的。

编辑:

我可以在你的code看到,你正在使用 byteData 被声明为类字段,并从另一个线程访问缓冲区时 BeginReceive 正试图访问它。检查异步服务器套接字示例看你如何处理读取的部分。

As i can see in your code, your are using byteData buffer which is declared as class field and accessed from another thread when BeginReceive is trying to access it. Check the Asynchronous Server Socket Example to see how you can handle the reading part.

您可以看看下面这个例子在MSDN上插座code范例

You can look at this example on msdn Socket Code Examples

异步服务器套接字示例

异步客户端的Socket实例

这篇关于异步Socket调用冻结UI线程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆