2 回答

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看起來很糟糕的地方,并帶來更多的嵌套層。您可以通過多種方式更好地做到這一點:
使用本地函數并在其上執行
Task.Run
。使用一個單獨的函數并
Task.Run
在其上執行。如果您只想異步啟動它一次并且有同步執行函數(阻塞)的用例,那么您應該保持這樣的函數并
Task.Run
在調用它時對其進行操作。
另外正如我在接受的答案下的評論中提到的那樣,使用 Load 事件并在構造函數中這樣做會更好:Load += async (o, e) => await Task.Run(() => ExecuteServer("test"));
。
不僅解決了在構造函數中啟動長時間運行的任務的問題,而且還使調用在函數內部沒有任何丑陋的嵌套而異步調用ExecuteServer
(參見第 3 點)。
如果您希望ExecuteServer
函數本身是異步的,請參閱第 1 點和第 2 點。

TA貢獻1813條經驗 獲得超2個贊
await Task.Run(() => {...});
在ExecuteServer的開頭使用,將它的代碼放在里面{...}
。
PS 在使用上面的代碼之前,如果您使用 UI 中的任何組件,請將其屬性插入變量中。像這樣:var name = txtName.Text;
并使用變量。
- 2 回答
- 0 關注
- 151 瀏覽
添加回答
舉報