【实战】C/C++ 实现 PC 热点(手动开启)+ 手机 UDP 自动发现 + TCP 通信全流程(超详细)

【实战】C/C++ 实现 PC 热点(手动开启)+ 手机 UDP 自动发现 + TCP 通信全流程

摘要

在物联网和移动应用开发中,本地设备间的无线通信是一个常见需求。本文详细介绍了一种基于PC热点的手动开启方案,结合UDP广播自动发现和TCP可靠通信的技术实现。通过解耦热点创建和通信逻辑,我们降低了代码复杂度和权限依赖,实现了手机连接PC热点后无需手动配置IP即可自动建立稳定通信的完整解决方案。文章包含详细的原理分析、完整的C/C++和Android/Kotlin代码实现,以及实际的部署测试步骤。

一、场景背景

1.1 应用场景

在多种实际场景中,我们需要实现PC与手机之间的本地数据交互:

  1. 文件传输:快速将手机照片、视频传输到PC,或从PC下载文件到手机
  2. 远程控制:手机作为遥控器控制PC上的媒体播放、PPT演示等
  3. 数据同步:游戏存档、笔记、联系人等数据的双向同步
  4. 调试工具:移动开发者通过手机远程调试PC上的服务
  5. 物联网控制:手机通过PC网关控制其他物联网设备

1.2 传统方案的局限性

传统的PC-手机通信方案通常存在以下问题:

  1. IP配置复杂:需要手动查看和输入IP地址,用户体验差
  2. 网络环境依赖:需要路由器或稳定的WiFi环境
  3. 权限限制:自动创建热点通常需要管理员权限
  4. 跨平台兼容性:不同操作系统热点API差异大

1.3 本文方案的优势

本文提出的方案具有以下特点:

  1. 免配置发现:手机连接热点后自动发现PC,无需手动输入IP
  2. 环境独立:只需PC和手机,无需路由器等额外设备
  3. 权限友好:热点由用户手动开启,程序无需特殊权限
  4. 跨平台:核心通信逻辑与操作系统解耦
  5. 稳定可靠:UDP发现+TCP通信+心跳保活三重保障

二、核心原理

2.1 系统架构设计

复制代码
┌─────────────────┐    UDP广播发现    ┌─────────────────┐
│     手机端      │◄─────────────────►│      PC端       │
│                 │    TCP通信连接    │                 │
│  Android/iOS    │◄─────────────────►│ Windows/macOS   │
└─────────────────┘                   └─────────────────┘
        │                                      │
        │ 连接PC热点                           │ 手动开启热点
        ▼                                      ▼
┌─────────────────┐                   ┌─────────────────┐
│  手机无线网卡    │                   │  PC无线网卡     │
└─────────────────┘                   └─────────────────┘

2.2 UDP广播发现机制

2.2.1 广播原理

UDP广播允许设备向同一局域网内的所有设备发送数据包,而不需要知道具体的目标IP地址。广播地址255.255.255.255表示局域网内的所有设备。

工作流程

  1. 手机连接PC热点后,获得一个私有IP地址(如192.168.137.100)
  2. 手机向广播地址255.255.255.255:9999发送DISCOVER_PC消息
  3. PC监听UDP端口9999,收到广播后获取手机的IP地址
  4. PC回复TCP服务端口号(8888)到手机的具体IP地址
  5. 手机收到回复后,使用该端口建立TCP连接
2.2.2 广播包格式设计
cpp 复制代码
// 发现请求包
struct DiscoverRequest {
    char magic[4];      // 魔术字:"DISC"
    uint16_t version;   // 协议版本:1
    char device_type;   // 设备类型:'P'=手机, 'C'=PC
    // 可扩展:设备ID、能力字段等
};

// 发现响应包  
struct DiscoverResponse {
    char magic[4];      // 魔术字:"RESP"
    uint16_t tcp_port;  // TCP服务端口
    uint32_t ip_addr;   // PC的IP地址(网络字节序)
    // 可扩展:服务类型、加密信息等
};

2.3 TCP通信机制

2.3.1 连接建立与维护

TCP提供可靠的、面向连接的通信服务。在我们的方案中:

  1. 三次握手:手机主动发起TCP连接,PC接受连接
  2. 流量控制:通过滑动窗口机制避免接收方缓冲区溢出
  3. 拥塞控制:TCP内置的拥塞避免算法保证网络稳定
2.3.2 心跳保活机制

为防止连接假死,我们实现了应用层心跳机制:

cpp 复制代码
// 心跳协议设计
手机端:每隔5秒发送"PING" → PC端:收到"PING"立即回复"PONG"
超时机制:PC端15秒未收到心跳则断开连接

2.4 网络地址转换(NAT)考虑

由于PC作为热点网关,通常具有NAT功能。在我们的方案中:

  1. PC端:使用热点网关IP(如192.168.137.1)
  2. 手机端:获得私有IP(如192.168.137.x)
  3. 通信路径:手机 ↔ PC(网关) ↔ PC应用

三、环境准备

3.1 硬件环境配置

3.1.1 PC端要求
项目 最低要求 推荐配置
操作系统 Windows 8.1 / macOS 10.13 / Ubuntu 18.04 Windows 10 / macOS 11 / Ubuntu 20.04
无线网卡 支持AP模式的802.11n网卡 支持802.11ac的5GHz网卡
处理器 双核1.6GHz 四核2.0GHz或更高
内存 4GB 8GB或更高
3.1.2 手机端要求
项目 最低要求 推荐配置
操作系统 Android 7.0 / iOS 11 Android 10 / iOS 14
Wi-Fi 支持802.11n 支持802.11ac
存储空间 50MB可用空间 100MB或更多

3.2 开发环境搭建

3.2.1 PC端开发环境

Windows平台(本文主要示例)

  1. 安装Visual Studio 2019或更高版本
  2. 安装C++桌面开发工作负载
  3. 配置Windows SDK(版本10.0.17763.0或更高)

macOS平台

bash 复制代码
# 安装Xcode和命令行工具
xcode-select --install

# 安装Homebrew(如果未安装)
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

# 安装编译工具链
brew install cmake pkg-config

Linux平台(Ubuntu)

bash 复制代码
# 安装编译工具和库
sudo apt-get update
sudo apt-get install build-essential cmake pkg-config
sudo apt-get install libssl-dev zlib1g-dev
3.2.2 手机端开发环境

Android开发环境

  1. 安装Android Studio 4.0或更高版本
  2. 配置JDK 11或更高版本
  3. 安装Android SDK Platform 30或更高
  4. 安装Android NDK(用于JNI开发,可选)

iOS开发环境

  1. 安装Xcode 12或更高版本
  2. 配置Swift或Objective-C开发环境

3.3 依赖库配置

3.3.1 PC端依赖

Windows Socket 2.0

  • 系统自带,通过#pragma comment(lib, "ws2_32.lib")链接
  • 支持IPv4和IPv6(本文使用IPv4简化实现)

可选增强库

cpp 复制代码
// OpenSSL - 加密通信
#pragma comment(lib, "libssl.lib")
#pragma comment(lib, "libcrypto.lib")

// Google Protocol Buffers - 高效序列化
#pragma comment(lib, "libprotobuf.lib")

// Boost.Asio - 异步网络编程
#pragma comment(lib, "boost_system.lib")
#pragma comment(lib, "boost_thread.lib")
3.3.2 Android端依赖

Gradle配置

gradle 复制代码
dependencies {
    implementation 'androidx.core:core-ktx:1.6.0'
    implementation 'androidx.appcompat:appcompat:1.3.1'
    implementation 'com.google.android.material:material:1.4.0'
    
    // 网络请求库(可选)
    implementation 'com.squareup.okhttp3:okhttp:4.9.1'
    
    // 协程支持
    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.1'
    
    // 序列化库(可选)
    implementation 'com.google.code.gson:gson:2.8.8'
}

四、PC端实现(C/C++)

4.1 项目结构设计

复制代码
PC_Server_Project/
├── src/
│   ├── main.cpp              # 程序入口
│   ├── network/
│   │   ├── udp_discover.cpp  # UDP发现服务
│   │   ├── tcp_server.cpp    # TCP服务器
│   │   └── heartbeat.cpp     # 心跳检测
│   ├── utils/
│   │   ├── logger.cpp        # 日志系统
│   │   └── config.cpp        # 配置管理
│   └── protocol/
│       ├── message.cpp       # 消息协议
│       └── parser.cpp        # 协议解析
├── include/                  # 头文件
├── third_party/             # 第三方库
└── CMakeLists.txt           # 构建配置

4.2 详细代码实现与解析

4.2.1 主程序入口
cpp 复制代码
// main.cpp - 程序主入口和整体控制流程
#include <iostream>
#include <thread>
#include <atomic>
#include <csignal>
#include "network/udp_discover.h"
#include "network/tcp_server.h"
#include "utils/logger.h"
#include "utils/config.h"

// 全局信号标志,用于优雅退出
std::atomic<bool> g_running{true};

// 信号处理函数
void signal_handler(int signal) {
    Logger::getInstance().log(LogLevel::INFO, "收到退出信号,正在关闭服务...");
    g_running = false;
}

int main(int argc, char* argv[]) {
    // 初始化日志系统
    Logger::getInstance().init("pc_server.log", LogLevel::DEBUG);
    
    // 注册信号处理器
    std::signal(SIGINT, signal_handler);   // Ctrl+C
    std::signal(SIGTERM, signal_handler);  // 终止信号
    
    Logger::getInstance().log(LogLevel::INFO, 
        "========================================");
    Logger::getInstance().log(LogLevel::INFO, 
        "PC热点通信服务器 v1.0 启动");
    Logger::getInstance().log(LogLevel::INFO, 
        "========================================");
    
    // 1. 加载配置文件
    ConfigManager& config = ConfigManager::getInstance();
    if (!config.load("config.ini")) {
        Logger::getInstance().log(LogLevel::ERROR, 
            "配置文件加载失败,使用默认配置");
        config.setDefault();
    }
    
    // 2. 显示配置信息
    std::cout << "\n当前配置信息:" << std::endl;
    std::cout << "热点IP: " << config.getHotspotIP() << std::endl;
    std::cout << "UDP发现端口: " << config.getUDPDiscoverPort() << std::endl;
    std::cout << "TCP服务端口: " << config.getTCPServicePort() << std::endl;
    std::cout << "心跳超时: " << config.getHeartbeatTimeout() << "秒" << std::endl;
    std::cout << "最大客户端数: " << config.getMaxClients() << std::endl;
    
    // 3. 等待用户开启热点
    std::cout << "\n请按以下步骤操作:" << std::endl;
    std::cout << "1. 手动开启PC热点(设置->网络和Internet->移动热点)" << std::endl;
    std::cout << "2. 确认热点IP是否为: " << config.getHotspotIP() << std::endl;
    std::cout << "3. 按Enter键继续..." << std::endl;
    std::cin.get();
    
    // 4. 初始化Windows Socket
    if (!NetworkManager::init()) {
        Logger::getInstance().log(LogLevel::ERROR, "网络初始化失败");
        return -1;
    }
    
    // 5. 启动UDP发现服务
    UDPDiscoverServer udpServer;
    if (!udpServer.start(config.getUDPDiscoverPort())) {
        Logger::getInstance().log(LogLevel::ERROR, "UDP服务启动失败");
        NetworkManager::cleanup();
        return -1;
    }
    
    // 6. 启动TCP服务器
    TCPServer tcpServer;
    if (!tcpServer.start(config.getHotspotIP(), config.getTCPServicePort())) {
        Logger::getInstance().log(LogLevel::ERROR, "TCP服务启动失败");
        udpServer.stop();
        NetworkManager::cleanup();
        return -1;
    }
    
    // 7. 启动心跳检测服务
    HeartbeatManager heartbeatManager;
    heartbeatManager.start(config.getHeartbeatTimeout());
    
    Logger::getInstance().log(LogLevel::INFO, 
        "所有服务已启动,等待手机连接...");
    Logger::getInstance().log(LogLevel::INFO, 
        "按Ctrl+C退出程序");
    
    // 8. 主循环(等待退出信号)
    while (g_running) {
        std::this_thread::sleep_for(std::chrono::seconds(1));
        
        // 显示当前连接状态
        static int counter = 0;
        if (++counter % 10 == 0) {  // 每10秒显示一次状态
            tcpServer.printStatus();
        }
    }
    
    // 9. 优雅关闭所有服务
    Logger::getInstance().log(LogLevel::INFO, "正在关闭服务...");
    heartbeatManager.stop();
    tcpServer.stop();
    udpServer.stop();
    NetworkManager::cleanup();
    
    Logger::getInstance().log(LogLevel::INFO, "服务器已安全退出");
    return 0;
}
4.2.2 UDP发现服务详细实现
cpp 复制代码
// udp_discover.cpp - UDP广播发现服务完整实现
#include "udp_discover.h"
#include <iostream>
#include <thread>
#include <chrono>
#include <cstring>
#include <vector>
#include <algorithm>

