云计算百科
云计算领域专业知识百科平台

打造自己的 C++ Socket 服务器:手把手教程

Socket 服务器技术文档

1. 概述

本文档描述了一个基于 C++ 的简单 TCP socket 服务器的实现和用法。该服务器监听指定的端口,接受客户端连接,读取客户端发送的消息,并向客户端发送一个固定的响应消息。

2. 环境要求

  • C++ 编译器,支持 C++11 或更高版本
  • POSIX 兼容操作系统
  • 支持 POSIX socket API 的库

3. 编译和运行

6. 后续改进

  • 将服务器代码保存为一个名为 server.cpp 的文件。
  • 使用以下命令编译代码: g++ server.cpp -o server
  • 运行服务器:
  • ./server

    4. 服务器实现

    4.1 头文件

    #include <iostream>
    #include <cstring>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <unistd.h>

    这些头文件分别用于输入输出流、字符串操作、socket 编程、网络地址结构和 UNIX 标准函数。

    4.2 定义端口号和缓冲区大小

    #define PORT 8080
    #define BUFFER_SIZE 1024

    PORT 定义了服务器监听的端口号,BUFFER_SIZE 定义了用于读取和发送数据的缓冲区大小。

    4.3 主函数

    int main() {
    // …
    }

    主函数是程序的入口点,包含了服务器的主要逻辑。

    4.4 创建 socket

    int server_fd, new_socket;
    server_fd = socket(AF_INET, SOCK_STREAM, 0);

    创建一个 socket 文件描述符 server_fd,用于监听客户端连接。AF_INET 表示 IPv4 地址族,SOCK_STREAM 表示 TCP 流套接字。

    4.5 绑定地址和端口

    struct sockaddr_in address;
    bind(server_fd, (struct sockaddr*)&address, sizeof(address));

    将 socket 绑定到本地地址和端口。

    4.6 监听连接

    listen(server_fd, 3);

    开始监听是否有客户端连接。第二个参数 3 表示最大连接数。

    4.7 接受连接

    new_socket = accept(server_fd, (struct sockaddr*)&address, (socklen_t*)&addrlen);

    接受客户端的连接,并返回一个新的 socket 文件描述符 new_socket。

    4.8 读取和发送数据

    read(new_socket, buffer, BUFFER_SIZE);
    send(new_socket, hello, strlen(hello), 0);

    从客户端读取数据到缓冲区,并向客户端发送固定的响应消息。

    4.9 关闭 socket

    close(server_fd);

    关闭服务器 socket,释放资源。

    5. 注意事项

  • 本示例代码没有进行错误检查和异常处理,这在实际应用中是非常重要的。
  • 服务器只能同时处理一个客户端连接,不支持并发。
  • 服务器在发送响应消息后立即关闭连接,不进行持续通信。
  • 添加错误检查和异常处理。
  • 使用多线程或多进程支持并发连接。
  • 实现完整的客户端-服务器通信协议。 #include <iostream>
    #include <cstring>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <unistd.h>

    #define PORT 8080
    #define BUFFER_SIZE 1024

    int main() {
    int server_fd, new_socket;
    struct sockaddr_in address;
    int opt = 1;
    int addrlen = sizeof(address);
    char buffer[BUFFER_SIZE] = {0};
    const char* hello = "Hello from server";

    // 创建 socket 文件描述符
    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
    perror("socket failed");
    exit(EXIT_FAILURE);
    }

    // 绑定 socket 到地址和端口
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port = htons(PORT);

    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);
    }

    // 读取数据
    read(new_socket, buffer, BUFFER_SIZE);
    std::cout << "Message from client: " << buffer << std::endl;

    // 发送数据
    send(new_socket, hello, strlen(hello), 0);
    std::cout << "Hello message sent\\n";

    // 关闭 socket
    close(server_fd);
    return 0;
    }

    几个问题1.sockfd是什么?答:

    在 socket 编程中,sockfd 是一个术语,通常用于指代一个 socket 的文件描述符。在 Unix-like 系统中,几乎所有的 I/O 操作都是通过文件描述符进行的,包括网络通信。文件描述符是一个非负整数,它是内核为了高效管理已打开的文件或其他 I/O 资源(如 socket、管道、设备等)而提供的一个抽象句柄。

    当你创建一个 socket 时,系统会返回一个文件描述符,这个文件描述符就被称为 sockfd。之后,你就可以使用这个文件描述符来进行各种 socket 操作,比如绑定地址(bind)、监听连接(listen)、接受连接(accept)、读取数据(read)、发送数据(write 或 send)、关闭 socket(close)等。

    例如,在下面的代码中,socket 函数创建了一个新的 socket,并返回了一个文件描述符,这个描述符被存储在变量 sockfd 中:

    int sockfd = socket(AF_INET, SOCK_STREAM, 0);

    在这里,AF_INET 指定了地址族为 IPv4,SOCK_STREAM 指定了 socket 类型为 TCP 流套接字。如果 socket 调用成功,sockfd 将是一个有效的文件描述符,用于后续的 socket 操作。如果调用失败,sockfd 将被设置为一个特定的错误值(通常是 -1),并且可以通过查看 errno 变量来获取失败的原因。

    我们可以用一个类比来通俗易懂地解释 sockfd。

    想象一下,你的电脑是一个大型的邮局,而你想通过邮局发送和接收信件。在邮局中,每个信箱都有一个唯一的编号,这个编号就像是文件描述符。当你创建一个 socket 时,就像是你在邮局申请了一个新的信箱,邮局会给你一个编号(即 sockfd),这样你就可以通过这个编号来发送和接收信件了。

    当你想发送一封信时,你会把信放入对应编号的信箱中,然后邮局会帮你把信发送出去。同样地,当你创建了一个 socket 并获得了 sockfd,你就可以使用这个 sockfd 来进行网络通信,比如发送数据(send)和接收数据(recv)。

    当你不再需要这个信箱时,你可以通知邮局回收这个信箱,这样其他人就可以使用这个编号了。在 socket 编程中,当你完成所有的通信任务后,你需要关闭 socket,释放 sockfd,这样系统就可以重新使用这个编号了。

    所以,sockfd 就像是邮局信箱的编号,它帮助你管理和操作网络通信。

  • 赞(0)
    未经允许不得转载:网硕互联帮助中心 » 打造自己的 C++ Socket 服务器:手把手教程
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!