C++实现Socket通信的简易demo

122 阅读3分钟

使用Socket通信实现,【客户端】每隔1s从【服务端】请求最新的时间戳

Server端

#include <iostream>            // 包含输入输出流库
#include <cstring>             // 包含C字符串库,用于字符串操作
#include <sys/socket.h>        // 包含套接字编程的库
#include <netinet/in.h>        // 包含Internet协议家族的定义
#include <unistd.h>            // 包含UNIX标准函数定义
#include <ctime>               // 包含时间相关的库

#define PORT 8080              // 定义服务器监听的端口号

int main() {
    int server_fd, new_socket; // 定义服务器文件描述符和新连接的套接字
    struct sockaddr_in address; // 定义用于存储地址信息的结构体
    int opt = 1;               // 选项值,用于设置套接字选项
    int addrlen = sizeof(address); // 地址长度
    char buffer[1024] = {0};   // 缓存区,用于存储从客户端接收的数据

    // 创建套接字文件描述符
    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
        perror("socket failed"); // 打印错误信息
        exit(EXIT_FAILURE);     // 退出程序
    }

    // 设置套接字选项,允许地址重用
    if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) {
        perror("setsockopt");// 打印错误信息
        exit(EXIT_FAILURE);
    }
    if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEPORT, &opt, sizeof(opt)) < 0) {
        perror("setsockopt");
        exit(EXIT_FAILURE);
    }

    address.sin_family = AF_INET; // 地址族为IPv4
    address.sin_addr.s_addr = INADDR_ANY; // 监听所有本地地址
    address.sin_port = htons(PORT); // 设置端口,转换为网络字节序

    // 将套接字绑定到指定的IP地址和端口上
    if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
        perror("bind failed");  // 打印错误信息
        exit(EXIT_FAILURE);     // 退出程序
    }

    // 使套接字进入监听状态,等待客户端连接
    if (listen(server_fd, 3) < 0) {
        perror("listen");       // 打印错误信息
        exit(EXIT_FAILURE);     // 退出程序
    }

    // 接受客户端连接请求
    if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) {
        perror("accept");       // 打印错误信息
        exit(EXIT_FAILURE);     // 退出程序
    }

    // 无限循环,处理客户端请求
    while (true) {
        // 从客户端读取数据
        int valread = read(new_socket, buffer, 1024);
        if (valread <= 0) {
            break; // 如果客户端关闭连接或发生错误,退出循环
        }
        std::cout << "Message from client: " << buffer << std::endl; // 输出收到的消息

        // 获取当前时间戳
        std::time_t now = std::time(nullptr);
        std::string timestamp = std::to_string(now); // 将时间戳转换为字符串

        // 发送时间戳到客户端
        send(new_socket, timestamp.c_str(), timestamp.size(), 0);
    }

    // 关闭客户端套接字
    close(new_socket);
    // 关闭服务器套接字
    close(server_fd);

    return 0; // 程序正常结束
}

客户端

#include <iostream>            // 包含输入输出流库
#include <cstring>             // 包含C字符串库,用于字符串操作
#include <sys/socket.h>        // 包含套接字编程的库
#include <arpa/inet.h>         // 包含Internet地址库
#include <unistd.h>            // 包含UNIX标准函数定义
#include <chrono>              // 包含时间相关的库,用于延时
#include <thread>              // 包含线程库,用于实现延时功能

#define PORT 8080              // 定义客户端要连接的服务器端口

int main() {
    int sock = 0;              // 定义套接字文件描述符
    struct sockaddr_in serv_addr; // 定义用于存储服务器地址的结构体
    char buffer[1024] = {0};   // 缓存区,用于存储从服务器接收的数据

    // 创建套接字
    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        std::cout << "Socket creation error" << std::endl; // 套接字创建错误信息
        return -1;         // 返回错误
    }

    serv_addr.sin_family = AF_INET; // 设置地址族为IPv4
    serv_addr.sin_port = htons(PORT); // 设置端口,转换为网络字节序

    // 将IP地址从文本格式转换为二进制格式
    if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0) {
        std::cout << "Invalid address/ Address not supported" << std::endl; // 地址无效或不支持
        return -1;         // 返回错误
    }

    // 连接到服务器
    if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
        std::cout << "Connection Failed" << std::endl; // 连接失败信息
        return -1;         // 返回错误
    }

    // 无限循环,每秒请求一次服务器
    while (true) {
        // 向服务器发送请求消息
        const char* message = "Requesting timestamp";
        send(sock, message, strlen(message), 0);

        // 从服务器读取响应
        int valread = read(sock, buffer, 1024);
        if (valread > 0) {
            buffer[valread] = '\0'; // 确保字符串以null结尾
            std::cout << "Timestamp from server: " << buffer << std::endl; // 输出接收到的时间戳
        }

        // 每隔1秒请求一次
        std::this_thread::sleep_for(std::chrono::seconds(1));
    }

    // 关闭套接字
    close(sock);

    return 0; // 程序正常结束
}