// UDP发现服务器类实现
class UDPDiscoverServer::Impl {
public:
    Impl() : m_udpSocket(INVALID_SOCKET), m_running(false) {}
    
    bool start(uint16_t port) {
        // 1. 创建UDP套接字
        m_udpSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
        if (m_udpSocket == INVALID_SOCKET) {
            Logger::getInstance().log(LogLevel::ERROR, 
                "创建UDP套接字失败: " + std::to_string(WSAGetLastError()));
            return false;
        }
        
        // 2. 设置SO_REUSEADDR选项(允许快速重启)
        int reuse = 1;
        if (setsockopt(m_udpSocket, SOL_SOCKET, SO_REUSEADDR, 
                      (char*)&reuse, sizeof(reuse)) == SOCKET_ERROR) {
            Logger::getInstance().log(LogLevel::WARNING, 
                "设置SO_REUSEADDR失败,但不影响功能");
        }
        
        // 3. 设置广播权限
        int broadcast = 1;
        if (setsockopt(m_udpSocket, SOL_SOCKET, SO_BROADCAST,
                      (char*)&broadcast, sizeof(broadcast)) == SOCKET_ERROR) {
            Logger::getInstance().log(LogLevel::ERROR,
                "设置广播权限失败: " + std::to_string(WSAGetLastError()));
            closesocket(m_udpSocket);
            return false;
        }
        
        // 4. 设置非阻塞模式(可选)
        u_long mode = 1; // 1=非阻塞,0=阻塞
        if (ioctlsocket(m_udpSocket, FIONBIO, &mode) == SOCKET_ERROR) {
            Logger::getInstance().log(LogLevel::WARNING,
                "设置非阻塞模式失败,使用阻塞模式");
        }
        
        // 5. 绑定到指定端口
        sockaddr_in serverAddr;
        memset(&serverAddr, 0, sizeof(serverAddr));
        serverAddr.sin_family = AF_INET;
        serverAddr.sin_addr.s_addr = INADDR_ANY; // 监听所有网络接口
        serverAddr.sin_port = htons(port);
        
        if (bind(m_udpSocket, (sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {
            Logger::getInstance().log(LogLevel::ERROR,
                "绑定UDP端口失败: " + std::to_string(WSAGetLastError()));
            closesocket(m_udpSocket);
            return false;
        }
        
        // 6. 获取本地IP地址(用于日志)
        char hostname[256];
        gethostname(hostname, sizeof(hostname));
        
        struct hostent* host = gethostbyname(hostname);
        if (host) {
            for (int i = 0; host->h_addr_list[i]; i++) {
                struct in_addr addr;
                memcpy(&addr, host->h_addr_list[i], sizeof(struct in_addr));
                Logger::getInstance().log(LogLevel::INFO,
                    "服务器IP地址: " + std::string(inet_ntoa(addr)));
            }
        }
        
        // 7. 启动接收线程
        m_running = true;
        m_receiveThread = std::thread(&UDPDiscoverServer::Impl::receiveLoop, this);
        m_cleanupThread = std::thread(&UDPDiscoverServer::Impl::cleanupLoop, this);
        
        Logger::getInstance().log(LogLevel::INFO,
            "UDP发现服务已启动,监听端口: " + std::to_string(port));
        
        return true;
    }
    
    void stop() {
        m_running = false;
        
        // 等待线程结束
        if (m_receiveThread.joinable()) {
            m_receiveThread.join();
        }
        if (m_cleanupThread.joinable()) {
            m_cleanupThread.join();
        }
        
        // 关闭套接字
        if (m_udpSocket != INVALID_SOCKET) {
            closesocket(m_udpSocket);
            m_udpSocket = INVALID_SOCKET;
        }
        
        Logger::getInstance().log(LogLevel::INFO, "UDP发现服务已停止");
    }
    
private:
    // 客户端发现记录结构
    struct ClientRecord {
        std::string ip;
        std::chrono::steady_clock::time_point lastSeen;
        uint16_t tcpPort;
        bool responded;
    };
    
    void receiveLoop() {
        const int BUFFER_SIZE = 1024;
        char buffer[BUFFER_SIZE];
        sockaddr_in clientAddr;
        int clientAddrLen = sizeof(clientAddr);
        
        while (m_running) {
            // 接收UDP数据包
            memset(buffer, 0, BUFFER_SIZE);
            int recvLen = recvfrom(m_udpSocket, buffer, BUFFER_SIZE, 0,
                                 (sockaddr*)&clientAddr, &clientAddrLen);
            
            if (recvLen <= 0) {
                // 非阻塞模式下,没有数据时继续循环
                if (WSAGetLastError() == WSAEWOULDBLOCK) {
                    std::this_thread::sleep_for(std::chrono::milliseconds(10));
                    continue;
                }
                Logger::getInstance().log(LogLevel::ERROR,
                    "接收UDP数据失败: " + std::to_string(WSAGetLastError()));
                continue;
            }
            
            // 处理接收到的数据
            processPacket(buffer, recvLen, clientAddr);
        }
    }
    
    void processPacket(const char* data, int length, const sockaddr_in& clientAddr) {
        std::string clientIP = inet_ntoa(clientAddr.sin_addr);
        std::string message(data, length);
        
        Logger::getInstance().log(LogLevel::DEBUG,
            "收到UDP包[来自" + clientIP + "]: " + message);
        
        // 加锁保护客户端记录
        std::lock_guard<std::mutex> lock(m_clientsMutex);
        
        // 查找或创建客户端记录
        auto it = std::find_if(m_clients.begin(), m_clients.end(),
            [&clientIP](const ClientRecord& record) {
                return record.ip == clientIP;
            });
        
        if (it == m_clients.end()) {
            // 新客户端
            ClientRecord newClient;
            newClient.ip = clientIP;
            newClient.lastSeen = std::chrono::steady_clock::now();
            newClient.responded = false;
            m_clients.push_back(newClient);
            it = m_clients.end() - 1;
            
            Logger::getInstance().log(LogLevel::INFO,
                "新客户端发现: " + clientIP);
        } else {
            // 更新现有客户端时间戳
            it->lastSeen = std::chrono::steady_clock::now();
        }
        
        // 处理不同类型的消息
        if (message == "DISCOVER_PC") {
            handleDiscoverRequest(clientAddr, *it);
        } else if (message.find("HELLO") == 0) {
            handleHelloMessage(message, clientAddr, *it);
        } else {
            Logger::getInstance().log(LogLevel::WARNING,
                "未知UDP消息格式: " + message);
        }
    }
    
    void handleDiscoverRequest(const sockaddr_in& clientAddr, ClientRecord& client) {
        // 获取TCP服务器端口(从配置中)
        uint16_t tcpPort = ConfigManager::getInstance().getTCPServicePort();
        
        // 构造响应消息
        std::string response = std::to_string(tcpPort);
        
        // 发送响应
        int sent = sendto(m_udpSocket, response.c_str(), response.length(), 0,
                         (const sockaddr*)&clientAddr, sizeof(clientAddr));
        
        if (sent == SOCKET_ERROR) {
            Logger::getInstance().log(LogLevel::ERROR,
                "发送UDP响应失败: " + std::to_string(WSAGetLastError()));
        } else {
            client.responded = true;
            client.tcpPort = tcpPort;
            
            Logger::getInstance().log(LogLevel::INFO,
                "已回复客户端 " + client.ip + " TCP端口: " + std::to_string(tcpPort));
        }
    }
    
    void handleHelloMessage(const std::string& message, 
                           const sockaddr_in& clientAddr,
                           ClientRecord& client) {
        // 解析HELLO消息,格式: "HELLO|设备名称|设备类型|版本"
        std::vector<std::string> parts;
        size_t start = 0, end = 0;
        
        while ((end = message.find('|', start)) != std::string::npos) {
            parts.push_back(message.substr(start, end - start));
            start = end + 1;
        }
        parts.push_back(message.substr(start));
        
        if (parts.size() >= 4) {
            Logger::getInstance().log(LogLevel::INFO,
                "设备信息 - IP: " + client.ip +
                ", 名称: " + parts[1] +
                ", 类型: " + parts[2] +
                ", 版本: " + parts[3]);
        }
        
        // 发送确认响应
        std::string ack = "ACK_HELLO|" + parts[1];
        sendto(m_udpSocket, ack.c_str(), ack.length(), 0,
              (const sockaddr*)&clientAddr, sizeof(clientAddr));
    }
    
    void cleanupLoop() {
        while (m_running) {
            std::this_thread::sleep_for(std::chrono::seconds(30));
            
            // 清理超时的客户端记录
            std::lock_guard<std::mutex> lock(m_clientsMutex);
            auto now = std::chrono::steady_clock::now();
            
            auto it = m_clients.begin();
            while (it != m_clients.end()) {
                auto duration = std::chrono::duration_cast<std::chrono::seconds>(
                    now - it->lastSeen);
                
                if (duration.count() > 300) { // 5分钟超时
                    Logger::getInstance().log(LogLevel::INFO,
                        "清理超时客户端: " + it->ip);
                    it = m_clients.erase(it);
                } else {
                    ++it;
                }
            }
        }
    }
    
    SOCKET m_udpSocket;
    std::atomic<bool> m_running;
    std::thread m_receiveThread;
    std::thread m_cleanupThread;
    std::vector<ClientRecord> m_clients;
    std::mutex m_clientsMutex;
};

// UDPDiscoverServer公共接口实现
UDPDiscoverServer::UDPDiscoverServer() : m_impl(new Impl()) {}
UDPDiscoverServer::~UDPDiscoverServer() { delete m_impl; }

bool UDPDiscoverServer::start(uint16_t port) {
    return m_impl->start(port);
}

void UDPDiscoverServer::stop() {
    m_impl->stop();
}
4.2.3 TCP服务器详细实现
cpp 复制代码
// tcp_server.cpp - TCP服务器完整实现
#include "tcp_server.h"
#include <iostream>
#include <thread>
#include <vector>
#include <memory>
#include <queue>
#include <condition_variable>
#include <atomic>

// 线程安全的队列模板
template<typename T>
class ThreadSafeQueue {
public:
    void push(const T& value) {
        std::lock_guard<std::mutex> lock(m_mutex);
        m_queue.push(value);
        m_cond.notify_one();
    }
    
    bool try_pop(T& value) {
        std::lock_guard<std::mutex> lock(m_mutex);
        if (m_queue.empty()) return false;
        
        value = std::move(m_queue.front());
        m_queue.pop();
        return true;
    }
    
    bool empty() const {
        std::lock_guard<std::mutex> lock(m_mutex);
        return m_queue.empty();
    }
    
    size_t size() const {
        std::lock_guard<std::mutex> lock(m_mutex);
        return m_queue.size();
    }
    
    void wait_and_pop(T& value) {
        std::unique_lock<std::mutex> lock(m_mutex);
        m_cond.wait(lock, [this] { return !m_queue.empty(); });
        value = std::move(m_queue.front());
        m_queue.pop();
    }
    
private:
    mutable std::mutex m_mutex;
    std::queue<T> m_queue;
    std::condition_variable m_cond;
};

// TCP客户端会话类
class TCPClientSession {
public:
    TCPClientSession(SOCKET socket, const std::string& clientIP, uint16_t clientPort)
        : m_socket(socket), m_clientIP(clientIP), m_clientPort(clientPort),
          m_running(false), m_lastActivity(std::chrono::steady_clock::now()) {
        
        // 设置Socket选项
        int timeout = 5000; // 5秒超时
        setsockopt(m_socket, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout));
        setsockopt(m_socket, SOL_SOCKET, SO_SNDTIMEO, (char*)&timeout, sizeof(timeout));
    }
    
    ~TCPClientSession() {
        stop();
    }
    
    void start() {
        m_running = true;
        m_receiveThread = std::thread(&TCPClientSession::receiveLoop, this);
        m_sendThread = std::thread(&TCPClientSession::sendLoop, this);
        
        Logger::getInstance().log(LogLevel::INFO,
            "客户端会话启动: " + m_clientIP + ":" + std::to_string(m_clientPort));
    }
    
    void stop() {
        m_running = false;
        
        // 关闭Socket以唤醒阻塞的线程
        if (m_socket != INVALID_SOCKET) {
            shutdown(m_socket, SD_BOTH);
            closesocket(m_socket);
            m_socket = INVALID_SOCKET;
        }
        
        // 等待线程结束
        if (m_receiveThread.joinable()) m_receiveThread.join();
        if (m_sendThread.joinable()) m_sendThread.join();
        
        Logger::getInstance().log(LogLevel::INFO,
            "客户端会话结束: " + m_clientIP);
    }
    
    void sendMessage(const std::string& message) {
        m_sendQueue.push(message);
    }
    
    std::string getClientInfo() const {
        return m_clientIP + ":" + std::to_string(m_clientPort);
    }
    
    std::chrono::steady_clock::time_point getLastActivity() const {
        return m_lastActivity;
    }
    
    bool isConnected() const {
        return m_running && m_socket != INVALID_SOCKET;
    }
    
private:
    void receiveLoop() {
        const int BUFFER_SIZE = 4096;
        char buffer[BUFFER_SIZE];
        
        while (m_running && m_socket != INVALID_SOCKET) {
            memset(buffer, 0, BUFFER_SIZE);
            
            // 接收数据
            int recvLen = recv(m_socket, buffer, BUFFER_SIZE - 1, 0);
            
            if (recvLen > 0) {
                // 成功收到数据
                buffer[recvLen] = '\0';
                m_lastActivity = std::chrono::steady_clock::now();
                
                // 处理接收到的消息
                processReceivedData(buffer, recvLen);
                
            } else if (recvLen == 0) {
                // 连接关闭
                Logger::getInstance().log(LogLevel::INFO,
                    "客户端主动关闭连接: " + m_clientIP);
                break;
            } else {
                // 接收错误
                int error = WSAGetLastError();
                if (error != WSAETIMEDOUT && error != WSAEWOULDBLOCK) {
                    Logger::getInstance().log(LogLevel::ERROR,
                        "接收数据错误: " + std::to_string(error));
                    break;
                }
            }
        }
        
        m_running = false;
    }
    
    void processReceivedData(const char* data, int length) {
        std::string message(data, length);
        
        // 心跳包处理
        if (message == "PING") {
            m_sendQueue.push("PONG");
            Logger::getInstance().log(LogLevel::DEBUG,
                "收到心跳包,回复PONG");
            return;
        }
        
        // JSON消息格式检查
        if (message.find("{") == 0 && message.find("}") != std::string::npos) {
            processJsonMessage(message);
        } else {
            // 普通文本消息
            Logger::getInstance().log(LogLevel::INFO,
                "收到消息[" + m_clientIP + "]: " + message);
            
            // 回显消息(示例)
            std::string echo = "ECHO: " + message;
            m_sendQueue.push(echo);
        }
    }
    
    void processJsonMessage(const std::string& json) {
        try {
            // 这里可以集成JSON解析库,如nlohmann/json
            // 示例:解析消息类型
            if (json.find("\"type\":\"file_info\"") != std::string::npos) {
                // 处理文件信息
                Logger::getInstance().log(LogLevel::INFO,
                    "收到文件信息: " + json);
                
                // 确认接收
                std::string ack = "{\"status\":\"ok\",\"message\":\"file_info_received\"}";
                m_sendQueue.push(ack);
            } else if (json.find("\"type\":\"command\"") != std::string::npos) {
                // 处理命令
                Logger::getInstance().log(LogLevel::INFO,
                    "收到命令: " + json);
                
                // 执行命令并回复结果
                std::string result = "{\"status\":\"ok\",\"result\":\"command_executed\"}";
                m_sendQueue.push(result);
            }
        } catch (...) {
            Logger::getInstance().log(LogLevel::ERROR,
                "JSON消息解析失败: " + json);
        }
    }
    
    void sendLoop() {
        while (m_running && m_socket != INVALID_SOCKET) {
            std::string message;
            m_sendQueue.wait_and_pop(message);
            
            if (!m_running) break;
            
            // 发送消息
            int sent = 0;
            int total = message.length();
            const char* buffer = message.c_str();
            
            while (sent < total && m_running) {
                int ret = send(m_socket, buffer + sent, total - sent, 0);
                if (ret <= 0) {
                    int error = WSAGetLastError();
                    if (error != WSAETIMEDOUT) {
                        Logger::getInstance().log(LogLevel::ERROR,
                            "发送数据失败: " + std::to_string(error));
                        m_running = false;
                        break;
                    }
                } else {
                    sent += ret;
                }
            }
            
            if (sent == total) {
                Logger::getInstance().log(LogLevel::DEBUG,
                    "发送消息成功: " + std::to_string(sent) + " bytes");
            }
        }
    }
    
    SOCKET m_socket;
    std::string m_clientIP;
    uint16_t m_clientPort;
    std::atomic<bool> m_running;
    std::chrono::steady_clock::time_point m_lastActivity;
    
    std::thread m_receiveThread;
    std::thread m_sendThread;
    ThreadSafeQueue<std::string> m_sendQueue;
};

// TCP服务器实现类
class TCPServer::Impl {
public:
    Impl() : m_listenSocket(INVALID_SOCKET), m_running(false) {}
    
    bool start(const std::string& ip, uint16_t port) {
        // 1. 创建监听Socket
        m_listenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
        if (m_listenSocket == INVALID_SOCKET) {
            Logger::getInstance().log(LogLevel::ERROR,
                "创建TCP Socket失败: " + std::to_string(WSAGetLastError()));
            return false;
        }
        
        // 2. 设置Socket选项
        int reuse = 1;
        setsockopt(m_listenSocket, SOL_SOCKET, SO_REUSEADDR, 
                  (char*)&reuse, sizeof(reuse));
        
        // 3. 绑定地址和端口
        sockaddr_in serverAddr;
        memset(&serverAddr, 0, sizeof(serverAddr));
        serverAddr.sin_family = AF_INET;
        inet_pton(AF_INET, ip.c_str(), &serverAddr.sin_addr);
        serverAddr.sin_port = htons(port);
        
        if (bind(m_listenSocket, (sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {
            Logger::getInstance().log(LogLevel::ERROR,
                "绑定TCP地址失败: " + std::to_string(WSAGetLastError()));
            closesocket(m_listenSocket);
            return false;
        }
        
        // 4. 开始监听
        if (listen(m_listenSocket, SOMAXCONN) == SOCKET_ERROR) {
            Logger::getInstance().log(LogLevel::ERROR,
                "监听TCP端口失败: " + std::to_string(WSAGetLastError()));
            closesocket(m_listenSocket);
            return false;
        }
        
        // 5. 启动接收线程
        m_running = true;
        m_acceptThread = std::thread(&TCPServer::Impl::acceptLoop, this);
        
        Logger::getInstance().log(LogLevel::INFO,
            "TCP服务器已启动: " + ip + ":" + std::to_string(port));
        
        return true;
    }
    
    void stop() {
        m_running = false;
        
        // 关闭监听Socket以唤醒accept
        if (m_listenSocket != INVALID_SOCKET) {
            shutdown(m_listenSocket, SD_BOTH);
            closesocket(m_listenSocket);
            m_listenSocket = INVALID_SOCKET;
        }
        
        // 等待接收线程结束
        if (m_acceptThread.joinable()) {
            m_acceptThread.join();
        }
        
        // 关闭所有客户端会话
        {
            std::lock_guard<std::mutex> lock(m_clientsMutex);
            for (auto& session : m_clients) {
                session->stop();
            }
            m_clients.clear();
        }
        
        Logger::getInstance().log(LogLevel::INFO, "TCP服务器已停止");
    }
    
    void printStatus() {
        std::lock_guard<std::mutex> lock(m_clientsMutex);
        
        Logger::getInstance().log(LogLevel::INFO,
            "TCP服务器状态 - 客户端数量: " + std::to_string(m_clients.size()));
        
        for (const auto& session : m_clients) {
            auto now = std::chrono::steady_clock::now();
            auto duration = std::chrono::duration_cast<std::chrono::seconds>(
                now - session->getLastActivity());
            
            Logger::getInstance().log(LogLevel::INFO,
                "  客户端: " + session->getClientInfo() +
                ", 活跃: " + std::to_string(duration.count()) + "秒前");
        }
    }
    
    void broadcastMessage(const std::string& message) {
        std::lock_guard<std::mutex> lock(m_clientsMutex);
        
        for (auto& session : m_clients) {
            if (session->isConnected()) {
                session->sendMessage(message);
            }
        }
    }
    
private:
    void acceptLoop() {
        while (m_running) {
            sockaddr_in clientAddr;
            int clientAddrLen = sizeof(clientAddr);
            
            // 接受新的客户端连接
            SOCKET clientSocket = accept(m_listenSocket, 
                                       (sockaddr*)&clientAddr, 
                                       &clientAddrLen);
            
            if (clientSocket == INVALID_SOCKET) {
                if (m_running) {
                    Logger::getInstance().log(LogLevel::ERROR,
                        "接受连接失败: " + std::to_string(WSAGetLastError()));
                }
                continue;
            }
            
            // 获取客户端信息
            std::string clientIP = inet_ntoa(clientAddr.sin_addr);
            uint16_t clientPort = ntohs(clientAddr.sin_port);
            
            // 创建客户端会话
            auto session = std::make_shared<TCPClientSession>(
                clientSocket, clientIP, clientPort);
            
            // 添加到客户端列表
            {
                std::lock_guard<std::mutex> lock(m_clientsMutex);
                
                // 清理已断开的会话
                auto it = m_clients.begin();
                while (it != m_clients.end()) {
                    if (!(*it)->isConnected()) {
                        it = m_clients.erase(it);
                    } else {
                        ++it;
                    }
                }
                
                // 检查最大连接数
                if (m_clients.size() >= ConfigManager::getInstance().getMaxClients()) {
                    Logger::getInstance().log(LogLevel::WARNING,
                        "达到最大客户端数,拒绝新连接: " + clientIP);
                    closesocket(clientSocket);
                    continue;
                }
                
                m_clients.push_back(session);
            }
            
            // 启动会话
            session->start();
            
            Logger::getInstance().log(LogLevel::INFO,
                "新客户端连接: " + clientIP + ":" + std::to_string(clientPort) +
                ", 当前连接数: " + std::to_string(m_clients.size()));
            
            // 发送欢迎消息
            std::string welcome = "欢迎连接到PC热点通信服务器!";
            session->sendMessage(welcome);
        }
    }
    
    SOCKET m_listenSocket;
    std::atomic<bool> m_running;
    std::thread m_acceptThread;
    
    std::vector<std::shared_ptr<TCPClientSession>> m_clients;
    std::mutex m_clientsMutex;
};

// TCPServer公共接口实现
TCPServer::TCPServer() : m_impl(new Impl()) {}
TCPServer::~TCPServer() { delete m_impl; }

bool TCPServer::start(const std::string& ip, uint16_t port) {
    return m_impl->start(ip, port);
}

void TCPServer::stop() {
    m_impl->stop();
}

void TCPServer::printStatus() {
    m_impl->printStatus();
}

void TCPServer::broadcastMessage(const std::string& message) {
    m_impl->broadcastMessage(message);
}
4.2.4 心跳管理模块
cpp 复制代码
// heartbeat.cpp - 心跳检测管理
#include "heartbeat.h"
#include <algorithm>
#include <chrono>

class HeartbeatManager::Impl {
public:
    Impl() : m_running(false) {}
    
    void start(int timeoutSeconds) {
        m_timeoutSeconds = timeoutSeconds;
        m_running = true;
        m_checkThread = std::thread(&HeartbeatManager::Impl::checkLoop, this);
        
        Logger::getInstance().log(LogLevel::INFO,
            "心跳检测已启动,超时时间: " + std::to_string(timeoutSeconds) + "秒");
    }
    
    void stop() {
        m_running = false;
        if (m_checkThread.joinable()) {
            m_checkThread.join();
        }
        
        Logger::getInstance().log(LogLevel::INFO, "心跳检测已停止");
    }
    
    void updateClientActivity(const std::string& clientId) {
        std::lock_guard<std::mutex> lock(m_clientsMutex);
        m_clients[clientId] = std::chrono::steady_clock::now();
    }
    
    void removeClient(const std::string& clientId) {
        std::lock_guard<std::mutex> lock(m_clientsMutex);
        m_clients.erase(clientId);
    }
    
private:
    void checkLoop() {
        while (m_running) {
            std::this_thread::sleep_for(std::chrono::seconds(1));
            
            auto now = std::chrono::steady_clock::now();
            
            std::lock_guard<std::mutex> lock(m_clientsMutex);
            auto it = m_clients.begin();
            
            while (it != m_clients.end()) {
                auto duration = std::chrono::duration_cast<std::chrono::seconds>(
                    now - it->second);
                
                if (duration.count() > m_timeoutSeconds) {
                    // 客户端超时
                    Logger::getInstance().log(LogLevel::WARNING,
                        "客户端心跳超时: " + it->first);
                    
                    // 这里可以触发断开连接逻辑
                    // 注意:在实际TCP连接管理中应该处理
                    
                    it = m_clients.erase(it);
                } else {
                    ++it;
                }
            }
        }
    }
    
    std::atomic<bool> m_running;
    std::thread m_checkThread;
    int m_timeoutSeconds;
    
    std::unordered_map<std::string, 
        std::chrono::steady_clock::time_point> m_clients;
    std::mutex m_clientsMutex;
};

HeartbeatManager::HeartbeatManager() : m_impl(new Impl()) {}
HeartbeatManager::~HeartbeatManager() { delete m_impl; }

void HeartbeatManager::start(int timeoutSeconds) {
    m_impl->start(timeoutSeconds);
}

void HeartbeatManager::stop() {
    m_impl->stop();
}

void HeartbeatManager::updateClientActivity(const std::string& clientId) {
    m_impl->updateClientActivity(clientId);
}

void HeartbeatManager::removeClient(const std::string& clientId) {
    m_impl->removeClient(clientId);
}

4.3 配置文件设计

ini 复制代码
; config.ini - 配置文件示例
[network]
; 热点IP地址(手动开启热点后确认)
hotspot_ip = 192.168.137.1

; UDP发现端口
udp_discover_port = 9999

; TCP服务端口
tcp_service_port = 8888

; 心跳超时时间(秒)
heartbeat_timeout = 15

; 最大客户端连接数
max_clients = 10

[logging]
; 日志级别: DEBUG, INFO, WARNING, ERROR, FATAL
log_level = INFO

; 日志文件路径
log_file = pc_server.log

; 是否输出到控制台
console_output = true

[security]
; 是否启用消息加密
enable_encryption = false

; AES加密密钥(256位)
aes_key = 0123456789ABCDEF0123456789ABCDEF

[advanced]
; 接收缓冲区大小(字节)
receive_buffer_size = 4096

; 发送缓冲区大小(字节)
send_buffer_size = 4096

; TCP连接超时(毫秒)
tcp_connect_timeout = 5000

; 是否启用Nagle算法
tcp_nodelay = true

4.4 构建配置文件(CMake)

cmake 复制代码
# CMakeLists.txt - 构建配置
cmake_minimum_required(VERSION 3.15)
project(PC_Hotspot_Server)

# 设置C++标准
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# 在Windows上链接Winsock库
if(WIN32)
    set(PLATFORM_LIBS ws2_32)
    add_definitions(-DWIN32_LEAN_AND_MEAN)
endif()

# 包含目录
include_directories(
    ${CMAKE_CURRENT_SOURCE_DIR}/include
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party
)

# 源文件
set(SOURCES
    src/main.cpp
    src/network/udp_discover.cpp
    src/network/tcp_server.cpp
    src/network/heartbeat.cpp
    src/utils/logger.cpp
    src/utils/config.cpp
    src/protocol/message.cpp
    src/protocol/parser.cpp
)

# 创建可执行文件
add_executable(pc_hotspot_server ${SOURCES})

# 链接库
target_link_libraries(pc_hotspot_server ${PLATFORM_LIBS})

# 安装目标
install(TARGETS pc_hotspot_server
    RUNTIME DESTINATION bin
    LIBRARY DESTINATION lib
    ARCHIVE DESTINATION lib
)

# 安装配置文件
install(FILES config.ini DESTINATION etc)

五、手机端实现(Android/Kotlin)

5.1 Android项目结构

复制代码
AndroidHotspotClient/
├── app/
│   ├── src/main/
│   │   ├── java/com/example/hotspotclient/
│   │   │   ├── MainActivity.kt
│   │   │   ├── network/
│   │   │   │   ├── PCHotspotClient.kt
│   │   │   │   ├── UdpDiscover.kt
│   │   │   │   └── TcpConnection.kt
│   │   │   ├── ui/
│   │   │   │   ├── ConnectionFragment.kt
│   │   │   │   ├── MessageFragment.kt
│   │   │   │   └── FileTransferFragment.kt
│   │   │   └── utils/
│   │   │       ├── Logger.kt
│   │   │       └── PreferenceHelper.kt
│   │   ├── res/
│   │   └── AndroidManifest.xml
│   └── build.gradle
└── build.gradle

5.2 完整的Android实现

5.2.1 AndroidManifest.xml配置
xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.hotspotclient">

    <!-- 网络权限 -->
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />
    
    <!-- 文件传输相关权限 -->
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    
    <!-- Android 10+ 需要额外的文件权限 -->
    <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
        android:minSdkVersion="30" />
    
    <!-- 前台服务权限(保持后台连接) -->
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.HotspotClient"
        android:usesCleartextTraffic="true"> <!-- 允许HTTP明文传输 -->
        
        <!-- 主Activity -->
        <activity
            android:name=".MainActivity"
            android:exported="true"
            android:screenOrientation="portrait"
            android:windowSoftInputMode="adjustResize">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        
        <!-- 文件选择Activity -->
        <activity
            android:name=".ui.FilePickerActivity"
            android:exported="false" />
        
        <!-- 连接服务(后台保持连接) -->
        <service
            android:name=".network.ConnectionService"
            android:exported="false"
            android:foregroundServiceType="dataSync" />
            
        <!-- 文件传输服务 -->
        <service
            android:name=".network.FileTransferService"
            android:exported="false" />
            
    </application>

</manifest>
5.2.2 增强的PCHotspotClient类
kotlin 复制代码
// PCHotspotClient.kt - 增强的网络客户端
package com.example.hotspotclient.network

import android.content.Context
import android.net.ConnectivityManager
import android.net.NetworkCapabilities
import android.net.wifi.WifiManager
import android.os.Build
import android.util.Log
import kotlinx.coroutines.*
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.*
import java.io.*
import java.net.*
import java.nio.charset.StandardCharsets
import java.security.MessageDigest
import java.util.*
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.atomic.AtomicBoolean
import javax.crypto.Cipher
import javax.crypto.spec.SecretKeySpec

/**
 * PC热点通信客户端(增强版)
 * 支持:
 * 1. UDP自动发现
 * 2. TCP可靠通信
 * 3. 心跳保活
 * 4. 自动重连
 * 5. 文件传输
 * 6. 消息加密
 */
class PCHotspotClient(private val context: Context) {
    
    companion object {
        private const val TAG = "PCHotspotClient"
        private const val UDP_DISCOVER_PORT = 9999
        private const val DEFAULT_TCP_PORT = 8888
        private const val BROADCAST_ADDRESS = "255.255.255.255"
        private const val DISCOVER_MAGIC = "DISC"
        private const val RESPONSE_MAGIC = "RESP"
        
        // 心跳配置
        private const val HEARTBEAT_INTERVAL = 5000L     // 5秒
        private const val HEARTBEAT_TIMEOUT = 15000L    // 15秒
        private const val RECONNECT_DELAY = 3000L       // 3秒
        
        // 消息类型
        const val MSG_TYPE_TEXT = 1
        const val MSG_TYPE_FILE_INFO = 2
        const val MSG_TYPE_COMMAND = 3
        const val MSG_TYPE_HEARTBEAT = 4
    }
    
    // 协程相关
    private val scope = CoroutineScope(Dispatchers.IO + SupervisorJob())
    private var heartbeatJob: Job? = null
    private var receiveJob: Job? = null
    private var discoverJob: Job? = null
    
    // 网络连接
    private var tcpSocket: Socket? = null
    private var outputStream: OutputStream? = null
    private var inputStream: InputStream? = null
    private var currentTcpPort = DEFAULT_TCP_PORT
    private var pcHotspotIP = "192.168.137.1"
    
    // 状态管理
    private val isConnected = AtomicBoolean(false)
    private val isDiscovering = AtomicBoolean(false)
    private val isReconnecting = AtomicBoolean(false)
    private var lastHeartbeatTime = System.currentTimeMillis()
    private var connectionStartTime = 0L
    
    // 数据流
    private val _connectionState = MutableStateFlow<ConnectionState>(ConnectionState.DISCONNECTED)
    val connectionState: StateFlow<ConnectionState> = _connectionState
    
    private val _receivedMessages = Channel<NetworkMessage>(Channel.UNLIMITED)
    val receivedMessages: Flow<NetworkMessage> = _receivedMessages.receiveAsFlow()
    
    private val _fileTransferProgress = MutableStateFlow<FileTransferProgress?>(null)
    val fileTransferProgress: StateFlow<FileTransferProgress?> = _fileTransferProgress
    
    // 配置
    private val preferences = context.getSharedPreferences("hotspot_config", Context.MODE_PRIVATE)
    private var enableEncryption = false
    private var aesKey: ByteArray? = null
    
    // 枚举定义
    enum class ConnectionState {
        DISCONNECTED,        // 未连接
        DISCOVERING,         // 正在发现PC
        CONNECTING,          // 正在连接PC
        CONNECTED,           // 已连接
        TRANSFERRING,        // 正在传输文件
        ERROR                // 连接错误
    }
    
    data class NetworkMessage(
        val type: Int,
        val content: String,
        val timestamp: Long = System.currentTimeMillis(),
        val sender: String = "PC"
    )
    
    data class FileTransferProgress(
        val fileName: String,
        val totalBytes: Long,
        val transferredBytes: Long,
        val progress: Float,
        val isUpload: Boolean,
        val state: TransferState
    ) {
        enum class TransferState {
            PREPARING,
            TRANSFERRING,
            COMPLETED,
            FAILED,
            CANCELLED
        }
    }
    
    /**
     * 启动通信流程
     */
    fun start() {
        if (isConnected.get()) {
            Log.w(TAG, "客户端已启动,忽略重复调用")
            return
        }
        
        scope.launch {
            _connectionState.value = ConnectionState.DISCOVERING
            loadConfig()
            
            // 先尝试使用上次保存的PC IP和端口
            val savedIP = preferences.getString("pc_ip", null)
            val savedPort = preferences.getInt("pc_port", -1)
            
            if (savedIP != null && savedPort != -1) {
                Log.d(TAG, "使用保存的连接信息: $savedIP:$savedPort")
                connectTCPServer(savedIP, savedPort, isFirstAttempt = false)
            }
            
            // 同时开始UDP发现
            discoverPCByUDP()
        }
    }
    
    /**
     * UDP发现PC
     */
    private suspend fun discoverPCByUDP() {
        if (isDiscovering.getAndSet(true)) {
            Log.d(TAG, "UDP发现已在运行中")
            return
        }
        
        discoverJob = scope.launch {
            var udpSocket: DatagramSocket? = null
            
            try {
                _connectionState.value = ConnectionState.DISCOVERING
                
                // 创建UDP Socket
                udpSocket = DatagramSocket()
                udpSocket.broadcast = true
                udpSocket.soTimeout = 5000 // 5秒超时
                
                // 构造发现消息(增强协议)
                val deviceInfo = getDeviceInfo()
                val discoverMsg = buildDiscoverMessage(deviceInfo)
                
                // 发送广播
                val broadcastAddr = InetAddress.getByName(BROADCAST_ADDRESS)
                val sendPacket = DatagramPacket(
                    discoverMsg, discoverMsg.size,
                    broadcastAddr, UDP_DISCOVER_PORT
                )
                
                udpSocket.send(sendPacket)
                Log.d(TAG, "UDP发现广播已发送: ${deviceInfo.deviceName}")
                
                // 接收响应(最多尝试3次)
                repeat(3) { attempt ->
                    if (!isDiscovering.get()) return@repeat
                    
                    try {
                        val recvBuffer = ByteArray(1024)
                        val recvPacket = DatagramPacket(recvBuffer, recvBuffer.size)
                        
                        udpSocket.receive(recvPacket)
                        
                        val response = parseDiscoverResponse(recvPacket.data, recvPacket.length)
                        if (response != null) {
                            val pcIP = recvPacket.address.hostAddress
                            val pcPort = response.tcpPort
                            
                            Log.d(TAG, "发现PC: $pcIP:$pcPort, 设备: ${response.deviceName}")
                            
                            // 保存连接信息
                            with(preferences.edit()) {
                                putString("pc_ip", pcIP)
                                putInt("pc_port", pcPort)
                                apply()
                            }
                            
                            // 连接到PC
                            connectTCPServer(pcIP, pcPort, isFirstAttempt = true)
                            return@repeat
                        }
                    } catch (e: SocketTimeoutException) {
                        Log.d(TAG, "UDP发现超时 (尝试 ${attempt + 1}/3)")
                    }
                }
                
                // 所有尝试都失败
                if (isDiscovering.get() && !isConnected.get()) {
                    Log.w(TAG, "UDP发现失败,尝试默认连接")
                    val savedIP = preferences.getString("pc_ip", pcHotspotIP)
                    val savedPort = preferences.getInt("pc_port", DEFAULT_TCP_PORT)
                    connectTCPServer(savedIP ?: pcHotspotIP, savedPort, isFirstAttempt = true)
                }
                
            } catch (e: Exception) {
                Log.e(TAG, "UDP发现失败: ${e.message}", e)
                _connectionState.value = ConnectionState.ERROR
            } finally {
                udpSocket?.close()
                isDiscovering.set(false)
            }
        }
    }
    
    /**
     * 连接TCP服务器
     */
    private suspend fun connectTCPServer(ip: String, port: Int, isFirstAttempt: Boolean) {
        if (isReconnecting.getAndSet(true) && !isFirstAttempt) {
            Log.d(TAG, "已经在重连中,跳过")
            return
        }
        
        scope.launch {
            try {
                _connectionState.value = ConnectionState.CONNECTING
                
                // 停止UDP发现
                discoverJob?.cancel()
                isDiscovering.set(false)
                
                // 关闭现有连接
                disconnectInternal()
                
                // 创建TCP连接
                val socket = Socket()
                socket.soTimeout = 5000 // 连接超时5秒
                
                withContext(Dispatchers.IO) {
                    socket.connect(InetSocketAddress(ip, port), 5000)
                }
                
                // 连接成功
                tcpSocket = socket
                outputStream = socket.getOutputStream()
                inputStream = socket.getInputStream()
                currentTcpPort = port
                pcHotspotIP = ip
                
                isConnected.set(true)
                connectionStartTime = System.currentTimeMillis()
                lastHeartbeatTime = System.currentTimeMillis()
                
                // 更新状态
                _connectionState.value = ConnectionState.CONNECTED
                isReconnecting.set(false)
                
                Log.d(TAG, "TCP连接成功: $ip:$port")
                
                // 发送连接确认消息
                sendConnectionInfo()
                
                // 启动心跳
                startHeartbeat()
                
                // 启动消息接收
                startReceiving()
                
            } catch (e: Exception) {
                Log.e(TAG, "TCP连接失败: ${e.message}", e)
                
                // 更新状态
                _connectionState.value = ConnectionState.ERROR
                isReconnecting.set(false)
                
                // 延迟后重试
                if (isFirstAttempt) {
                    delay(RECONNECT_DELAY)
                    discoverPCByUDP()
                }
            }
        }
    }
    
    /**
     * 启动心跳
     */
    private fun startHeartbeat() {
        heartbeatJob?.cancel()
        
        heartbeatJob = scope.launch {
            while (isConnected.get() && isActive) {
                try {
                    // 检查心跳超时
                    val now = System.currentTimeMillis()
                    if (now - lastHeartbeatTime > HEARTBEAT_TIMEOUT) {
                        Log.w(TAG, "心跳超时,触发重连")
                        reconnect()
                        break
                    }
                    
                    // 发送心跳
                    sendHeartbeat()
                    
                    delay(HEARTBEAT_INTERVAL)
                    
                } catch (e: Exception) {
                    Log.e(TAG, "心跳发送失败: ${e.message}")
                    if (isConnected.get()) {
                        reconnect()
                    }
                    break
                }
            }
        }
    }
    
    /**
     * 启动消息接收
     */
    private fun startReceiving() {
        receiveJob?.cancel()
        
        receiveJob = scope.launch {
            val reader = BufferedReader(InputStreamReader(inputStream!!, StandardCharsets.UTF_8))
            val buffer = CharArray(4096)
            
            try {
                while (isConnected.get() && isActive) {
                    val length = withContext(Dispatchers.IO) {
                        reader.read(buffer)
                    }
                    
                    if (length == -1) {
                        Log.d(TAG, "连接已关闭")
                        reconnect()
                        break
                    }
                    
                    val message = String(buffer, 0, length).trim()
                    if (message.isNotEmpty()) {
                        processReceivedMessage(message)
                    }
                }
            } catch (e: Exception) {
                Log.e(TAG, "接收消息失败: ${e.message}")
                if (isConnected.get()) {
                    reconnect()
                }
            }
        }
    }
    
    /**
     * 处理接收到的消息
     */
    private suspend fun processReceivedMessage(message: String) {
        // 更新心跳时间
        if (message == "PONG") {
            lastHeartbeatTime = System.currentTimeMillis()
            Log.d(TAG, "收到心跳回复")
            return
        }
        
        // 解密消息(如果启用加密)
        val decryptedMessage = if (enableEncryption && aesKey != null) {
            decryptMessage(message)
        } else {
            message
        }
        
        // 解析消息类型
        val networkMessage = parseNetworkMessage(decryptedMessage)
        
        // 发送到消息通道
        _receivedMessages.send(networkMessage)
        
        Log.d(TAG, "收到消息[${networkMessage.type}]: ${networkMessage.content}")
    }
    
    /**
     * 发送文本消息
     */
    fun sendTextMessage(text: String) {
        scope.launch {
            if (!isConnected.get()) {
                Log.w(TAG, "未连接,无法发送消息")
                return@launch
            }
            
            try {
                val message = buildTextMessage(text)
                sendRawMessage(message)
                
                // 本地也显示发送的消息
                val sentMessage = NetworkMessage(
                    type = MSG_TYPE_TEXT,
                    content = text,
                    sender = "我"
                )
                _receivedMessages.send(sentMessage)
                
            } catch (e: Exception) {
                Log.e(TAG, "发送消息失败: ${e.message}")
                reconnect()
            }
        }
    }
    
    /**
     * 发送文件
     */
    fun sendFile(filePath: String, fileName: String? = null) {
        scope.launch {
            if (!isConnected.get()) {
                Log.w(TAG, "未连接,无法发送文件")
                return@launch
            }
            
            try {
                _connectionState.value = ConnectionState.TRANSFERRING
                
                val file = File(filePath)
                if (!file.exists()) {
                    throw IOException("文件不存在: $filePath")
                }
                
                val actualFileName = fileName ?: file.name
                val fileSize = file.length()
                
                // 1. 发送文件信息
                val fileInfo = buildFileInfoMessage(actualFileName, fileSize)
                sendRawMessage(fileInfo)
                
                // 2. 等待PC确认
                delay(100) // 简单延迟,实际应该等待确认消息
                
                // 3. 发送文件数据
                _fileTransferProgress.value = FileTransferProgress(
                    fileName = actualFileName,
                    totalBytes = fileSize,
                    transferredBytes = 0,
                    progress = 0f,
                    isUpload = true,
                    state = FileTransferProgress.TransferState.TRANSFERRING
                )
                
                val buffer = ByteArray(4096)
                var bytesSent = 0L
                
                FileInputStream(file).use { fis ->
                    BufferedInputStream(fis).use { bis ->
                        while (bytesSent < fileSize) {
                            val read = bis.read(buffer)
                            if (read == -1) break
                            
                            // 发送数据块
                            val chunk = buildFileChunkMessage(buffer, read)
                            sendRawMessage(chunk)
                            
                            bytesSent += read
                            
                            // 更新进度
                            val progress = bytesSent.toFloat() / fileSize
                            _fileTransferProgress.value = FileTransferProgress(
                                fileName = actualFileName,
                                totalBytes = fileSize,
                                transferredBytes = bytesSent,
                                progress = progress,
                                isUpload = true,
                                state = FileTransferProgress.TransferState.TRANSFERRING
                            )
                            
                            // 控制发送速度
                            delay(10)
                        }
                    }
                }
                
                // 4. 发送完成标记
                val endMarker = buildFileEndMessage(actualFileName, fileSize)
                sendRawMessage(endMarker)
                
                // 更新状态
                _fileTransferProgress.value = FileTransferProgress(
                    fileName = actualFileName,
                    totalBytes = fileSize,
                    transferredBytes = fileSize,
                    progress = 1f,
                    isUpload = true,
                    state = FileTransferProgress.TransferState.COMPLETED
                )
                
                _connectionState.value = ConnectionState.CONNECTED
                
                Log.d(TAG, "文件发送完成: $actualFileName ($fileSize bytes)")
                
            } catch (e: Exception) {
                Log.e(TAG, "文件发送失败: ${e.message}", e)
                _fileTransferProgress.value = FileTransferProgress(
                    fileName = fileName ?: "",
                    totalBytes = 0,
                    transferredBytes = 0,
                    progress = 0f,
                    isUpload = true,
                    state = FileTransferProgress.TransferState.FAILED
                )
                _connectionState.value = ConnectionState.CONNECTED
                reconnect()
            }
        }
    }
    
    /**
     * 重新连接
     */
    private fun reconnect() {
        scope.launch {
            if (isReconnecting.getAndSet(true)) {
                return@launch
            }
            
            Log.d(TAG, "开始重新连接...")
            _connectionState.value = ConnectionState.DISCONNECTED
            
            // 断开现有连接
            disconnectInternal()
            
            // 延迟后重试
            delay(RECONNECT_DELAY)
            
            // 重新发现PC
            isReconnecting.set(false)
            discoverPCByUDP()
        }
    }
    
    /**
     * 断开连接
     */
    fun disconnect() {
        scope.launch {
            disconnectInternal()
            _connectionState.value = ConnectionState.DISCONNECTED
            Log.d(TAG, "手动断开连接")
        }
    }
    
    /**
     * 内部断开连接
     */
    private fun disconnectInternal() {
        isConnected.set(false)
        isDiscovering.set(false)
        
        // 取消所有任务
        heartbeatJob?.cancel()
        receiveJob?.cancel()
        discoverJob?.cancel()
        
        // 关闭Socket
        try {
            tcpSocket?.close()
        } catch (e: Exception) {
            Log.e(TAG, "关闭Socket失败: ${e.message}")
        }
        
        tcpSocket = null
        outputStream = null
        inputStream = null
    }
    
    /**
     * 加载配置
     */
    private fun loadConfig() {
        enableEncryption = preferences.getBoolean("enable_encryption", false)
        val savedKey = preferences.getString("aes_key", null)
        if (savedKey != null) {
            aesKey = savedKey.toByteArray()
        }
        
        // 获取设备信息
        val wifiManager = context.applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager
        val wifiInfo = wifiManager.connectionInfo
        pcHotspotIP = preferences.getString("pc_ip", "192.168.137.1") ?: "192.168.137.1"
    }
    
    /**
     * 获取设备信息
     */
    private fun getDeviceInfo(): DeviceInfo {
        return DeviceInfo(
            deviceName = Build.MODEL,
            deviceType = "Android",
            osVersion = Build.VERSION.RELEASE,
            appVersion = "1.0.0"
        )
    }
    
    // 以下为消息构建和解析的辅助方法...
    
    data class DeviceInfo(
        val deviceName: String,
        val deviceType: String,
        val osVersion: String,
        val appVersion: String
    )
    
    data class DiscoverResponse(
        val tcpPort: Int,
        val deviceName: String,
        val ipAddress: String
    )
    
    // 消息构建方法
    private fun buildDiscoverMessage(deviceInfo: DeviceInfo): ByteArray {
        val message = StringBuilder()
        message.append(DISCOVER_MAGIC)
        message.append("|")
        message.append(deviceInfo.deviceName)
        message.append("|")
        message.append(deviceInfo.deviceType)
        message.append("|")
        message.append(deviceInfo.osVersion)
        message.append("|")
        message.append(deviceInfo.appVersion)
        return message.toString().toByteArray()
    }
    
    private fun parseDiscoverResponse(data: ByteArray, length: Int): DiscoverResponse? {
        val response = String(data, 0, length, StandardCharsets.UTF_8)
        if (!response.startsWith(RESPONSE_MAGIC)) {
            return null
        }
        
        val parts = response.split("|")
        if (parts.size >= 3) {
            return try {
                DiscoverResponse(
                    tcpPort = parts[1].toInt(),
                    deviceName = parts[2],
                    ipAddress = parts.getOrElse(3) { "" }
                )
            } catch (e: NumberFormatException) {
                null
            }
        }
        return null
    }
    
    private fun buildTextMessage(text: String): String {
        return "TEXT|$text"
    }
    
    private fun buildFileInfoMessage(fileName: String, fileSize: Long): String {
        return "FILE_INFO|$fileName|$fileSize"
    }
    
    private fun parseNetworkMessage(message: String): NetworkMessage {
        return when {
            message.startsWith("TEXT|") -> {
                val content = message.substringAfter("TEXT|")
                NetworkMessage(MSG_TYPE_TEXT, content)
            }
            message.startsWith("FILE_INFO|") -> {
                NetworkMessage(MSG_TYPE_FILE_INFO, message)
            }
            message == "PONG" -> {
                NetworkMessage(MSG_TYPE_HEARTBEAT, message)
            }
            else -> {
                NetworkMessage(MSG_TYPE_TEXT, message)
            }
        }
    }
    
    private fun sendRawMessage(message: String) {
        val bytes = if (enableEncryption && aesKey != null) {
            encryptMessage(message)
        } else {
            message.toByteArray(StandardCharsets.UTF_8)
        }
        
        outputStream?.write(bytes)
        outputStream?.write('\n'.code) // 添加分隔符
        outputStream?.flush()
    }
    
    private fun sendHeartbeat() {
        sendRawMessage("PING")
    }
    
    private fun sendConnectionInfo() {
        val deviceInfo = getDeviceInfo()
        val info = "CONNECT|${deviceInfo.deviceName}|${deviceInfo.appVersion}"
        sendRawMessage(info)
    }
    
    // 加密解密方法
    private fun encryptMessage(message: String): ByteArray {
        // 简化的AES加密实现
        // 实际项目中应该使用更安全的密钥管理和加密方式
        return message.toByteArray(StandardCharsets.UTF_8)
    }
    
    private fun decryptMessage(encrypted: String): String {
        // 简化解密实现
        return encrypted
    }
}
5.2.3 MainActivity实现
kotlin 复制代码
// MainActivity.kt - 主界面
package com.example.hotspotclient

import android.Manifest
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import com.example.hotspotclient.databinding.ActivityMainBinding
import com.example.hotspotclient.network.PCHotspotClient
import com.example.hotspotclient.ui.ConnectionFragment
import com.example.hotspotclient.ui.MessageFragment
import com.example.hotspotclient.ui.FileTransferFragment
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch

class MainActivity : AppCompatActivity() {
    
    private lateinit var binding: ActivityMainBinding
    private lateinit var hotspotClient: PCHotspotClient
    
    // 权限请求
    private val requestPermissionLauncher = registerForActivityResult(
        ActivityResultContracts.RequestMultiplePermissions()
    ) { permissions ->
        val allGranted = permissions.all { it.value }
        if (allGranted) {
            startHotspotClient()
        } else {
            Toast.makeText(this, "需要权限才能使用全部功能", Toast.LENGTH_LONG).show()
        }
    }
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)
        
        // 初始化热点客户端
        hotspotClient = PCHotspotClient(this)
        
        // 检查权限
        checkPermissions()
        
        // 设置底部导航
        setupBottomNavigation()
        
        // 监听连接状态
        observeConnectionState()
    }
    
    private fun checkPermissions() {
        val permissions = mutableListOf<String>()
        
        // 网络权限
        permissions.add(Manifest.permission.INTERNET)
        permissions.add(Manifest.permission.ACCESS_NETWORK_STATE)
        permissions.add(Manifest.permission.ACCESS_WIFI_STATE)
        permissions.add(Manifest.permission.CHANGE_WIFI_MULTICAST_STATE)
        
        // 存储权限(Android 10以下)
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
            permissions.add(Manifest.permission.READ_EXTERNAL_STORAGE)
            permissions.add(Manifest.permission.WRITE_EXTERNAL_STORAGE)
        }
        
        // 检查是否已授予权限
        val ungrantedPermissions = permissions.filter {
            ContextCompat.checkSelfPermission(this, it) != PackageManager.PERMISSION_GRANTED
        }
        
        if (ungrantedPermissions.isNotEmpty()) {
            requestPermissionLauncher.launch(ungrantedPermissions.toTypedArray())
        } else {
            startHotspotClient()
        }
    }
    
    private fun startHotspotClient() {
        lifecycleScope.launch {
            // 延迟启动,等待UI加载完成
            kotlinx.coroutines.delay(1000)
            hotspotClient.start()
        }
    }
    
    private fun setupBottomNavigation() {
        binding.bottomNavigation.setOnItemSelectedListener { item ->
            when (item.itemId) {
                R.id.navigation_connection -> {
                    replaceFragment(ConnectionFragment.newInstance(hotspotClient))
                    true
                }
                R.id.navigation_messages -> {
                    replaceFragment(MessageFragment.newInstance(hotspotClient))
                    true
                }
                R.id.navigation_files -> {
                    replaceFragment(FileTransferFragment.newInstance(hotspotClient))
                    true
                }
                else -> false
            }
        }
        
        // 默认显示连接页面
        replaceFragment(ConnectionFragment.newInstance(hotspotClient))
    }
    
    private fun replaceFragment(fragment: Fragment) {
        supportFragmentManager.beginTransaction()
            .replace(R.id.fragment_container, fragment)
            .commit()
    }
    
    private fun observeConnectionState() {
        lifecycleScope.launch {
            hotspotClient.connectionState.collect { state ->
                when (state) {
                    PCHotspotClient.ConnectionState.DISCONNECTED -> {
                        updateConnectionStatus("未连接", R.color.red)
                    }
                    PCHotspotClient.ConnectionState.DISCOVERING -> {
                        updateConnectionStatus("正在发现PC...", R.color.orange)
                    }
                    PCHotspotClient.ConnectionState.CONNECTING -> {
                        updateConnectionStatus("正在连接...", R.color.orange)
                    }
                    PCHotspotClient.ConnectionState.CONNECTED -> {
                        updateConnectionStatus("已连接", R.color.green)
                    }
                    PCHotspotClient.ConnectionState.TRANSFERRING -> {
                        updateConnectionStatus("传输中...", R.color.blue)
                    }
                    PCHotspotClient.ConnectionState.ERROR -> {
                        updateConnectionStatus("连接错误", R.color.red)
                    }
                }
            }
        }
    }
    
    private fun updateConnectionStatus(text: String, colorRes: Int) {
        binding.connectionStatus.text = text
        binding.connectionStatus.setTextColor(ContextCompat.getColor(this, colorRes))
    }
    
    override fun onDestroy() {
        super.onDestroy()
        hotspotClient.disconnect()
    }
}
5.2.4 UI Fragment实现
kotlin 复制代码
// ConnectionFragment.kt - 连接状态界面
package com.example.hotspotclient.ui

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import com.example.hotspotclient.databinding.FragmentConnectionBinding
import com.example.hotspotclient.network.PCHotspotClient
import kotlinx.coroutines.flow.collect

class ConnectionFragment : Fragment() {
    
    private var _binding: FragmentConnectionBinding? = null
    private val binding get() = _binding!!
    
    private lateinit var hotspotClient: PCHotspotClient
    
    companion object {
        fun newInstance(client: PCHotspotClient): ConnectionFragment {
            val fragment = ConnectionFragment()
            fragment.hotspotClient = client
            return fragment
        }
    }
    
    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        _binding = FragmentConnectionBinding.inflate(inflater, container, false)
        return binding.root
    }
    
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        
        setupUI()
        observeConnectionState()
    }
    
