C# 上位机UDP/TCP连接外部设备

连接方式:PC与外部设备使用网线连接同一个路由器,此时路由器通过DHCP给双方分配同网段的IP;

目标:通过UPD探测外部连接设备,获取外部设备的IP,再根据IP建立TCP链接;

一、UDP探测外部设备

UDP(无连接协议)与TCP(三次握手连接状态)不同,UDP的通信双方平等,没有服务端、客户端之分,且UDP通信可以广播,而TCP作为点对点协议,必须先建立连接,因此先用UDP广播获取外部设备IP。

复制代码
IPEndPoint point = new IPEndPoint(IPAddress.Any, 0); // 监听本机网卡的所有IP地址,设置自身的端口为0
using UdpClient client = new(point) { EnableBroadcast = true }; // 创建UdpClient对象,EnableBroadcast 给所有IP都发信息
byte[] request = Encoding.UTF8.GetBytes("自行定义的字符串");
IPAddress target = IPAddress.Broadcast;
await client.SendAsync(request.AsMemory(), new IPEndPoint(target, port));  // 发送双方约定的信息,port为已知的外部设备端口,外部设备不需要知道这边的端口是什么

while(!cancelToken.IsCanceled)
{
    UdpReceiveResult reply = await client.ReceiveAsync();
    // 解析reply.Buffer,获取外部设备的IP和Name
}

二、TCP连接

外部设备作为TCP的服务端(TcpListener),已固定ip和端口,由上位机作为客户端发送连接请求。

复制代码
TcpClient client = new TcpClient();
client.ConnectAsync(ip, port, token);  // ip为IPAddress对象,由UDP读出来后创建的,port为已经约定好的外部设备端口

连接方式:PC与外部设备通过网线直连,此时PC端需调整IP,让自身与外部设备在同一网段下;

目标:上位机读取自身网卡信息,按照已知的外部设备IP,修正网卡自身IP,实现同一网段,再建立TCP连接;

一、 获取本机网卡对象

复制代码
- NetworkInterface interface = NetworkInterface.GetAllNetworkInferfaces()  // 获取当前操作系统检测到的所有网络接口
                                               .Where(t => t.NetworkInterfaceType == NetworkInterfaceType.Ethernet &&  // 仅选择物理网卡,筛选掉回环地址、虚拟网卡、WIFI等
                                                           t.OperationalStatus == OperationalStatus.Up &&  // 仅选择已成功链接的网卡
                                                           !t.Name.Contains("Npcap", StringComparision.OrdinalIgnoreCase) &&  // 筛选掉虚拟网卡
                                                           !t.Name.Contains("Loopback", StringComparision.OrdinalIgnoreCase) &&  // 再筛一次回环地址
                                                           t.GetIPProperties().UnicastAddresses.Any(p => p.Address.AddressFamily == AddressFamily.InterNetwork)).// 只要InterNetwork IPV4;GetIPProperties:获取该网络接口的属性,包含网关、DHCP信息;UnicastAddresses:包含所有的单播地址信息,同时包含IPV4、IPV6(AddressFamily.InterNetworkV6)
                                                           FirstOrDefault();  

                                                           // DHCP 动态主机配置协议:网络设备自动获取IP、子网掩码、网关等信息;

二、 修改本机IP

复制代码
string[] parts = targetIp.Split['.'];  // targetIp为已知的外部设备IP
string clientIp = $"{parts[0]}.{parts[1]}.{parts[2]}.{100}";  // clientIp为上位机(Tcp客户端)的新IP,100那里自行添加自增逻辑什么的

// Windows
ProcessStartInfo info = new("netsh", $"interface ip set address \"{interface.Name}\" static {clientIp} 255.255.255.0")
{
    UseShellExecute = true,  // 修改IP需要管理员权限,UseShellExecute可以获得UAC提权,即临时获取管理员权限
    Verb = "runas",  // 弹窗提示是否给权限
    CreateNoWindow = true  // 后台运行
};

using Process process = Process.Start(info);
await process.WaitForExitAsync();
var errorCode = process.ExitCode;  // errorCode为0就是成功

// 后续恢复DHCP自动分配IP:netsh interface ip set address \"{interface.Name}\" dhcp

// Linux
ProcessStartInfo info = new("ip", $"addr replace {clientIp}/24 dev {interface.Name} ")  // 24为子网掩码长度
{
    RedirectStandardOutput = true,  // Process信息重定向到输出
    RedirectStandardError = true  // Process信息重定向到错误
};

using Process process = Process.Start(info);
await process.WaitForExitAsync();
var errorCode = process.ExitCode;

// 后续恢复DHCP自动分配IP:ip addr flash dev {interface.Name}

三、 建立TCP连接

同上;

相关推荐
xixingzhe28 小时前
AI 对话打字机效果:SSE 和 HTTP 的区别与适用场景
网络·网络协议·http
xiaoye-duck8 小时前
《C++ 项目:手写大模型接入 SDK》Gemini接口设计(上):初始化、全量响应实现和测试
开发语言·网络·c++·语言模型
布裘9 小时前
【银河麒麟】重启后时区丢失?排查发现 localtime 被业务程序替换成硬链接
linux·运维·网络
zhikouai10 小时前
把外部助手接进聊天软件的架构分层与参数配置
服务器·网络·php
huainingning10 小时前
锐捷10.X路由器版本升级不生效问题排查
运维·网络·智能路由器
QZ1665609515913 小时前
政务泛监测体系能力排行:AI 重塑监测边界,治理的颗粒度革命
网络·人工智能·安全·网络安全·政务
叼烟扛炮14 小时前
Linux 学习笔记(五十八):IO 多路复用封神——epoll 底层原理揭秘
linux·运维·服务器·网络·笔记·学习·php
叼烟扛炮14 小时前
Linux 学习笔记(五十一):数据链路层与 ARP 协议——局域网寻址与黑客骗局
linux·网络·网络协议·php·tcpdump
星恒随风15 小时前
Linux网络编程:彻底理解IO多路复用select!从fd_set位图、读写就绪到手写TCP多客户端字典服务器
linux·服务器·网络
xyzzklk16 小时前
在Open-WebUI中提升向量化速度
网络·人工智能·爬虫·ai·语言模型·自然语言处理·安卓