异步Socket调用冻结UI线程 [英] Asynchronous socket calls freezing UI Thread
问题描述
我已经工作一个客户端到服务器的聊天信使上我遇到了关于异步调用的一些问题。我一直在努力,但没有成功,解决这些问题了一段时间。
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 code>被声明为类字段,并从另一个线程访问缓冲区时
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调用冻结UI线程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!