    private fun setupUI() {
        binding.btnReconnect.setOnClickListener {
            hotspotClient.start()
        }
        
        binding.btnDisconnect.setOnClickListener {
            hotspotClient.disconnect()
        }
        
        binding.btnTestConnection.setOnClickListener {
            // 发送测试消息
            hotspotClient.sendTextMessage("测试连接消息")
        }
    }
    
    private fun observeConnectionState() {
        lifecycleScope.launch {
            hotspotClient.connectionState.collect { state ->
                updateConnectionInfo(state)
            }
        }
    }
    
    private fun updateConnectionInfo(state: PCHotspotClient.ConnectionState) {
        when (state) {
            PCHotspotClient.ConnectionState.DISCONNECTED -> {
                binding.tvConnectionStatus.text = "未连接"
                binding.tvConnectionStatus.setTextColor(resources.getColor(android.R.color.holo_red_dark, null))
                binding.btnReconnect.isEnabled = true
                binding.btnDisconnect.isEnabled = false
            }
            PCHotspotClient.ConnectionState.DISCOVERING -> {
                binding.tvConnectionStatus.text = "正在搜索PC..."
                binding.tvConnectionStatus.setTextColor(resources.getColor(android.R.color.holo_orange_dark, null))
                binding.btnReconnect.isEnabled = false
                binding.btnDisconnect.isEnabled = true
            }
            PCHotspotClient.ConnectionState.CONNECTING -> {
                binding.tvConnectionStatus.text = "正在连接..."
                binding.tvConnectionStatus.setTextColor(resources.getColor(android.R.color.holo_orange_dark, null))
                binding.btnReconnect.isEnabled = false
                binding.btnDisconnect.isEnabled = true
            }
            PCHotspotClient.ConnectionState.CONNECTED -> {
                binding.tvConnectionStatus.text = "已连接"
                binding.tvConnectionStatus.setTextColor(resources.getColor(android.R.color.holo_green_dark, null))
                binding.btnReconnect.isEnabled = false
                binding.btnDisconnect.isEnabled = true
            }
            PCHotspotClient.ConnectionState.TRANSFERRING -> {
                binding.tvConnectionStatus.text = "传输中..."
                binding.tvConnectionStatus.setTextColor(resources.getColor(android.R.color.holo_blue_dark, null))
                binding.btnReconnect.isEnabled = false
                binding.btnDisconnect.isEnabled = false
            }
            PCHotspotClient.ConnectionState.ERROR -> {
                binding.tvConnectionStatus.text = "连接错误"
                binding.tvConnectionStatus.setTextColor(resources.getColor(android.R.color.holo_red_dark, null))
                binding.btnReconnect.isEnabled = true
                binding.btnDisconnect.isEnabled = false
            }
        }
    }
    
