因此,我试图制作一个可以执行从客户端发送的功能的应用程序,它工作正常,但UI冻结,同时侦听来自客户端的消息时,我需要更改些什么才能使此代码运行Async?已经尝试将public void ExecuteServer(string pwd)更改为公共异步任务ExecuteServer(string pwd),但这只是告诉我即时通讯没有等待状态
//Where im calling it
public Form2()
{
InitializeComponent();
(ExecuteServer("test"));
}
//The Network Socket im trying to run Async
public static void ExecuteServer(string pwd)
{
// Establish the local endpoint
// for the socket. Dns.GetHostName
// returns the name of the host
// running the application.
IPHostEntry ipHost = Dns.GetHostEntry(Dns.GetHostName());
IPAddress ipAddr = ipHost.AddressList[0];
IPEndPoint localEndPoint = new IPEndPoint(ipAddr, 11111);
// Creation TCP/IP Socket using
// Socket Class Costructor
Socket listener = new Socket(ipAddr.AddressFamily,
SocketType.Stream, ProtocolType.Tcp);
try
{
// Using Bind() method we associate a
// network address to the Server Socket
// All client that will connect to this
// Server Socket must know this network
// Address
listener.Bind(localEndPoint);
// Using Listen() method we create
// the Client list that will want
// to connect to Server
listener.Listen(10);
while (true)
{
//Console.WriteLine("Waiting connection ... ");
// Suspend while waiting for
// incoming connection Using
// Accept() method the server
// will accept connection of client
Socket clientSocket = listener.Accept();
// Data buffer
byte[] bytes = new Byte[1024];
string data = null;
while (true)
{
int numByte = clientSocket.Receive(bytes);
data += Encoding.ASCII.GetString(bytes,
0, numByte);
if (data.IndexOf("<EOF>") > -1)
break;
}
Console.WriteLine("Text received -> {0} ", data);
if(data == "<EOF> " + "kill")
{
Application.Exit();
}
else if (data == "<EOF>" + "getpw")
{
sendtoclient(clientSocket, pwd);
}
else
{
sendtoclient(clientSocket, "Error 404 message not found!");
}
// Close client Socket using the
// Close() method. After closing,
// we can use the closed Socket
// for a new Client Connection
clientSocket.Shutdown(SocketShutdown.Both);
clientSocket.Close();
}
}
catch (Exception e)
{
//Console.WriteLine(e.ToString());
}
}
答案 0 :(得分:2)
由于您不在服务器循环中访问或更改UI,因此建议您使用线程。
您可以像这样启动新线程:
public Form2()
{
InitializeComponent();
Thread serverThread = new Thread(() => ExecuteServer("test"));
serverThread.Start();
}
这里要注意几件事。
首先,永远不要在构造函数内部启动长时间运行的线程。为此,请使用Load
事件。如果双击设计器中的表单,则可以为其创建事件处理程序。您还可以执行以下操作:
public Form2()
{
InitializeComponent();
this.Load += (o, e) => StartServer();
}
private void StartServer()
{
Thread serverThread = new Thread(() => ExecuteServer("test"));
serverThread.Start();
}
接下来要注意的是,除了将正确的数据发送到套接字外,您目前无法停止线程。您至少应在外部while循环中使用volatile bool
而不是true
。
此外,您应尽量少使用Application.Exit
。使用这种线程解决方案,我建议您只是打破while循环,并在线程方法的末尾执行一些关闭操作。您的ExecuteServer
方法可能看起来像这样:
public static void ExecuteServer(string pwd, Action closingAction)
{
// Establish the local endpoint
// for the socket. Dns.GetHostName
// returns the name of the host
// running the application.
IPHostEntry ipHost = Dns.GetHostEntry(Dns.GetHostName());
IPAddress ipAddr = ipHost.AddressList[0];
IPEndPoint localEndPoint = new IPEndPoint(ipAddr, 11111);
// Creation TCP/IP Socket using
// Socket Class Costructor
Socket listener = new Socket(ipAddr.AddressFamily,
SocketType.Stream, ProtocolType.Tcp);
try
{
// Using Bind() method we associate a
// network address to the Server Socket
// All client that will connect to this
// Server Socket must know this network
// Address
listener.Bind(localEndPoint);
// Using Listen() method we create
// the Client list that will want
// to connect to Server
listener.Listen(10);
while (_shouldContinue)
{
//Console.WriteLine("Waiting connection ... ");
// Suspend while waiting for
// incoming connection Using
// Accept() method the server
// will accept connection of client
Socket clientSocket = listener.Accept();
// Data buffer
byte[] bytes = new Byte[1024];
string data = null;
while (true)
{
int numByte = clientSocket.Receive(bytes);
data += Encoding.ASCII.GetString(bytes,
0, numByte);
if (data.IndexOf("<EOF>") > -1)
break;
}
Console.WriteLine("Text received -> {0} ", data);
if (data == "<EOF> " + "kill")
{
break;
}
else if (data == "<EOF>" + "getpw")
{
sendtoclient(clientSocket, pwd);
}
else
{
sendtoclient(clientSocket, "Error 404 message not found!");
}
// Close client Socket using the
// Close() method. After closing,
// we can use the closed Socket
// for a new Client Connection
clientSocket.Shutdown(SocketShutdown.Both);
clientSocket.Close();
}
}
catch (Exception e)
{
//Console.WriteLine(e.ToString());
}
closingAction();
}
您的StartServer
必须进行一些调整:
private void StartServer()
{
Action closingAction = () => this.Close();
Thread serverThread = new Thread(() => ExecuteServer("test", closingAction));
serverThread.Start();
}
服务器结束后,这将关闭表单。当然,您可以更改执行的动作。
shouldContinue
布尔也应如下所示:
private static volatile bool _shouldContinue = true;
您当然可以将其交换为属性,或者如果希望循环结束,只需将其设置为false即可。
最后,请记住,如果使用listener.Accept();
之类的阻塞调用,则在更改布尔值时当然不会立即取消线程。对于这些事情,我建议您远离阻塞这样的呼叫,并尝试例如在超时的情况下进行查找。
希望您可以以此为起点。
祝好运!
编辑:
在考虑接受的答案时,我必须重复您永远不要在构造函数内部启动长时间运行的线程/任务。如果您确实要使用async / await代替任务,请不要像接受的答案所建议的那样做。
首先,将整个方法主体包装在Task.Run
中看起来很可怕,并带来了更多的嵌套层。有很多方法可以更好地做到这一点:
Task.Run
。Task.Run
。Task.Run
。 另外,正如我在接受的答案下的评论中所提到的,使用Load事件并在构造函数中执行以下操作会更好:
Load += async (o, e) => await Task.Run(() => ExecuteServer("test"));
。
不仅解决了在构造函数内部启动长时间运行的任务的问题,而且还使调用在那里异步进行,而没有ExecuteServer
函数内部的任何丑陋嵌套(请参见第3点)。
如果您希望ExecuteServer
函数本身是异步的,请参见第1点和第2点。
答案 1 :(得分:0)
在ExecuteServer的开头使用await Task.Run(() => {...});
,并将其代码放入{...}
中。
P.S。在使用上面的代码之前,如果您要使用UI中的任何组件,请将其属性插入变量中。像这样:var name = txtName.Text;
并使用变量。