它在控制台应用程序中运行良好,但是当我创建WinForm时,它会冻结我的表单。
我实际上知道,为什么会发生:
public static Task<int> ReceiveAsync(this Socket socket, byte[] buffer, int offset, int size, SocketFlags flags = SocketFlags.None)
{
if (socket == null) throw new Exception("Socket is null.");
var tcs = new TaskCompletionSource<int>(socket);
socket.BeginReceive(buffer, offset, size, flags, iar =>
{
var t = (TaskCompletionSource<int>)iar.AsyncState;
var s = (Socket)t.Task.AsyncState;
try { t.SetResult(s.EndReceive(iar)); }
catch (Exception exc) { t.SetException(exc); }
}, tcs);
return tcs.Task;
}
while ((byteRead = ReceiveAsync(socket, buffer, 0, buffer.Length, SocketFlags.None).Result) > 0)
{
lock (buffer)
{
try
{
byte[] dBuffer = decompressor.Decompress(buffer);
lock (dBuffer)
{
string receivedData = Encoding.UTF8.GetString(dBuffer);
OnRead(receivedData, byteRead);
}
}
catch (Exception ex)
{
Client.Base.Log.Save(ex);
socket.Shutdown(SocketShutdown.Both);
}
}
}
我认为,在单独的线程中启动ReceiveAsync-Task方法不是一个好主意。
我可以使用没有while循环的FormAsync,如Async-Methods(BeginXXX,EndXXX)吗?
提前致谢!
答案 0 :(得分:0)
看起来您需要在单独的线程中调用第二个代码段。否则,第二个代码片段只会强制从第一个代码段的异步调用同步工作(这就是让你的WindowsForms应用程序挂起的原因 - 只需调用你在单独的线程中发布的整个代码的第二部分,它就可以了。)
为避免挂起应用程序,可以稍微更改您使用的功能的定义 - 如下所示:
// Is not changed
public static Task<int> ReceiveAsync(this Socket socket, byte[] buffer, int offset, int size, SocketFlags flags = SocketFlags.None)
{
if (socket == null) throw new Exception("Socket is null.");
var tcs = new TaskCompletionSource<int>(socket);
socket.BeginReceive(buffer, offset, size, flags, iar =>
{
var t = (TaskCompletionSource<int>)iar.AsyncState;
var s = (Socket)t.Task.AsyncState;
try { t.SetResult(s.EndReceive(iar)); }
catch (Exception exc) { t.SetException(exc); }
}, tcs);
return tcs.Task;
}
// Moved to new function
public void PerformRead()
{
while ((byteRead = ReceiveAsync(socket, buffer, 0, buffer.Length, SocketFlags.None).Result) > 0)
{
lock (buffer)
{
try
{
byte[] dBuffer = decompressor.Decompress(buffer);
lock (dBuffer)
{
string receivedData = Encoding.UTF8.GetString(dBuffer);
OnRead(receivedData, byteRead);
}
}
catch (Exception ex)
{
Client.Base.Log.Save(ex);
socket.Shutdown(SocketShutdown.Both);
}
}
}
}
然后,当您以下列方式调用读取套接字时,您的应用程序将顺利运行(没有延迟):
// Invokes reading of socket in separate thread
Thread readSocketThread = new Thread(this.PerformRead);
readSocketThread.Start();
注意:您必须以某种方式将读取的数据传送到Windows窗体控件(例如,通过某些字段或属性或直接从读取套接字的线程访问窗体的字段)。 / p>