    override fun onDestroyView() {
        super.onDestroyView()
        _binding = null
    }
}

5.3 Gradle构建配置

gradle 复制代码
// app/build.gradle.kts
plugins {
    id("com.android.application")
    id("org.jetbrains.kotlin.android")
}

android {
    namespace = "com.example.hotspotclient"
    compileSdk = 34
    
    defaultConfig {
        applicationId = "com.example.hotspotclient"
        minSdk = 24
        targetSdk = 34
        versionCode = 1
        versionName = "1.0"
        
        testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
    }
    
    buildTypes {
        release {
            isMinifyEnabled = false
            proguardFiles(
                getDefaultProguardFile("proguard-android-optimize.txt"),
                "proguard-rules.pro"
            )
        }
    }
    
    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_11
        targetCompatibility = JavaVersion.VERSION_11
    }
    
    kotlinOptions {
        jvmTarget = "11"
    }
    
    buildFeatures {
        viewBinding = true
    }
}

dependencies {
    // 核心依赖
    implementation("androidx.core:core-ktx:1.12.0")
    implementation("androidx.appcompat:appcompat:1.6.1")
    implementation("com.google.android.material:material:1.10.0")
    implementation("androidx.constraintlayout:constraintlayout:2.1.4")
    
    // 生命周期
    implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.6.2")
    implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2")
    implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.6.2")
    
    // 导航组件
    implementation("androidx.navigation:navigation-fragment-ktx:2.7.4")
    implementation("androidx.navigation:navigation-ui-ktx:2.7.4")
    
    // 协程
    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3")
    
    // 网络
    implementation("com.squareup.okhttp3:okhttp:4.12.0")
    
    // JSON解析
    implementation("com.google.code.gson:gson:2.10.1")
    
    // 权限请求
    implementation("com.guolindev.permissionx:permissionx:1.7.1")
    
    // 测试
    testImplementation("junit:junit:4.13.2")
    androidTestImplementation("androidx.test.ext:junit:1.1.5")
    androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
}

