亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

當后臺代碼運行 C# 時,如何使我的 UI 不凍結

當后臺代碼運行 C# 時,如何使我的 UI 不凍結

C#
斯蒂芬大帝 2023-04-16 09:51:06
因此,我試圖制作一個可以執行從客戶端發送的功能的應用程序,它工作正常,但 UI 在偵聽來自客戶端的消息時凍結,我必須更改什么才能使此代碼異步運行?已經嘗試將 public void ExecuteServer(string pwd) 更改為 public async task ExecuteServer(string pwd) 但它只是告訴我我缺少等待//Where im calling itpublic 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;            }
查看完整描述

2 回答

?
BIG陽

TA貢獻1859條經驗 獲得超6個贊

由于您沒有在服務器循環中訪問或更改 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看起來很糟糕的地方,并帶來更多的嵌套層。您可以通過多種方式更好地做到這一點:

  1. 使用本地函數并在其上執行Task.Run

  2. 使用一個單獨的函數并Task.Run在其上執行。

  3. 如果您只想異步啟動它一次并且有同步執行函數(阻塞)的用例,那么您應該保持這樣的函數并Task.Run在調用它時對其進行操作。

另外正如我在接受的答案下的評論中提到的那樣,使用 Load 事件并在構造函數中這樣做會更好:
Load += async (o, e) => await Task.Run(() => ExecuteServer("test"));。

不僅解決了在構造函數中啟動長時間運行的任務的問題,而且還使調用在函數內部沒有任何丑陋的嵌套而異步調用ExecuteServer(參見第 3 點)。
如果您希望ExecuteServer函數本身是異步的,請參閱第 1 點和第 2 點。


查看完整回答
反對 回復 2023-04-16
?
慕姐8265434

TA貢獻1813條經驗 獲得超2個贊

await Task.Run(() => {...});在ExecuteServer的開頭使用,將它的代碼放在里面{...}

PS 在使用上面的代碼之前,如果您使用 UI 中的任何組件,請將其屬性插入變量中。像這樣:var name = txtName.Text;并使用變量。



查看完整回答
反對 回復 2023-04-16
  • 2 回答
  • 0 關注
  • 151 瀏覽

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號