visual stdio中用C#,UDP协议写一个简陋的服务器
·
窗体1:
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Windows.Forms;
namespace UdpServerDemo
{
public partial class Form1 : Form
{
private Socket udpServerSocket;
private Thread listenThread;
private bool isServerRunning = false;
public Form1()
{
InitializeComponent();
}
// 启动UDP服务按钮1
private void btnStart_Click(object sender, EventArgs e)
{
if (!int.TryParse(txtPort.Text, out int port) || port < 1 || port > 65535)
{
MessageBox.Show("请输入合法端口");
return;
}
try
{
// 创建UDP Socket
udpServerSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
// 绑定本机所有网卡+指定端口
IPEndPoint endPoint = new IPEndPoint(IPAddress.Any, port);
udpServerSocket.Bind(endPoint);
isServerRunning = true;
// 新开线程循环接收数据(防止界面卡死)
listenThread = new Thread(ReceiveLoop);
listenThread.IsBackground = true;
listenThread.Start();
AppendLog($"UDP服务已启动,监听端口:{port}");
btnStart.Enabled = false;
btnStop.Enabled = true;
}
catch (Exception ex)
{
AppendLog($"启动失败:{ex.Message}");
}
}
// 循环接收客户端数据
private void ReceiveLoop()
{
byte[] buffer = new byte[1024 * 10];
while (isServerRunning)
{
try
{
// 存储客户端地址
IPEndPoint clientEp = new IPEndPoint(IPAddress.Any, 0);
EndPoint remoteEp = clientEp;
// 阻塞等待接收数据
int recvLen = udpServerSocket.ReceiveFrom(buffer, ref remoteEp);
clientEp = (IPEndPoint)remoteEp;
// 解析收到的字符串
string recvStr = Encoding.UTF8.GetString(buffer, 0, recvLen);
string clientInfo = $"{clientEp.Address}:{clientEp.Port}";
// 界面打印日志
Invoke(new Action(() =>
{
AppendLog($"[{clientInfo}] 收到:{recvStr}");
}));
// 给客户端回复消息
string response = $"服务端已收到你的消息:{recvStr}";
byte[] sendBuf = Encoding.UTF8.GetBytes(response);
udpServerSocket.SendTo(sendBuf, sendBuf.Length, SocketFlags.None, clientEp);
Invoke(new Action(() =>
{
AppendLog($"[{clientInfo}] 已回复:{response}");
}));
}
catch (SocketException)
{
// 服务关闭时抛出异常,正常退出循环
}
catch (Exception ex)
{
Invoke(new Action(() =>
{
AppendLog($"接收异常:{ex.Message}");
}));
}
}
}
// 停止服务按钮
private void btnStop_Click(object sender, EventArgs e)
{
isServerRunning = false;
udpServerSocket?.Close();
listenThread?.Abort();
AppendLog("UDP服务已停止");
btnStart.Enabled = true;
btnStop.Enabled = false;
}
// 追加日志到文本框
private void AppendLog(string msg)
{
txtLog.AppendText($"{DateTime.Now:HH:mm:ss} {msg}\r\n");
// 自动滚动到最后一行
txtLog.SelectionStart = txtLog.TextLength;
txtLog.ScrollToCaret();
}
// 窗口关闭时释放资源
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (isServerRunning)
{
udpServerSocket?.Close();
listenThread?.Abort();
}
}
private void button1_Click(object sender, EventArgs e)
{
//实例化客户端窗口
Form2 clientForm = new Form2();
clientForm.Show();
}
}
}
窗体2:
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Windows.Forms;
namespace UdpServerDemo
{
public partial class Form2 : Form
{
// 单Socket同时负责发送、接收
private Socket udpSocket;
private Thread recvThread;
private bool isRecving = false;
public Form2()
{
InitializeComponent();
// 创建UDP套接字并提前绑定随机本地端口,收发共用此端口
udpSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
IPEndPoint localBindEp = new IPEndPoint(IPAddress.Any, 0);
udpSocket.Bind(localBindEp);
// 初始关闭按钮不可点击
btnStopRecv.Enabled = false;
}
// 开启后台持续接收线程
private void btnStartRecv_Click(object sender, EventArgs e)
{
if (isRecving)
{
AppendLog("后台接收已开启,无需重复启动");
return;
}
isRecving = true;
recvThread = new Thread(ClientReceiveLoop);
recvThread.IsBackground = true;
recvThread.Start();
AppendLog("✅ 客户端后台接收线程已启动");
btnStartRecv.Enabled = false;
btnStopRecv.Enabled = true;
}
// 后台循环接收服务端下发的数据
private void ClientReceiveLoop()
{
byte[] buffer = new byte[1024 * 10];
while (isRecving)
{
try
{
EndPoint remoteEp = new IPEndPoint(IPAddress.Any, 0);
// 阻塞等待服务端消息
int recvLen = udpSocket.ReceiveFrom(buffer, ref remoteEp);
IPEndPoint serverEp = (IPEndPoint)remoteEp;
string msg = Encoding.UTF8.GetString(buffer, 0, recvLen);
Invoke(new Action(() =>
{
if (!this.IsDisposed)
{
AppendLog($"[来自 {serverEp.Address}:{serverEp.Port}] 收到:{msg}");
}
}));
}
catch (SocketException)
{
// 仅停止接收时跳出循环
if (!isRecving)
break;
}
catch (Exception ex)
{
Invoke(new Action(() =>
{
if (!this.IsDisposed)
{
AppendLog($"接收异常:{ex.Message}");
}
}));
}
}
}
// 发送消息到服务端
private void btnSend_Click(object sender, EventArgs e)
{
// 1. 校验IP
string ipStr = txtServerIP.Text.Trim();
if (!IPAddress.TryParse(ipStr, out IPAddress serverIp))
{
AppendLog("❌ IP地址格式错误!");
return;
}
// 2. 校验端口
string portStr = txtServerPort.Text.Trim();
if (!int.TryParse(portStr, out int port) || port < 1 || port > 65535)
{
AppendLog("❌ 端口必须是1~65535数字!");
return;
}
// 3. 校验发送内容
string sendContent = txtSendMsg.Text.Trim();
if (string.IsNullOrEmpty(sendContent))
{
AppendLog("❌ 发送内容不能为空!");
return;
}
IPEndPoint targetEp = new IPEndPoint(serverIp, port);
byte[] sendBuf = Encoding.UTF8.GetBytes(sendContent);
try
{
// 使用共用Socket发送
udpSocket.SendTo(sendBuf, sendBuf.Length, SocketFlags.None, targetEp);
AppendLog($"→ 发送至 {serverIp}:{port} 内容:{sendContent}");
// 发送成功清空输入框并聚焦
txtSendMsg.Clear();
txtSendMsg.Focus();
}
catch (Exception ex)
{
AppendLog($"❌ 发送失败:{ex.Message}(检查服务端是否启动/防火墙拦截)");
}
}
// 日志追加工具方法
private void AppendLog(string info)
{
txtLog.AppendText($"{DateTime.Now:HH:mm:ss} {info}\r\n");
txtLog.SelectionStart = txtLog.TextLength;
txtLog.ScrollToCaret();
}
// 关闭后台接收
private void btnStopRecv_Click(object sender, EventArgs e)
{
if (!isRecving)
{
AppendLog("当前未开启接收,无需关闭");
return;
}
// 标记停止循环
isRecving = false;
// 等待线程安全结束
recvThread?.Join(100);
AppendLog("✅ 客户端后台接收已关闭");
btnStartRecv.Enabled = true;
btnStopRecv.Enabled = false;
}
// 窗口关闭释放资源
private void Form2_FormClosing(object sender, FormClosingEventArgs e)
{
// 先停止接收线程
if (isRecving)
{
isRecving = false;
recvThread?.Join(100);
}
// 程序退出再关闭套接字
udpSocket?.Close();
}
}
}


更多推荐

所有评论(0)