六、部署与测试步骤

6.1 PC端部署详细步骤

6.1.1 Windows平台部署
  1. 环境准备

    bash 复制代码
    # 检查Visual Studio安装
    # 确保已安装"C++桌面开发"工作负载
    
    # 安装CMake(可选)
    choco install cmake --installargs 'ADD_CMAKE_TO_PATH=System'
  2. 编译项目

    bash 复制代码
    # 方法1:使用Visual Studio IDE
    # 1. 打开Visual Studio
    # 2. 选择"打开项目或解决方案"
    # 3. 选择CMakeLists.txt文件
    # 4. 选择目标平台(x64 Debug/Release)
    # 5. 点击"生成" -> "生成解决方案"
    
    # 方法2:使用CMake命令行
    mkdir build
    cd build
    cmake .. -G "Visual Studio 17 2022" -A x64
    cmake --build . --config Release
  3. 防火墙配置

    powershell 复制代码
    # 以管理员身份运行PowerShell
    
    # 添加入站规则(UDP)
    New-NetFirewallRule -DisplayName "Hotspot UDP Discover" `
        -Direction Inbound `
        -Protocol UDP `
        -LocalPort 9999 `
        -Action Allow
    
    # 添加入站规则(TCP)
    New-NetFirewallRule -DisplayName "Hotspot TCP Service" `
        -Direction Inbound `
        -Protocol TCP `
        -LocalPort 8888 `
        -Action Allow
  4. 创建启动脚本

    batch 复制代码
    @echo off
    REM start_server.bat
    echo 正在启动PC热点通信服务器...
    echo.
    echo 请确保已执行以下操作:
    echo 1. 手动开启PC热点
    echo 2. 确认热点IP是否为192.168.137.1
    echo 3. 手机已连接该热点
    echo.
    pause
    
    REM 以管理员身份运行(需要处理UDP广播)
    if not "%1"=="admin" (
        powershell -Command "Start-Process '%0' -Verb RunAs -ArgumentList 'admin'"
        exit /b
    )
    
    cd /d "%~dp0"
    bin\pc_hotspot_server.exe
    pause
