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 关注
- 128 浏览
添加回答
举报