我使用套接字编程在c#中创建了一个接收服务器的文件。我做了一个GUI。有一个名为' connect' 的按钮,它会在点击它时启动服务器,并且有一个文本框,当服务器启动时会显示一条消息。但是当我点击按钮时,GUI会冻结。
以下是我的示例代码:
using System;
using System.Drawing;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Collections.Generic;
class sampleserver : Form
{
private TextBox newText;
public TcpClient tcpClient;
public TcpListener tcpListener;
public sampleserver()
{
Text = " TCP Server";
Size = new Size(400, 380);
newText = new TextBox();
newText.Parent = this;
newText.Size = new Size(200, 2 * Font.Height);
newText.Location = new Point(10, 55);
Button connect = new Button();
connect.Parent = this;
connect.Text = "Connect";
connect.Location = new Point(295, 20);
connect.Size = new Size(6 * Font.Height, 2 * Font.Height);
connect.Click += new EventHandler(ButtonConnectOnClick);
}
void ButtonConnectOnClick(object obj, EventArgs ea)
{
tcpListener = new TcpListener(IPAddress.Any, 1234);
tcpListener.Start();
newText.Text = "Server started"; //**This line is not working**
//Infinite loop to connect to new clients
while (true)
{
// Accept a TcpClient
TcpClient tcpClient = tcpListener.AcceptTcpClient();
string address = ((IPEndPoint)tcpClient.Client.RemoteEndPoint).Address.ToString();
byte[] data = new byte[1024];
NetworkStream ns = tcpClient.GetStream();
int recv = ns.Read(data, 0, data.Length);
StreamReader reader = new StreamReader(tcpClient.GetStream());
// The first message from the client is the file size
string cmdFileSize = reader.ReadLine();
int length = Convert.ToInt32(cmdFileSize);
byte[] buffer = new byte[length];
int received = 0;
int read = 0;
int size = 1024;
int remaining = 0;
// Read bytes from the client using the length sent from the client
while (received < length)
{
remaining = length - received;
if (remaining < size)
{
size = remaining;
}
read = tcpClient.GetStream().Read(buffer, received, size);
received += read;
}
}
}
public static void Main()
{
Application.Run(new sampleserver());
}
}
我需要做哪些更改才能正常运行?
答案 0 :(得分:1)
我建议您使用异步套接字,但您也可以只使用按钮点击方法异步,就像这样。
async void ButtonConnectOnClick(object obj, EventArgs ea)
{
tcpListener = new TcpListener(IPAddress.Any, 1234);
tcpListener.Start();
newText.Text = "Server started"; //**This line is not working**
await Task.Run(() =>
{
//Infinite loop to connect to new clients
while (true)
{
// Accept a TcpClient
TcpClient tcpClient = tcpListener.AcceptTcpClient();
string address = ((IPEndPoint)tcpClient.Client.RemoteEndPoint).Address.ToString();
byte[] data = new byte[1024];
NetworkStream ns = tcpClient.GetStream();
int recv = ns.Read(data, 0, data.Length);
StreamReader reader = new StreamReader(tcpClient.GetStream());
// The first message from the client is the file size
string cmdFileSize = reader.ReadLine();
int length = Convert.ToInt32(cmdFileSize);
byte[] buffer = new byte[length];
int received = 0;
int read = 0;
int size = 1024;
int remaining = 0;
// Read bytes from the client using the length sent from the client
while (received < length)
{
remaining = length - received;
if (remaining < size)
{
size = remaining;
}
read = tcpClient.GetStream().Read(buffer, received, size);
received += read;
}
}
});
}
这会使整个方法异步,现在您可以从套接字读取而不冻结主UI。
古德勒克。
答案 1 :(得分:0)
UI事件通常意味着运行然后返回。您的程序正在启动应该在线程中启动的代码 - 通过按钮代码 - 然后在应用程序退出时正确停止。
正如Ron Beyer所说,你有一个while(true)
,但我更感兴趣的是读取是否超时以及按下按钮后如何返回主UI线程。看起来你永远不会回到主UI线程。正如我的评论所述,我测试网络代码,包括控制台应用程序中的while循环,然后添加UI的复杂性。
顺便说一下,正如其他评论所指出的那样,当您设置此代码以便网络设置(启动)成功时,您无法再次单击启动按钮。您必须禁用(灰显)按钮,因此无法双击,并且仅在网络启动(启动)失败时才启用。第二个按钮,不是灰色的,可以让你关闭所有东西。
线程和用户界面并不是你相信的简单。他们需要做很多工作。