6.1.2 Linux平台部署
bash 复制代码
#!/bin/bash
# install_server.sh

# 安装依赖
sudo apt-get update
sudo apt-get install -y build-essential cmake libssl-dev

# 编译
mkdir build && cd build
cmake .. -DCMAKE_BUILD_TYPE=Release
make -j$(nproc)

# 创建服务用户
sudo useradd -r -s /bin/false hotspot_server

# 安装到系统
sudo cp pc_hotspot_server /usr/local/bin/
sudo mkdir -p /etc/hotspot_server
sudo cp ../config.ini /etc/hotspot_server/
sudo chown -R hotspot_server:hotspot_server /etc/hotspot_server

# 创建systemd服务
cat << EOF | sudo tee /etc/systemd/system/hotspot-server.service
[Unit]
Description=PC Hotspot Communication Server
After=network.target

[Service]
Type=simple
User=hotspot_server
Group=hotspot_server
WorkingDirectory=/etc/hotspot_server
ExecStart=/usr/local/bin/pc_hotspot_server
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF

# 启动服务
sudo systemctl daemon-reload
sudo systemctl enable hotspot-server
sudo systemctl start hotspot-server

echo "安装完成!服务已启动"
echo "查看状态: sudo systemctl status hotspot-server"
echo "查看日志: sudo journalctl -u hotspot-server -f"

