测试_第27章_网络编程.cpp

← 测试总览 · 目录

编译运行:clang++ -std=c++26 -Wall -Wextra -pthread 测试_第27章_网络编程.cpp -o t && ./t(需先 cd 测试/

// 第27章测试:网络编程(本机端到端 TCP 回显)
// 说明:在同一进程内启动服务器线程和客户端线程,
// 用 127.0.0.1 随机端口完成完整通信验证。
// Termux 下系统调用可用;若沙箱禁止网络,请手动运行
// 书中的 server.cpp / client.cpp 验证。
#include <print>
#include <thread>
#include <string>
#include <string_view>
#include <cstring>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>

int failures = 0;
#define CHECK(expr)                                                         \
    do {                                                                    \
        if (!(expr)) {                                                      \
            ++failures;                                                     \
            std::println("FAIL 第{}行: {}", __LINE__, #expr);              \
        }                                                                   \
    } while (0)

int start_server(int port, std::string& received) {
    int fd = ::socket(AF_INET, SOCK_STREAM, 0);
    if (fd < 0) return -1;
    int opt = 1;
    ::setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
    sockaddr_in addr{};
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = htonl(INADDR_ANY);
    addr.sin_port = htons(port);
    if (::bind(fd, (sockaddr*)&addr, sizeof(addr)) < 0) { ::close(fd); return -1; }
    if (::listen(fd, 4) < 0) { ::close(fd); return -1; }

    // 服务器线程:接受一次连接,回显,退出
    std::thread([fd, &received] {
        int client = ::accept(fd, nullptr, nullptr);
        if (client < 0) return;
        char buf[1024];
        ssize_t n = ::recv(client, buf, sizeof(buf), 0);
        if (n > 0) {
            received.assign(buf, n);
            ::send(client, buf, n, 0);          // 回显
        }
        ::close(client);
    }).detach();

    return fd;
}

int main() {
    // 服务器监听随机端口(端口 0 = 系统分配,这里用固定 18926)
    const int PORT = 18926;
    std::string received;
    int server_fd = start_server(PORT, received);
    CHECK(server_fd >= 0);
    if (server_fd < 0) { std::println("服务器启动失败(端口被占用?)"); return 1; }

    // 客户端连接并发送
    int cfd = ::socket(AF_INET, SOCK_STREAM, 0);
    CHECK(cfd >= 0);
    sockaddr_in addr{};
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    addr.sin_port = htons(PORT);

    bool connected = false;
    for (int attempt = 0; attempt < 50 && !connected; ++attempt) {
        if (::connect(cfd, (sockaddr*)&addr, sizeof(addr)) == 0) connected = true;
        else std::this_thread::sleep_for(std::chrono::milliseconds(20));
    }
    CHECK(connected);

    const char* msg = "你好,服务器!";
    CHECK(::send(cfd, msg, (int)std::strlen(msg), 0) > 0);

    char buf[1024] = {};
    ssize_t n = ::recv(cfd, buf, sizeof(buf), 0);
    CHECK(n > 0);
    std::string reply(buf, n);
    std::println("客户端收到: {}", reply);

    // 等待服务器线程处理完
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
    CHECK(received == "你好,服务器!");      // 服务器收到的内容
    CHECK(reply == "你好,服务器!");         // 回显内容

    ::close(cfd);
    ::close(server_fd);

    if (failures == 0) std::println("全部通过");
    return failures;
}