化妆品网站建设目标,无锡百度推广平台,施工企业三大体系认证,哈尔滨网站建设网站开发一、场景背景在本地数据交互场景中#xff0c;手动开启 PC 热点后#xff0c;需实现手机连接热点后无需手动配置 IP#xff0c;通过 UDP 广播自动发现 PC、建立 TCP 稳定通信。本文聚焦 “手动开热点” 场景#xff0c;剥离热点创建代码#xff0c;强化 UDP 自动发现与 TC…一、场景背景在本地数据交互场景中手动开启 PC 热点后需实现手机连接热点后无需手动配置 IP通过 UDP 广播自动发现 PC、建立 TCP 稳定通信。本文聚焦 “手动开热点” 场景剥离热点创建代码强化 UDP 自动发现与 TCP 通信逻辑代码全程添加详细注释便于理解和二次开发。二、核心原理手动热点基础用户手动在 PC 端开启热点Windows/macOS/Linux 均可PC 作为热点网关会分配固定网段 IPWindows 默认192.168.137.1UDP 广播发现手机连接热点后发送DISCOVER_PC广播包PC 监听 UDP 端口并回复 TCP 服务端口解决 “找 IP / 端口” 问题TCP 可靠通信手机解析 UDP 回复后建立 TCP 连接配合心跳机制避免假连接断开后自动重连全流程解耦代码仅负责通信逻辑热点由用户手动开启降低代码复杂度和权限依赖。三、环境准备1. 硬件要求PC带无线网卡手动开启热点以 Windows 为例设置→网络和 Internet→移动热点→开启手机Android/iOS本文以 Android 为例连接 PC 热点。2. 开发环境PC 端Visual Studio 2019C/C11、Windows Socket 2.0手机端Android StudioKotlin、Android 7.0依赖PC 端链接ws2_32.libAndroid 端配置网络权限。四、PC 端实现C/C核心说明PC 端仅实现 “UDP 广播监听 TCP 服务端”热点由用户手动开启Windows 手动开热点后网关 IP 默认192.168.137.1需确认自身热点 IP 并修改代码。cpp运行// 头文件包含Windows Socket核心头文件基础工具头文件 #include windows.h #include winsock2.h #include ws2tcpip.h #include iostream #include thread #include chrono #include string #include cstring // 链接Windows Socket库必须添加否则编译报错 #pragma comment(lib, ws2_32.lib) /************************ 全局配置参数可根据需求修改 ************************/ #define UDP_DISCOVER_PORT 9999 // UDP广播监听端口需与手机端一致 #define TCP_SERVICE_PORT 8888 // TCP通信端口 #define PC_HOTSPOT_IP 192.168.137.1 // 手动开热点后PC的网关IP关键需确认自身热点IP #define BUF_SIZE 1024 // 数据缓冲区大小 #define HEARTBEAT_TIMEOUT 15 // 心跳超时时间秒超过该时间未收到心跳则断开 /************************ 全局变量通信状态管理 ************************/ SOCKET g_tcpClientSocket INVALID_SOCKET; // 保存已连接的手机客户端Socket bool g_isClientConnected false; // 标记是否有手机客户端连接 time_t g_lastHeartbeatTime; // 最后一次收到心跳的时间戳 /** * brief 初始化Windows Socket环境 * return 成功返回true失败返回false * note Windows Socket必须先初始化才能使用版本选择2.2兼容所有Windows系统 */ bool InitWinsock() { WSADATA wsaData; // 存储WSA初始化信息 // MAKEWORD(2,2)表示使用Socket 2.2版本 int ret WSAStartup(MAKEWORD(2, 2), wsaData); if (ret ! 0) { std::cerr [错误] WSAStartup初始化失败错误码 ret std::endl; return false; } std::cout [信息] WSAStartup初始化成功 std::endl; return true; } /** * brief UDP广播监听线程函数 * note 持续监听UDP广播端口收到手机的DISCOVER_PC请求后回复TCP服务端口 */ void UDPDiscoverThreadFunc() { // 1. 创建UDP套接字AF_INETIPv4SOCK_DGRAMUDPIPPROTO_UDPUDP协议 SOCKET udpSocket socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (udpSocket INVALID_SOCKET) { std::cerr [错误] 创建UDP套接字失败错误码 WSAGetLastError() std::endl; return; } // 2. 设置UDP套接字为广播模式允许接收广播包 BOOL bBroadcast TRUE; int optRet setsockopt(udpSocket, SOL_SOCKET, SO_BROADCAST, (char*)bBroadcast, sizeof(bBroadcast)); if (optRet SOCKET_ERROR) { std::cerr [错误] 设置UDP广播模式失败错误码 WSAGetLastError() std::endl; closesocket(udpSocket); // 失败则关闭套接字 return; } // 3. 绑定UDP端口监听所有网卡的UDP_DISCOVER_PORT端口 sockaddr_in udpServerAddr; // UDP服务端地址结构体 memset(udpServerAddr, 0, sizeof(udpServerAddr)); // 初始化内存 udpServerAddr.sin_family AF_INET; // IPv4协议 udpServerAddr.sin_addr.s_addr INADDR_ANY; // 监听所有网卡包括热点网卡 udpServerAddr.sin_port htons(UDP_DISCOVER_PORT); // 端口转换为网络字节序必须 if (bind(udpSocket, (sockaddr*)udpServerAddr, sizeof(udpServerAddr)) SOCKET_ERROR) { std::cerr [错误] UDP端口绑定失败错误码 WSAGetLastError() std::endl; closesocket(udpSocket); return; } std::cout [信息] UDP广播监听已启动端口 UDP_DISCOVER_PORT std::endl; // 4. 循环接收UDP广播包 char recvBuf[BUF_SIZE] {0}; // 接收缓冲区 sockaddr_in clientAddr; // 发送广播的客户端手机地址 int clientAddrLen sizeof(clientAddr); // 客户端地址长度 while (true) { // 无限循环监听直到程序退出 // 接收UDP包recvfrom用于UDP可获取发送方地址 int recvLen recvfrom( udpSocket, // 监听的UDP套接字 recvBuf, // 接收数据缓冲区 BUF_SIZE, // 缓冲区大小 0, // 标志位0默认 (sockaddr*)clientAddr, // 输出发送方地址 clientAddrLen // 输入输出地址长度 ); // 接收失败处理 if (recvLen 0) { std::cerr [错误] UDP接收数据失败错误码 WSAGetLastError() std::endl; memset(recvBuf, 0, BUF_SIZE); // 清空缓冲区 continue; // 继续监听下一个包 } // 解析接收的消息 std::string recvMsg(recvBuf, recvLen); std::cout [信息] 收到UDP广播来自 inet_ntoa(clientAddr.sin_addr) recvMsg std::endl; // 5. 识别手机的发现请求回复TCP端口 if (recvMsg DISCOVER_PC) { std::string tcpPortStr std::to_string(TCP_SERVICE_PORT); // 转换为字符串 // 发送回复sendto用于UDP指定发送到手机的地址 int sendLen sendto( udpSocket, tcpPortStr.c_str(), tcpPortStr.length(), 0, (sockaddr*)clientAddr, clientAddrLen ); if (sendLen SOCKET_ERROR) { std::cerr [错误] UDP回复TCP端口失败错误码 WSAGetLastError() std::endl; } else { std::cout [信息] 已回复手机TCP端口 TCP_SERVICE_PORT std::endl; } } memset(recvBuf, 0, BUF_SIZE); // 清空缓冲区准备下一次接收 } // 理论上不会执行到这里除非循环退出 closesocket(udpSocket); } /** * brief 心跳检测线程函数 * note 每隔1秒检查一次心跳超过HEARTBEAT_TIMEOUT未收到心跳则断开客户端 */ void HeartbeatCheckThreadFunc() { while (true) { // 仅当有客户端连接时才检查心跳 if (g_isClientConnected) { time_t currentTime time(NULL); // 获取当前时间戳 // 计算与最后一次心跳的时间差 double timeDiff difftime(currentTime, g_lastHeartbeatTime); if (timeDiff HEARTBEAT_TIMEOUT) { std::cerr [警告] 客户端心跳超时 HEARTBEAT_TIMEOUT 秒断开连接 std::endl; // 关闭客户端Socket closesocket(g_tcpClientSocket); g_tcpClientSocket INVALID_SOCKET; g_isClientConnected false; // 标记为未连接 } } std::this_thread::sleep_for(std::chrono::seconds(1)); // 每秒检查一次 } } /** * brief 处理单个TCP客户端连接手机 * param clientSocket 已连接的客户端Socket * note 负责接收手机消息、处理心跳、回复数据 */ void HandleTCPClientFunc(SOCKET clientSocket) { char recvBuf[BUF_SIZE] {0}; // 接收缓冲区 // 更新心跳时间连接成功即视为一次心跳 g_lastHeartbeatTime time(NULL); g_isClientConnected true; // 标记为已连接 // 获取客户端IP地址调试用 sockaddr_in clientAddr; int clientAddrLen sizeof(clientAddr); getpeername(clientSocket, (sockaddr*)clientAddr, clientAddrLen); std::cout [信息] 手机TCP连接成功IP inet_ntoa(clientAddr.sin_addr) std::endl; // 循环接收客户端消息 while (g_isClientConnected) { // 接收TCP数据recv用于TCP无发送方地址已建立连接 int recvLen recv(clientSocket, recvBuf, BUF_SIZE, 0); // 接收失败/客户端断开 if (recvLen 0) { std::cerr [错误] TCP接收数据失败/客户端断开错误码 WSAGetLastError() std::endl; closesocket(clientSocket); // 关闭Socket g_tcpClientSocket INVALID_SOCKET; // 重置全局Socket g_isClientConnected false; // 标记为未连接 break; // 退出循环 } // 解析接收的消息 std::string recvMsg(recvBuf, recvLen); // 处理心跳包手机发送的PING if (recvMsg PING) { g_lastHeartbeatTime time(NULL); // 更新心跳时间 // 回复PONG确认 send(clientSocket, PONG, 4, 0); std::cout [信息] 收到心跳包PING回复PONG std::endl; } else { // 处理业务消息非心跳 std::cout [信息] 收到手机消息 recvMsg std::endl; // 回复客户端示例拼接确认消息 std::string replyMsg PC已接收 recvMsg; send(clientSocket, replyMsg.c_str(), replyMsg.length(), 0); } memset(recvBuf, 0, BUF_SIZE); // 清空缓冲区 } } /** * brief 启动TCP服务端 * note 监听PC热点IP的TCP_SERVICE_PORT端口接收手机连接 */ void StartTCPServer() { // 1. 创建TCP套接字AF_INETIPv4SOCK_STREAMTCPIPPROTO_TCPTCP协议 SOCKET tcpListenSocket socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (tcpListenSocket INVALID_SOCKET) { std::cerr [错误] 创建TCP监听套接字失败错误码 WSAGetLastError() std::endl; return; } // 2. 绑定TCP端口到PC热点IP sockaddr_in tcpServerAddr; memset(tcpServerAddr, 0, sizeof(tcpServerAddr)); tcpServerAddr.sin_family AF_INET; // 转换热点IP为网络字节序必须 inet_pton(AF_INET, PC_HOTSPOT_IP, tcpServerAddr.sin_addr); tcpServerAddr.sin_port htons(TCP_SERVICE_PORT); // 端口转换为网络字节序 if (bind(tcpListenSocket, (sockaddr*)tcpServerAddr, sizeof(tcpServerAddr)) SOCKET_ERROR) { std::cerr [错误] TCP端口绑定失败错误码 WSAGetLastError() std::endl; closesocket(tcpListenSocket); return; } // 3. 开始监听SOMAXCONN系统最大连接数 if (listen(tcpListenSocket, SOMAXCONN) SOCKET_ERROR) { std::cerr [错误] TCP监听失败错误码 WSAGetLastError() std::endl; closesocket(tcpListenSocket); return; } std::cout [信息] TCP服务端已启动监听地址 PC_HOTSPOT_IP : TCP_SERVICE_PORT std::endl; // 4. 启动心跳检测线程分离线程后台运行 std::thread heartbeatThread(HeartbeatCheckThreadFunc); heartbeatThread.detach(); // 5. 循环接收客户端连接 while (true) { // accept阻塞等待客户端连接成功返回新的Socket用于与该客户端通信 SOCKET newClientSocket accept(tcpListenSocket, NULL, NULL); if (newClientSocket INVALID_SOCKET) { std::cerr [错误] 接受TCP连接失败错误码 WSAGetLastError() std::endl; continue; } // 如果已有客户端连接关闭旧连接单客户端模式可修改为多客户端 if (g_isClientConnected) { std::cerr [警告] 已有客户端连接断开旧连接 std::endl; closesocket(g_tcpClientSocket); } // 保存新客户端Socket并启动线程处理通信 g_tcpClientSocket newClientSocket; std::thread clientThread(HandleTCPClientFunc, newClientSocket); clientThread.detach(); // 分离线程避免主线程阻塞 } // 理论上不会执行到这里 closesocket(tcpListenSocket); } /** * brief 主函数程序入口 * return 0成功-1失败 * note 流程初始化Socket→启动UDP监听线程→启动TCP服务端 */ int main() { std::cout [信息] 程序启动等待手动开启PC热点... std::endl; std::cout [提示] 请先手动开启PC热点确认热点IP为 PC_HOTSPOT_IP std::endl; std::cout [提示] 按任意键继续... std::endl; system(pause); // 暂停等待用户手动开启热点 // 1. 初始化Windows Socket if (!InitWinsock()) { std::cerr [错误] Socket初始化失败程序退出 std::endl; system(pause); return -1; } // 2. 启动UDP广播监听线程后台运行 std::thread udpDiscoverThread(UDPDiscoverThreadFunc); udpDiscoverThread.detach(); // 3. 启动TCP服务端阻塞运行 StartTCPServer(); // 4. 清理Socket环境理论上不会执行到这里 WSACleanup(); std::cout [信息] 程序退出 std::endl; system(pause); return 0; }五、手机端实现Android/Kotlin1. 权限配置AndroidManifest.xmlxml!-- 核心网络权限允许应用访问网络 -- uses-permission android:nameandroid.permission.INTERNET / !-- 获取WiFi状态确认是否连接到PC热点 -- uses-permission android:nameandroid.permission.ACCESS_WIFI_STATE / !-- 获取网络状态判断网络是否可用 -- uses-permission android:nameandroid.permission.ACCESS_NETWORK_STATE / !-- 允许接收多播/广播包UDP广播必需 -- uses-permission android:nameandroid.permission.CHANGE_WIFI_MULTICAST_STATE /2. 核心代码带详细注释kotlinimport android.os.Handler import android.os.Looper import java.net.* import java.io.OutputStreamWriter import java.io.BufferedReader import java.io.InputStreamReader import java.util.concurrent.Executors /** * PC热点通信客户端 * 核心流程UDP广播发现PC → TCP建立连接 → 心跳保活 → 消息收发 → 断开自动重连 */ class PCHotspotClient { // 线程池用于处理网络操作避免阻塞UI线程 private val executor Executors.newSingleThreadExecutor() // 主线程Handler用于更新UIAndroid网络操作不能在主线程更新UI必须在主线程 private val mainHandler Handler(Looper.getMainLooper()) /************************ 配置参数与PC端保持一致 ************************/ // UDP广播端口需与PC端UDP_DISCOVER_PORT一致 private val UDP_DISCOVER_PORT 9999 // PC热点网关IP手动开热点后确认的IP如Windows默认192.168.137.1 private val PC_HOTSPOT_IP 192.168.137.1 // TCP默认端口UDP发现失败时兜底 private val DEFAULT_TCP_PORT 8888 // 心跳间隔秒 private val HEARTBEAT_INTERVAL 5 * 1000L /************************ 通信状态变量 ************************/ // TCP Socket与PC的连接 private var tcpSocket: Socket? null // 输出流向PC发送数据 private var outputWriter: OutputStreamWriter? null // 标记是否正在重连避免重复重连 private var isReconnecting false /** * 启动流程先UDP发现PC再建立TCP连接 */ fun start() { executor.execute { discoverPCByUDP() } } /** * 步骤1UDP广播发现PC * 逻辑发送DISCOVER_PC广播 → 接收PC回复的TCP端口 → 调用TCP连接函数 */ private fun discoverPCByUDP() { var tcpPort -1 // 存储PC回复的TCP端口 var udpSocket: DatagramSocket? null try { // 1. 创建UDP Socket并设置为广播模式 udpSocket DatagramSocket() udpSocket.broadcast true // 允许发送广播包 udpSocket.soTimeout 5000 // 设置超时5秒未收到回复则视为失败 // 2. 构造广播消息DISCOVER_PC与PC端识别的关键词一致 val discoverMsg DISCOVER_PC.toByteArray() // 广播地址255.255.255.255局域网内所有设备都能收到 val broadcastAddress InetAddress.getByName(255.255.255.255) // 构造UDP数据包消息广播地址端口 val sendPacket DatagramPacket( discoverMsg, discoverMsg.size, broadcastAddress, UDP_DISCOVER_PORT ) // 3. 发送广播包 udpSocket.send(sendPacket) log(UDP广播已发送DISCOVER_PC) // 4. 接收PC的回复TCP端口 val recvBuffer ByteArray(1024) val recvPacket DatagramPacket(recvBuffer, recvBuffer.size) udpSocket.receive(recvPacket) // 阻塞等待回复 // 解析回复的TCP端口 tcpPort String(recvPacket.data, 0, recvPacket.length).toInt() log(UDP发现成功PC的TCP端口$tcpPort) } catch (e: SocketTimeoutException) { // 超时异常使用默认端口 log(UDP发现超时使用默认TCP端口$DEFAULT_TCP_PORT) tcpPort DEFAULT_TCP_PORT } catch (e: Exception) { // 其他异常使用默认端口 log(UDP发现失败${e.message}使用默认TCP端口$DEFAULT_TCP_PORT) tcpPort DEFAULT_TCP_PORT } finally { // 关闭UDP Socket无论成功失败都要关闭 udpSocket?.close() } // 5. 调用TCP连接函数 if (tcpPort 0) { connectTCPServer(tcpPort) } } /** * 步骤2TCP连接PC服务端 * param tcpPort PC的TCP服务端口 * 逻辑尝试连接 → 成功则启动心跳和消息监听 → 失败则3秒后重连 */ private fun connectTCPServer(tcpPort: Int) { // 标记为正在重连避免重复调用 isReconnecting true while (isReconnecting) { try { // 1. 创建TCP Socket并连接PC tcpSocket Socket(PC_HOTSPOT_IP, tcpPort) // 2. 获取输出流用于发送数据 outputWriter OutputStreamWriter(tcpSocket!!.getOutputStream()) // 3. 连接成功更新状态日志 log(TCP连接成功$PC_HOTSPOT_IP:$tcpPort) isReconnecting false // 停止重连循环 // 4. 启动心跳保活和消息监听 startHeartbeat() listenTCPPacket() } catch (e: Exception) { // 连接失败日志3秒后重试 log(TCP连接失败${e.message}3秒后重试...) Thread.sleep(3000) // 休眠3秒 } } } /** * 步骤3心跳保活 * 逻辑每5秒发送一次PING → 失败则触发重连 */ private fun startHeartbeat() { executor.execute { while (tcpSocket?.isConnected true !isReconnecting) { try { // 发送心跳包PING与PC端识别的心跳关键词一致 outputWriter?.write(PING\n) outputWriter?.flush() // 强制刷新确保数据发送 log(发送心跳包PING) // 休眠5秒 Thread.sleep(HEARTBEAT_INTERVAL) } catch (e: Exception) { // 心跳发送失败断开连接触发重连 log(心跳发送失败${e.message}) break } } // 心跳循环退出触发重连 reconnect() } } /** * 步骤4监听PC发送的TCP消息 * 逻辑循环读取PC消息 → 心跳包PONG不处理 → 业务消息回调 */ private fun listenTCPPacket() { executor.execute { var reader: BufferedReader? null try { // 1. 获取输入流用于接收PC数据 reader BufferedReader(InputStreamReader(tcpSocket!!.getInputStream())) var recvLine: String? // 2. 循环读取消息阻塞直到收到数据/断开 while (tcpSocket?.isConnected true !isReconnecting reader.readLine().also { recvLine it } ! null) { val finalLine recvLine ?: continue // 主线程更新日志/UI mainHandler.post { // 区分心跳回复和业务消息 if (finalLine PONG) { log(收到心跳回复PONG) } else { log(收到PC消息$finalLine) // 此处可添加业务消息处理逻辑如更新UI、解析数据等 } } } } catch (e: Exception) { log(消息监听失败${e.message}) } finally { // 关闭输入流 reader?.close() // 触发重连 reconnect() } } } /** * 发送消息到PC * param msg 要发送的字符串消息 * 注意需在非UI线程执行避免阻塞 */ fun sendMsgToPC(msg: String) { executor.execute { try { // 发送消息末尾加换行符避免粘包 outputWriter?.write($msg\n) outputWriter?.flush() log(发送消息到PC$msg) } catch (e: Exception) { log(发送消息失败${e.message}) // 发送失败触发重连 reconnect() } } } /** * 断开连接重连 * 逻辑清理资源 → 重新执行UDP发现TCP连接 */ private fun reconnect() { // 避免重复重连 if (isReconnecting) return // 1. 清理资源 try { outputWriter?.close() tcpSocket?.close() log(已清理TCP连接资源) } catch (e: Exception) { log(清理资源失败${e.message}) } // 2. 重新启动发现流程 log(开始重新连接PC...) discoverPCByUDP() } /** * 停止所有通信 * 调用场景APP退出、页面销毁 */ fun stop() { // 标记为停止重连 isReconnecting false // 清理资源 executor.execute { try { outputWriter?.close() tcpSocket?.close() log(已停止所有通信) } catch (e: Exception) { log(停止通信失败${e.message}) } } } /** * 日志输出主线程 * param msg 日志内容 */ private fun log(msg: String) { mainHandler.post { println([PCHotspotClient] $msg) // 此处可替换为APP的日志框架如Logcat // Log.d(PCHotspotClient, msg) } } }3. Activity 中调用示例带注释kotlinimport androidx.appcompat.app.AppCompatActivity import android.os.Bundle import android.widget.Button import android.widget.EditText class MainActivity : AppCompatActivity() { // 声明PC热点客户端 private lateinit var pcClient: PCHotspotClient override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // 1. 初始化客户端 pcClient PCHotspotClient() // 2. 启动通信流程UDP发现→TCP连接 pcClient.start() // 3. 发送消息按钮点击事件 val btnSend: Button findViewById(R.id.btn_send) val etMsg: EditText findViewById(R.id.et_msg) btnSend.setOnClickListener { val msg etMsg.text.toString().trim() if (msg.isNotEmpty()) { pcClient.sendMsgToPC(msg) etMsg.setText() // 清空输入框 } } } /** * 页面销毁时停止通信避免内存泄漏 */ override fun onDestroy() { super.onDestroy() pcClient.stop() } }六、部署与测试步骤1. PC 端操作手动开启热点Windows 系统 → 设置 → 网络和 Internet → 移动热点 → 开启记录热点 IP默认192.168.137.1编译运行代码打开 Visual Studio创建项目修改PC_HOTSPOT_IP为实际热点 IP项目属性→链接器→输入→附加依赖项添加ws2_32.lib以管理员身份运行程序避免端口绑定失败确认启动成功控制台输出 “UDP 广播监听已启动”“TCP 服务端已启动”。2. 手机端操作连接 PC 热点手机 WiFi 连接手动开启的 PC 热点输入热点密码编译安装 APKAndroid Studio 编译代码安装到手机测试通信打开 APP自动触发 UDP 发现→TCP 连接输入消息点击发送PC 控制台可看到消息断开 WiFi 重新连接APP 自动重连验证稳定性。七、常见问题与解决方案问题现象可能原因解决方案PC 端 UDP 绑定失败端口被占用 / 无管理员权限1. 更换 UDP 端口2. 以管理员身份运行程序手机 UDP 发现失败PC 防火墙拦截 / 未连热点1. Windows 防火墙放行9999/UDP和8888/TCP2. 确认手机已连接 PC 热点TCP 连接超时PC 热点 IP 配置错误1.cmd执行ipconfig查看热点 IP2. 修改代码中PC_HOTSPOT_IP为实际 IP心跳超时频繁网络波动 / 间隔过短1. 调整HEARTBEAT_TIMEOUT为 20 秒2. 靠近 PC 减少信号干扰手机端发送消息失败TCP 连接已断开代码已内置自动重连等待 3 秒后重试八、核心优化点可选多客户端支持PC 端将单客户端改为多客户端用数组 / 链表存储 SocketIOCP 模型优化数据粘包处理消息末尾加换行符本文已实现或添加消息头长度 类型加密通信TCP 消息添加 AES 加密防止局域网内数据被监听热点 IP 自动识别PC 端添加代码自动获取热点 IP替代手动配置UI 交互优化手机端添加连接状态、消息列表展示提升用户体验。九、总结本文聚焦 “手动开启 PC 热点” 场景通过 UDP 广播实现设备自动发现TCP 实现可靠通信代码全程添加详细注释兼顾可读性和实用性。核心优势无需手动配置 IP手机连接热点即自动发现 PC心跳保活 自动重连保障通信稳定性代码解耦仅负责通信逻辑热点由用户手动管理降低权限依赖。该方案可直接应用于本地数据交互、工业控制、移动调试等场景也可基于此扩展外网通信如 FRP 内网穿透。