6.2 手机端部署详细步骤

6.2.1 编译和安装
  1. 导入项目到Android Studio

    • 打开Android Studio
    • 选择"Open" -> 选择项目目录
    • 等待Gradle同步完成
  2. 配置签名

    gradle 复制代码
    // app/build.gradle.kts
    signingConfigs {
        create("release") {
            storeFile = file("hotspotclient.jks")
            storePassword = "your_password"
            keyAlias = "hotspotclient"
            keyPassword = "your_password"
        }
    }
    
    buildTypes {
        release {
            signingConfig = signingConfigs.getByName("release")
            // ...
        }
    }
  3. 生成APK

    • 选择Build -> Generate Signed Bundle / APK
    • 选择APK
    • 配置签名信息
    • 选择Build Variant: release
    • 点击Finish
6.2.2 无线调试安装(无需USB)
bash 复制代码
# 1. 确保PC和手机在同一网络
# 2. 启用手机开发者选项和无线调试
# 3. 获取手机IP和端口
# 4. 使用adb无线连接

adb connect 192.168.1.100:5555
adb install app-release.apk

6.3 完整测试流程

6.3.1 第一阶段:基础连接测试
  1. PC端操作

    bash 复制代码
    # 开启热点
    # Windows: 设置 -> 网络和Internet -> 移动热点 -> 开
    # 记录热点名称和密码
    
    # 运行服务器
    ./start_server.bat
    
    # 确认输出
    [INFO] UDP广播监听已启动,端口:9999
    [INFO] TCP服务端已启动,监听地址:192.168.137.1:8888
  2. 手机端操作

    • 连接PC热点

    • 打开应用

    • 观察连接状态变化:

      复制代码
      未连接 -> 正在发现PC... -> 正在连接... -> 已连接
    • 点击"测试连接"按钮

  3. 预期结果

    • PC控制台显示收到连接和消息
    • 手机显示连接成功状态
    • 测试消息正常收发
6.3.2 第二阶段:稳定性测试
  1. 断线重连测试

    • 手机端关闭WiFi,等待5秒后重新打开
    • 观察自动重连功能
    • 预期:30秒内自动恢复连接
  2. 心跳测试

    • 保持连接5分钟
    • 使用Wireshark抓包验证心跳包
    • 预期:每5秒发送一次PING,立即收到PONG回复
  3. 压力测试

    bash 复制代码
    # 使用多台手机同时连接
    # 测试最大连接数限制
    # 发送大量小消息(每秒10条)
6.3.3 第三阶段:功能测试
  1. 文件传输测试

    • 选择1MB图片文件
    • 点击发送
    • 观察进度条和传输速度
    • 验证文件完整性(MD5校验)
  2. 大文件测试

    • 选择100MB视频文件
    • 测试断点续传(如传输中断后恢复)
    • 验证传输速度和内存使用
  3. 多任务测试

    • 同时进行文件传输和消息聊天
    • 测试UI响应性
    • 验证数据不混乱

七、常见问题与解决方案

7.1 连接问题排查表

