使用C# WinForms开发的TCP/UDP网络小助手程序,包含客户端和服务器功能,支持TCP和UDP协议切换。这个程序将实现基本的消息发送和接收功能,并附带详细步骤和完整源码。
开发步骤
1. 创建项目:
- 在Visual Studio中创建新的Windows Forms应用程序 (.NET Framework)。
- 项目命名为`NetworkAssistant`。
2. 设计界面:
- 使用WinForms设计器创建一个主窗体,包含:
- 下拉框选择协议(TCP/UDP)。
- 文本框输入IP地址和端口。
- 按钮启动服务器或连接客户端。
- 文本框发送消息和显示接收消息。
- 按钮发送消息和清空消息。
3. 实现网络逻辑:
- TCP:使用`TcpListener`和`TcpClient`实现服务器和客户端。
- UDP:使用`UdpClient`实现无连接的消息收发。
- 使用异步方法(如`async/await`)处理网络操作,避免UI线程阻塞。
- 实现消息接收的循环和异常处理。
4. 添加功能:
- 协议切换(TCP/UDP)。
- 消息发送和接收的实时显示。
- 错误提示和日志记录。
5. 测试:
- 本地测试:运行程序,分别启动服务器和客户端,测试TCP和UDP消息收发。
- 确保界面响应良好,无卡顿。
源码
以下是完整的C# WinForms程序源码,包括窗体设计和网络逻辑。
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace NetworkAssistant
{
public partial class Form1 : Form
{
private TcpListener tcpListener;
private TcpClient tcpClient;
private UdpClient udpClient;
private bool isServerRunning;
private bool isClientConnected;
public Form1()
{
InitializeComponent();
}
// 窗体初始化
private void InitializeComponent()
{
this.comboBoxProtocol = new ComboBox();
this.labelIP = new Label();
this.textBoxIP = new TextBox();
this.labelPort = new Label();
this.textBoxPort = new TextBox();
this.buttonStartServer = new Button();
this.buttonConnectClient = new Button();
this.textBoxSend = new TextBox();
this.buttonSend = new Button();
this.textBoxReceive = new TextBox();
this.buttonClear = new Button();
// comboBoxProtocol
this.comboBoxProtocol.Items.AddRange(new object[] { "TCP", "UDP" });
this.comboBoxProtocol.Location = new System.Drawing.Point(20, 20);
this.comboBoxProtocol.Size = new System.Drawing.Size(100, 21);
this.comboBoxProtocol.SelectedIndex = 0;
// labelIP
this.labelIP.Text = "IP Address:";
this.labelIP.Location = new System.Drawing.Point(20, 50);
this.labelIP.Size = new System.Drawing.Size(60, 20);
// textBoxIP
this.textBoxIP.Text = "127.0.0.1";
this.textBoxIP.Location = new System.Drawing.Point(90, 50);
this.textBoxIP.Size = new System.Drawing.Size(150, 20);
// labelPort
this.labelPort.Text = "Port:";
this.labelPort.Location = new System.Drawing.Point(20, 80);
this.labelPort.Size = new System.Drawing.Size(60, 20);
// textBoxPort
this.textBoxPort.Text = "8080";
this.textBoxPort.Location = new System.Drawing.Point(90, 80);
this.textBoxPort.Size = new System.Drawing.Size(150, 20);
// buttonStartServer
this.buttonStartServer.Text = "Start Server";
this.buttonStartServer.Location = new System.Drawing.Point(20, 110);
this.buttonStartServer.Size = new System.Drawing.Size(100, 30);
this.buttonStartServer.Click += new EventHandler(this.buttonStartServer_Click);
// buttonConnectClient
this.buttonConnectClient.Text = "Connect Client";
this.buttonConnectClient.Location = new System.Drawing.Point(140, 110);
this.buttonConnectClient.Size = new System.Drawing.Size(100, 30);
this.buttonConnectClient.Click += new EventHandler(this.buttonConnectClient_Click);
// textBoxSend
this.textBoxSend.Location = new System.Drawing.Point(20, 150);
this.textBoxSend.Size = new System.Drawing.Size(300, 50);
this.textBoxSend.Multiline = true;
// buttonSend
this.buttonSend.Text = "Send";
this.buttonSend.Location = new System.Drawing.Point(330, 150);
this.buttonSend.Size = new System.Drawing.Size(60, 50);
this.buttonSend.Click += new EventHandler(this.buttonSend_Click);
// textBoxReceive
this.textBoxReceive.Location = new System.Drawing.Point(20, 210);
this.textBoxReceive.Size = new System.Drawing.Size(300, 150);
this.textBoxReceive.Multiline = true;
this.textBoxReceive.ReadOnly = true;
// buttonClear
this.buttonClear.Text = "Clear";
this.buttonClear.Location = new System.Drawing.Point(330, 210);
this.buttonClear.Size = new System.Drawing.Size(60, 50);
this.buttonClear.Click += new EventHandler(this.buttonClear_Click);
// Form
this.Text = "TCP/UDP Network Assistant";
this.Size = new System.Drawing.Size(420, 400);
this.Controls.Add(this.comboBoxProtocol);
this.Controls.Add(this.labelIP);
this.Controls.Add(this.textBoxIP);
this.Controls.Add(this.labelPort);
this.Controls.Add(this.textBoxPort);
this.Controls.Add(this.buttonStartServer);
this.Controls.Add(this.buttonConnectClient);
this.Controls.Add(this.textBoxSend);
this.Controls.Add(this.buttonSend);
this.Controls.Add(this.textBoxReceive);
this.Controls.Add(this.buttonClear);
}
// 启动服务器
private async void buttonStartServer_Click(object sender, EventArgs e)
{
if (isServerRunning)
{
MessageBox.Show("Server is already running!");
return;
}
try
{
string ip = textBoxIP.Text;
int port = int.Parse(textBoxPort.Text);
isServerRunning = true;
buttonStartServer.Enabled = false;
if (comboBoxProtocol.SelectedItem.ToString() == "TCP")
{
await StartTcpServer(ip, port);
}
else
{
await StartUdpServer(ip, port);
}
}
catch (Exception ex)
{
isServerRunning = false;
buttonStartServer.Enabled = true;
MessageBox.Show($"Error starting server: {ex.Message}");
}
}
// TCP服务器
private async Task StartTcpServer(string ip, int port)
{
tcpListener = new TcpListener(IPAddress.Parse(ip), port);
tcpListener.Start();
AppendReceiveText("TCP Server started...");
while (isServerRunning)
{
try
{
TcpClient client = await tcpListener.AcceptTcpClientAsync();
AppendReceiveText("Client connected.");
_ = HandleTcpClient(client); // 异步处理客户端
}
catch (Exception ex)
{
AppendReceiveText($"Server error: {ex.Message}");
break;
}
}
}
// 处理TCP客户端
private async Task HandleTcpClient(TcpClient client)
{
using (client)
using (NetworkStream stream = client.GetStream())
{
byte[] buffer = new byte[1024];
while (isServerRunning)
{
try
{
int bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);
if (bytesRead == 0) break;
string message = Encoding.UTF8.GetString(buffer, 0, bytesRead);
AppendReceiveText($"Received: {message}");
}
catch
{
AppendReceiveText("Client disconnected.");
break;
}
}
}
}
// UDP服务器
private async Task StartUdpServer(string ip, int port)
{
udpClient = new UdpClient(port);
AppendReceiveText("UDP Server started...");
while (isServerRunning)
{
try
{
UdpReceiveResult result = await udpClient.ReceiveAsync();
string message = Encoding.UTF8.GetString(result.Buffer);
AppendReceiveText($"Received from {result.RemoteEndPoint}: {message}");
}
catch (Exception ex)
{
AppendReceiveText($"Server error: {ex.Message}");
break;
}
}
}
// 连接客户端
private async void buttonConnectClient_Click(object sender, EventArgs e)
{
if (isClientConnected)
{
MessageBox.Show("Client is already connected!");
return;
}
try
{
string ip = textBoxIP.Text;
int port = int.Parse(textBoxPort.Text);
isClientConnected = true;
buttonConnectClient.Enabled = false;
if (comboBoxProtocol.SelectedItem.ToString() == "TCP")
{
tcpClient = new TcpClient();
await tcpClient.ConnectAsync(ip, port);
AppendReceiveText("Connected to TCP server.");
_ = ReceiveTcpClientMessages(); // 异步接收消息
}
else
{
udpClient = new UdpClient();
AppendReceiveText("UDP Client ready.");
}
}
catch (Exception ex)
{
isClientConnected = false;
buttonConnectClient.Enabled = true;
MessageBox.Show($"Error connecting: {ex.Message}");
}
}
// 接收TCP客户端消息
private async Task ReceiveTcpClientMessages()
{
try
{
using (NetworkStream stream = tcpClient.GetStream())
{
byte[] buffer = new byte[1024];
while (isClientConnected)
{
int bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);
if (bytesRead == 0) break;
string message = Encoding.UTF8.GetString(buffer, 0, bytesRead);
AppendReceiveText($"Received: {message}");
}
}
}
catch (Exception ex)
{
AppendReceiveText($"Client error: {ex.Message}");
}
finally
{
isClientConnected = false;
buttonConnectClient.Enabled = true;
tcpClient?.Close();
AppendReceiveText("Disconnected from server.");
}
}
// 发送消息
private async void buttonSend_Click(object sender, EventArgs e)
{
if (string.IsNullOrWhiteSpace(textBoxSend.Text))
{
MessageBox.Show("Please enter a message to send.");
return;
}
try
{
string message = textBoxSend.Text;
byte[] buffer = Encoding.UTF8.GetBytes(message);
if (comboBoxProtocol.SelectedItem.ToString() == "TCP")
{
if (isClientConnected && tcpClient != null)
{
NetworkStream stream = tcpClient.GetStream();
await stream.WriteAsync(buffer, 0, buffer.Length);
AppendReceiveText($"Sent: {message}");
}
else
{
MessageBox.Show("Client not connected!");
}
}
else
{
if (udpClient != null)
{
string ip = textBoxIP.Text;
int port = int.Parse(textBoxPort.Text);
await udpClient.SendAsync(buffer, buffer.Length, ip, port);
AppendReceiveText($"Sent: {message}");
}
else
{
MessageBox.Show("UDP client not initialized!");
}
}
textBoxSend.Clear();
}
catch (Exception ex)
{
MessageBox.Show($"Error sending message: {ex.Message}");
}
}
// 清空接收消息
private void buttonClear_Click(object sender, EventArgs e)
{
textBoxReceive.Clear();
}
// 追加接收消息到文本框
private void AppendReceiveText(string text)
{
if (textBoxReceive.InvokeRequired)
{
textBoxReceive.Invoke(new Action(() => textBoxReceive.AppendText(text + Environment.NewLine)));
}
else
{
textBoxReceive.AppendText(text + Environment.NewLine);
}
}
// 窗体关闭时清理资源
protected override void OnFormClosing(FormClosingEventArgs e)
{
isServerRunning = false;
isClientConnected = false;
tcpListener?.Stop();
tcpClient?.Close();
udpClient?.Close();
base.OnFormClosing(e);
}
private ComboBox comboBoxProtocol;
private Label labelIP;
private TextBox textBoxIP;
private Label labelPort;
private TextBox textBoxPort;
private Button buttonStartServer;
private Button buttonConnectClient;
private TextBox textBoxSend;
private Button buttonSend;
private TextBox textBoxReceive;
private Button buttonClear;
}
}
使用说明
1. 运行程序:
- 打开Visual Studio,创建新项目并替换`Form1.cs`为上述代码。
- 编译并运行程序。
2. 操作步骤:
- 选择协议:在下拉框中选择`TCP`或`UDP`。
- 输入IP和端口:默认使用`127.0.0.1`和`8080`,可根据需要修改。
- 启动服务器:点击“Start Server”按钮启动服务器,等待客户端连接。
- 连接客户端:在另一实例中,点击“Connect Client”按钮连接到服务器(TCP模式需要连接,UDP模式直接发送)。
- 发送消息:在发送文本框输入消息,点击“Send”发送。
- 查看消息:接收到的消息显示在下方文本框,点击“Clear”清空。
3. 注意事项:
- 确保端口未被占用。
- TCP需要服务器先启动,客户端再连接;UDP无需连接,直接发送。
- 异常情况(如断开连接)会显示在消息框或接收文本框。
测试建议
- 本地测试:在一台机器上运行两个程序实例,一个作为服务器,一个作为客户端。
- 网络测试:在不同机器上运行,修改IP地址为目标服务器IP。
- 协议切换:分别测试TCP和UDP功能,确保消息收发正常。
这个程序提供了一个简单但功能完整的TCP/UDP网络小助手,适合学习和测试网络通信。如果需要进一步扩展(如多客户端支持、文件传输等),可以基于此代码添加功能。