异步套接字阻塞UI线程
本文关键字:UI 线程 套接字 异步 | 更新日期: 2023-09-27 17:53:20
参见我之前的问题:异步套接字调用冻结UI线程
问题是客户端,连接到服务器或发送没有问题,但是当调用'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);
}
}
当你尝试在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);
}
}