问题现象 可能原因 解决方案 验证方法
UDP发现失败 1. 防火墙拦截 2. 未开启热点 3. 端口被占用 1. 检查防火墙规则 2. 确认热点已开启 3. 更换UDP端口 `netstat -ano
TCP连接超时 1. IP地址错误 2. 端口错误 3. PC未监听 1. 确认热点IP 2. 检查TCP端口 3. 验证PC服务运行 telnet 192.168.137.1 8888
频繁断开重连 1. 信号弱 2. 心跳超时 3. 系统休眠 1. 靠近PC 2. 调整心跳参数 3. 保持唤醒锁 监控信号强度RSSI
传输速度慢 1. 网络干扰 2. 缓冲区小 3. 加密开销 1. 更换WiFi信道 2. 调整缓冲区 3. 禁用加密测试 iperf网络测速
内存泄漏 1. 资源未释放 2. 循环引用 3. 大文件缓存 1. 完善析构函数 2. 使用弱引用 3. 流式传输 Android Profiler

7.2 高级调试技巧

7.2.1 PC端调试
cpp 复制代码
// 启用详细日志
#define DEBUG_NETWORK 1

#ifdef DEBUG_NETWORK
    #define NET_LOG(fmt, ...) printf("[NET] " fmt "\n", ##__VA_ARGS__)
    #define NET_HEX_DUMP(data, len) hexDump(data, len)
#else
    #define NET_LOG(fmt, ...)
    #define NET_HEX_DUMP(data, len)
#endif

void hexDump(const void* data, size_t size) {
    const unsigned char* bytes = (const unsigned char*)data;
    for (size_t i = 0; i < size; i += 16) {
        printf("%06zx: ", i);
        for (size_t j = 0; j < 16; j++) {
            if (i + j < size) {
                printf("%02x ", bytes[i + j]);
            } else {
                printf("   ");
            }
            if (j == 7) printf(" ");
        }
        printf(" |");
        for (size_t j = 0; j < 16 && i + j < size; j++) {
            unsigned char c = bytes[i + j];
            printf("%c", (c >= 32 && c < 127) ? c : '.');
        }
        printf("|\n");
    }
}
7.2.2 Android端调试
kotlin 复制代码
// 网络调试工具类
object NetworkDebugger {
    private const val DEBUG = BuildConfig.DEBUG
    
    fun logSocketInfo(socket: Socket) {
        if (!DEBUG) return
        
        Log.d("NetworkDebug", """
            Socket信息:
            Local: ${socket.localAddress}:${socket.localPort}
            Remote: ${socket.inetAddress}:${socket.port}
            Connected: ${socket.isConnected}
            Closed: ${socket.isClosed}
            Timeout: ${socket.soTimeout}
            KeepAlive: ${socket.keepAlive}
            TCP_NODELAY: ${socket.tcpNoDelay}
        """.trimIndent())
    }
    
    fun logNetworkInfo(context: Context) {
        val connectivityManager = context.getSystemService(
            Context.CONNECTIVITY_SERVICE) as ConnectivityManager
        
        val network = connectivityManager.activeNetwork
        val caps = connectivityManager.getNetworkCapabilities(network)
        
        Log.d("NetworkDebug", """
            网络信息:
            有网络: ${caps != null}
            WiFi: ${caps?.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)}
            移动网络: ${caps?.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)}
            带宽: ${caps?.linkDownstreamBandwidthKbps}Kbps
        """.trimIndent())
    }
    
    fun startPacketCapture(context: Context) {
        // 使用tcpdump或PCAPdroid进行抓包
        // 需要root权限或VPNService
        Log.d("NetworkDebug", "开始抓包,保存到: ${context.filesDir}/capture.pcap")
    }
}

7.3 性能优化建议

  1. 网络层优化

    cpp 复制代码
    // 使用SO_RCVBUF和SO_SNDBUF调整缓冲区
    int bufSize = 256 * 1024; // 256KB
    setsockopt(socket, SOL_SOCKET, SO_RCVBUF, (char*)&bufSize, sizeof(bufSize));
    setsockopt(socket, SOL_SOCKET, SO_SNDBUF, (char*)&bufSize, sizeof(bufSize));
    
    // 禁用Nagle算法(减少延迟)
    int noDelay = 1;
    setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, (char*)&noDelay, sizeof(noDelay));
    
    // 启用TCP快速打开(TCP Fast Open)
    #ifdef TCP_FASTOPEN
    int qlen = 5;
    setsockopt(socket, IPPROTO_TCP, TCP_FASTOPEN, &qlen, sizeof(qlen));
    #endif
  2. Android端优化

    kotlin 复制代码
    // 使用连接池复用连接
    object ConnectionPool {
        private val pool = ConcurrentHashMap<String, Socket>()
        
        fun getConnection(host: String, port: Int): Socket {
            return pool.getOrPut("$host:$port") {
                Socket(host, port).apply {
                    keepAlive = true
                    soTimeout = 30000
                }
            }
        }
    }
    
    // 使用OkHttp替代原生Socket(更好的连接管理)
    val okHttpClient = OkHttpClient.Builder()
        .connectTimeout(5, TimeUnit.SECONDS)
        .readTimeout(30, TimeUnit.SECONDS)
        .writeTimeout(30, TimeUnit.SECONDS)
        .connectionPool(ConnectionPool(5, 5, TimeUnit.MINUTES))
        .build()
  3. 内存优化

    cpp 复制代码
    // 使用内存池减少碎片
    class MemoryPool {
    private:
        struct Block {
            void* data;
            size_t size;
            bool used;
        };
        std::vector<Block> blocks;
        
    public:
        void* allocate(size_t size) {
            // 查找空闲块或分配新块
            // ...
        }
        
        void deallocate(void* ptr) {
            // 标记块为空闲
            // ...
        }
    };

八、核心优化点(可选)

8.1 协议优化

8.1.1 二进制协议设计
cpp 复制代码
// protocol.h - 优化的二进制协议
#pragma pack(push, 1)

struct MessageHeader {
    uint32_t magic;          // 魔术字 0x48505354 "HPST"
    uint16_t version;        // 协议版本
    uint8_t  type;           // 消息类型
    uint32_t length;         // 数据长度
    uint32_t checksum;       // 校验和
    uint64_t timestamp;      // 时间戳
    uint32_t sequence;       // 序列号
};

enum MessageType {
    MSG_DISCOVER_REQUEST = 1,
    MSG_DISCOVER_RESPONSE,
    MSG_HEARTBEAT,
    MSG_TEXT,
    MSG_FILE_INFO,
    MSG_FILE_DATA,
    MSG_FILE_END,
    MSG_COMMAND,
    MSG_ACK,
    MSG_NACK
};

struct DiscoverRequest {
    char device_name[32];
    char device_type[16];
    char os_version[16];
    char app_version[16];
};

struct DiscoverResponse {
    uint32_t ip_address;
    uint16_t tcp_port;
    char     server_name[32];
};

struct FileInfo {
    char     file_name[256];
    uint64_t file_size;
    uint32_t chunk_size;
    char     md5[32];
};

#pragma pack(pop)

// 消息序列化/反序列化
class MessageSerializer {
public:
    static std::vector<uint8_t> serialize(const MessageHeader& header, 
                                         const void* data = nullptr) {
        std::vector<uint8_t> buffer(sizeof(MessageHeader));
        memcpy(buffer.data(), &header, sizeof(header));
        
        if (data && header.length > 0) {
            size_t oldSize = buffer.size();
            buffer.resize(oldSize + header.length);
            memcpy(buffer.data() + oldSize, data, header.length);
        }
        
        // 计算校验和
        uint32_t checksum = calculateChecksum(buffer.data() + 4, 
                                            buffer.size() - 4);
        ((MessageHeader*)buffer.data())->checksum = checksum;
        
        return buffer;
    }
    
    static bool deserialize(const uint8_t* data, size_t length,
                           MessageHeader& header, std::vector<uint8_t>& payload) {
        if (length < sizeof(MessageHeader)) return false;
        
        memcpy(&header, data, sizeof(header));
        
        // 验证魔术字
        if (header.magic != 0x48505354) return false;
        
        // 验证长度
        if (length != sizeof(MessageHeader) + header.length) return false;
        
        // 验证校验和
        uint32_t calculated = calculateChecksum(data + 4, length - 4);
        if (calculated != header.checksum) return false;
        
        // 提取负载
        if (header.length > 0) {
            payload.resize(header.length);
            memcpy(payload.data(), data + sizeof(header), header.length);
        }
        
        return true;
    }
    
private:
    static uint32_t calculateChecksum(const uint8_t* data, size_t length) {
        uint32_t sum = 0;
        for (size_t i = 0; i < length; i++) {
            sum = (sum << 5) - sum + data[i];
        }
        return sum;
    }
};
8.1.2 Protobuf协议定义
protobuf 复制代码
// hotspot.proto
syntax = "proto3";

package hotspot;

message DeviceInfo {
    string device_name = 1;
    string device_type = 2;
    string os_version = 3;
    string app_version = 4;
    string device_id = 5;
}

message DiscoverRequest {
    DeviceInfo device = 1;
    uint32 timestamp = 2;
    bytes nonce = 3;
}

message DiscoverResponse {
    string server_name = 1;
    string server_version = 2;
    uint32 ip_address = 3;
    uint32 tcp_port = 4;
    uint32 udp_port = 5;
    repeated Service services = 6;
}

message Service {
    string name = 1;
    uint32 port = 2;
    string description = 3;
}

message TextMessage {
    string sender = 1;
    string content = 2;
    uint64 timestamp = 3;
    string message_id = 4;
}

message FileTransfer {
    string file_name = 1;
    uint64 file_size = 2;
    string file_hash = 3;
    uint32 chunk_size = 4;
    uint32 total_chunks = 5;
}

message FileChunk {
    string transfer_id = 1;
    uint32 chunk_index = 2;
    bytes data = 3;
    bool is_last = 4;
}

message Heartbeat {
    uint64 timestamp = 1;
    uint32 sequence = 2;
    DeviceStatus status = 3;
}

message DeviceStatus {
    float battery_level = 1;
    NetworkInfo network = 2;
    MemoryInfo memory = 3;
}

message NetworkInfo {
    string ssid = 1;
    int32 rssi = 2;
    string ip_address = 3;
}

message MemoryInfo {
    uint64 total_memory = 1;
    uint64 free_memory = 2;
}

message HotspotMessage {
    oneof payload {
        DiscoverRequest discover_req = 1;
        DiscoverResponse discover_resp = 2;
        TextMessage text_msg = 3;
        FileTransfer file_transfer = 4;
        FileChunk file_chunk = 5;
        Heartbeat heartbeat = 6;
    }
}

8.2 安全增强

8.2.1 TLS加密通信
cpp 复制代码
// tls_wrapper.h - TLS/SSL封装
#ifdef USE_OPENSSL
#include <openssl/ssl.h>
#include <openssl/err.h>

class TLSSocket {
public:
    TLSSocket() : ctx(nullptr), ssl(nullptr) {
        SSL_library_init();
        SSL_load_error_strings();
        OpenSSL_add_all_algorithms();
    }
    
    ~TLSSocket() {
        if (ssl) {
            SSL_shutdown(ssl);
            SSL_free(ssl);
        }
        if (ctx) {
            SSL_CTX_free(ctx);
        }
    }
    
    bool initServer(const std::string& certFile, 
                   const std::string& keyFile) {
        ctx = SSL_CTX_new(TLS_server_method());
        if (!ctx) return false;
        
        // 加载证书和私钥
        if (SSL_CTX_use_certificate_file(ctx, certFile.c_str(), 
                                        SSL_FILETYPE_PEM) <= 0) {
            return false;
        }
        
        if (SSL_CTX_use_PrivateKey_file(ctx, keyFile.c_str(), 
                                       SSL_FILETYPE_PEM) <= 0) {
            return false;
        }
        
        // 验证私钥
        if (!SSL_CTX_check_private_key(ctx)) {
            return false;
        }
        
        return true;
    }
    
    bool accept(SOCKET clientSocket) {
        ssl = SSL_new(ctx);
        if (!ssl) return false;
        
        SSL_set_fd(ssl, clientSocket);
        return SSL_accept(ssl) == 1;
    }
    
    int send(const void* buffer, size_t length) {
        return SSL_write(ssl, buffer, length);
    }
    
    int receive(void* buffer, size_t length) {
        return SSL_read(ssl, buffer, length);
    }
    
private:
    SSL_CTX* ctx;
    SSL* ssl;
};
#endif
8.2.2 端到端加密
kotlin 复制代码
// EndToEndEncryption.kt
object EndToEndEncryption {
    
    // 使用ECDH进行密钥交换
    fun generateKeyPair(): KeyPair {
        val keyPairGenerator = KeyPairGenerator.getInstance("EC")
        keyPairGenerator.initialize(256)
        return keyPairGenerator.generateKeyPair()
    }
    
    fun generateSharedSecret(privateKey: PrivateKey, 
                            publicKey: PublicKey): ByteArray {
        val keyAgreement = KeyAgreement.getInstance("ECDH")
        keyAgreement.init(privateKey)
        keyAgreement.doPhase(publicKey, true)
        return keyAgreement.generateSecret()
    }
    
    // 使用AES-GCM加密
    fun encrypt(data: ByteArray, key: ByteArray): ByteArray {
        val cipher = Cipher.getInstance("AES/GCM/NoPadding")
        val secretKey = SecretKeySpec(key, "AES")
        val iv = ByteArray(12).apply {
            SecureRandom().nextBytes(this)
        }
        
        val parameterSpec = GCMParameterSpec(128, iv)
        cipher.init(Cipher.ENCRYPT_MODE, secretKey, parameterSpec)
        
        val cipherText = cipher.doFinal(data)
        return iv + cipherText
    }
    
    fun decrypt(encrypted: ByteArray, key: ByteArray): ByteArray {
        val cipher = Cipher.getInstance("AES/GCM/NoPadding")
        val secretKey = SecretKeySpec(key, "AES")
        
        val iv = encrypted.copyOfRange(0, 12)
        val cipherText = encrypted.copyOfRange(12, encrypted.size)
        
        val parameterSpec = GCMParameterSpec(128, iv)
        cipher.init(Cipher.DECRYPT_MODE, secretKey, parameterSpec)
        
        return cipher.doFinal(cipherText)
    }
    
    // 数字签名
    fun sign(data: ByteArray, privateKey: PrivateKey): ByteArray {
        val signature = Signature.getInstance("SHA256withECDSA")
        signature.initSign(privateKey)
        signature.update(data)
        return signature.sign()
    }
    
    fun verify(data: ByteArray, signature: ByteArray, 
              publicKey: PublicKey): Boolean {
        val verifier = Signature.getInstance("SHA256withECDSA")
        verifier.initVerify(publicKey)
        verifier.update(data)
        return verifier.verify(signature)
    }
}

8.3 多平台支持

8.3.1 跨平台网络库封装
cpp 复制代码
// platform_network.h
#ifdef _WIN32
    #include <winsock2.h>
    #include <ws2tcpip.h>
    #pragma comment(lib, "ws2_32.lib")
    
    typedef SOCKET socket_t;
    #define INVALID_SOCKET_VALUE INVALID_SOCKET
    #define SOCKET_ERROR_VALUE SOCKET_ERROR
    
    inline void close_socket(socket_t sock) {
        closesocket(sock);
    }
    
    inline int get_last_error() {
        return WSAGetLastError();
    }
    
    inline void init_network() {
        WSADATA wsaData;
        WSAStartup(MAKEWORD(2, 2), &wsaData);
    }
    
    inline void cleanup_network() {
        WSACleanup();
    }
    
#else // Linux/macOS
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <unistd.h>
    #include <errno.h>
    
    typedef int socket_t;
    #define INVALID_SOCKET_VALUE (-1)
    #define SOCKET_ERROR_VALUE (-1)
    
    inline void close_socket(socket_t sock) {
        close(sock);
    }
    
    inline int get_last_error() {
        return errno;
    }
    
    inline void init_network() {
        // Linux/macOS不需要特殊初始化
    }
    
    inline void cleanup_network() {
        // Linux/macOS不需要特殊清理
    }
#endif

// 统一的Socket类
class PlatformSocket {
public:
    PlatformSocket() : sock(INVALID_SOCKET_VALUE) {
        init_network();
    }
    
    ~PlatformSocket() {
        close();
    }
    
    bool create(int domain, int type, int protocol) {
        sock = socket(domain, type, protocol);
        return sock != INVALID_SOCKET_VALUE;
    }
    
    bool bind(const std::string& ip, uint16_t port) {
        sockaddr_in addr{};
        addr.sin_family = AF_INET;
        inet_pton(AF_INET, ip.c_str(), &addr.sin_addr);
        addr.sin_port = htons(port);
        
        return ::bind(sock, (sockaddr*)&addr, sizeof(addr)) != SOCKET_ERROR_VALUE;
    }
    
    bool connect(const std::string& ip, uint16_t port) {
        sockaddr_in addr{};
        addr.sin_family = AF_INET;
        inet_pton(AF_INET, ip.c_str(), &addr.sin_addr);
        addr.sin_port = htons(port);
        
        return ::connect(sock, (sockaddr*)&addr, sizeof(addr)) != SOCKET_ERROR_VALUE;
    }
    
    void close() {
        if (sock != INVALID_SOCKET_VALUE) {
            close_socket(sock);
            sock = INVALID_SOCKET_VALUE;
        }
    }
    
private:
    socket_t sock;
};

九、总结

本文详细介绍了基于PC热点的手动开启方案,结合UDP广播自动发现和TCP可靠通信的完整实现。通过本文的指导,读者可以:

9.1 核心技术要点总结

  1. 架构设计:采用分层架构,分离网络层、协议层和应用层,提高代码可维护性。

  2. 自动发现机制:UDP广播+TCP连接的组合,解决了设备自动发现的难题。

  3. 可靠性保障:心跳机制、自动重连、超时处理等多重保障措施。

  4. 性能优化:缓冲区管理、连接复用、协议优化等提升传输效率。

  5. 安全考虑:支持TLS加密、端到端加密、数字签名等安全特性。

  6. 跨平台支持:通过抽象层实现Windows、Linux、macOS多平台支持。

9.2 实际应用价值

  1. 物联网设备通信:适用于智能家居、工业控制等场景。

  2. 移动开发调试:开发者无需配置网络即可调试设备。

  3. 文件快速传输:替代蓝牙,提供更快的文件传输速度。

  4. 游戏联机:局域网游戏的多设备通信。

  5. 教育演示:课堂教学中的设备互联演示。

9.3 未来扩展方向

  1. P2P通信:引入NAT穿透技术,支持外网直连。

  2. 多播优化:使用组播替代广播,减少网络负担。

  3. QUIC协议:采用HTTP/3的QUIC协议,提高连接建立速度。

  4. WebRTC集成:支持浏览器端的直接通信。

  5. AI优化:使用机器学习预测网络状况,动态调整参数。

9.4 代码获取与贡献

本文完整代码已开源,欢迎Star和贡献:

9.5 致谢

感谢所有为本文提供反馈和建议的开发者。特别感谢CSDN社区的技术支持,以及开源社区提供的优秀工具和库。


版权声明:本文采用CC BY-SA 4.0协议,转载请注明出处。

作者 :通信技术开发者
日期 :2025-12-16
版本 :v1.0
联系方式:example@email.com


扩展阅读

  1. Windows Socket编程完全指南
  2. Android网络编程最佳实践
  3. TCP/IP协议详解
  4. 网络安全入门到精通

相关项目

  1. 局域网文件传输工具
  2. 多平台远程控制软件
  3. 物联网通信框架

希望本文对您的项目开发有所帮助,欢迎在评论区交流讨论!

相关推荐
罗湖老棍子7 小时前
【例3-3】医院设置(信息学奥赛一本通- P1338)
数据结构·c++·算法·
不想写笔记7 小时前
算法 C语言 冒泡排序
c语言·笔记·算法·排序算法
了一梨7 小时前
网络编程:UDP Socket
linux·网络协议·udp
xinxinhenmeihao7 小时前
长效住宅静态IP有什么好处?是选择动态IP还是静态IP好?
服务器·网络·tcp/ip
xu_yule7 小时前
算法基础-路径类dp
算法
车载测试工程师7 小时前
CAPL学习-SOME/IP交互层-值处理类函数2
学习·tcp/ip·以太网·capl·canoe
车载测试工程师7 小时前
CAPL学习-SOME/IP交互层-值处理类函数1
学习·tcp/ip·交互·以太网·capl·canoe
智驱力人工智能7 小时前
从项目管理视角 拆解景区无人机人群密度分析系统的构建逻辑 无人机人员密度检测 无人机人群密度检测系统价格 低空人群密度统计AI优化方案
人工智能·深度学习·算法·安全·无人机·边缘计算
ChristXlx7 小时前
Linux安装MongoDB(虚拟机适用)
linux·mongodb·postgresql