当后台代码运行 C# 时,如何使我的 UI 不冻结

因此,我试图制作一个可以执行从客户端发送的功能的应用程序,它工作正常,但 UI 在侦听来自客户端的消息时冻结,我必须更改什么才能使此代码异步运行?已经尝试将 public void ExecuteServer(string pwd) 更改为 public async task 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;

            }



斯蒂芬大帝
浏览 171回答 2
2回答

BIG阳

由于您没有在服务器循环中访问或更改 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 循环中 使用 avolatile bool而不是 the 。true你也应该Application.Exit尽可能少地使用。对于这个线程解决方案,我建议只是跳出 while 循环并在线程方法结束时执行一些关闭操作。你的ExecuteServer-method 看起来像这样: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();您当然不会在更改 bool 时立即取消线程。对于这些事情,我建议您远离这样的阻塞调用,并尝试查找超时的事情。我希望你能以此为起点。祝你好运!编辑:在考虑接受的答案时,我必须重申,你永远不应该在构造函数中启动长时间运行的线程/任务。如果你真的想使用 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 点。

慕姐8265434

await Task.Run(() => {...});在ExecuteServer的开头使用,将它的代码放在里面{...}。PS 在使用上面的代码之前,如果您使用 UI 中的任何组件,请将其属性插入变量中。像这样:var name = txtName.Text;并使用变量。
打开App,查看更多内容
随时随地看视频慕课网APP