Linux C/C++ Socket 编程-Linux C语言 socket 编程 server 端

// server.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>    // 提供 close、read 和 write (这里通过 send 间接使用,因为 send 是 write 的一个更高级别的封装)
#include <arpa/inet.h>   // 提供了用于网络地址转换的函数声明,如将点分十进制格式的 IP 地址转换为网络字节序,以及将端口号从主机字节序转换为网络字节序。

#define PORT 12000    // socket 绑定的端口好
#define BUFFER_SIZE 1024       // 缓存大小

int main() {
    int server_fd, new_socket;
    struct sockaddr_in address;     // 结构体,用于存储 IPv4 地址和端口号的信息。
    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) {
    /*
    AF_INET:指定地址族为 IPv4。
    SOCK_STREAM:指定套接字类型为 TCP(面向连接的字节流)。
    0:指定协议为 0,通常对于 SOCK_STREAM 和 AF_INET,这个参数为 0,意味着使用 TCP。
    */
        perror("socket failed");
        exit(EXIT_FAILURE);
    }

    // 绑定socket到端口
    if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) {
        perror("setsockopt");
        exit(EXIT_FAILURE);
    }
    address.sin_family = AF_INET; // IPv4
    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);
    }

    // 接受连接
    while (1) {
        printf("等待连接...\n");
        if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) {
            perror("accept");
            exit(EXIT_FAILURE);
        }

        // 接收数据
        read(new_socket, buffer, BUFFER_SIZE);
        printf("收到消息: %s\n", buffer);

        // 发送数据
        send(new_socket, hello, strlen(hello), 0);
        printf("欢迎消息已发送\n");

        // 关闭当前连接
        close(new_socket);
    }

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

编译:gcc -o server server.c

setsockopt()

#include <sys/socket.h>
int setsockopt(int socket, int level, int option_name,
    const void *option_value, socklen_t option_len);
    if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) {
        perror("setsockopt");
        exit(EXIT_FAILURE);
    }

setsockopt() 函数,用于设置套接字的选项。是在创建一个服务器套接字时,配置套接字的一些行为或属性。SO_REUSEADDR 选项的设置允许在套接字关闭后,立即重用相同的地址(IP 和端口),而不必等到操作系统回收该端口。

level:指定选项所在的协议层,通常是 SOL_SOCKET,表示设置的是套接字级别的选项。

optval:指向一个存储选项值的内存区域。这个值会根据不同的选项而变化,通常是一个整数或布尔值。

optlenoptval 指向的内存区域的大小(字节数)。

int opt = 1; opt 是 SO_REUSEADDR 选项的值通常是 1(启用)或 0(禁用)。sizeof(opt) 用来确定 opt 变量的大小。

setsockopt() 返回值:设置成功返回 0,否则返回 -1 。

address.sin_addr.s_addr = INADDR_ANY; INADDR_ANY 是一个特殊的常量,值是 0.0.0.0,它代表任何可用的网络接口地址(所有的 IPv4 地址),通常用于绑定套接字到所有本地可用的网络接口,可以使得服务器程序更灵活地接受来自不同网络接口的请求。

bind()

#include <sys/socket.h>
int bind(int socket, const struct sockaddr *address,
    socklen_t address_len);

返回值:绑定成功成功返回 0,否则返回 -1 。

listen()

#include <sys/socket.h>
int listen(int socket, int backlog);

返回值:监听成功返回 0,否则返回 -1 。

accept()

#include <sys/socket.h>
int accept(int socket, struct sockaddr *restrict address,
    socklen_t *restrict address_len);

返回值:接受失败返回 -1,成功则返回接受套接字的非负文件描述。

read()

从套接字接收缓存中读取收到的数据。

#include <unistd.h>
ssize_t read(int fildes, void *buf, size_t nbyte);

成功完成后,将返回一个非负整数,表示实际读取的字节数。否则,函数将返回 -1 并设置 errno 以指示错误。

server 端 C++

// server.cpp
#include <iostream>
#include <cstring>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>

#define PORT 12000     // 端口
#define BUFFER_SIZE 1024

class Server {
public:
    Server() {
        server_fd = socket(AF_INET, SOCK_STREAM, 0);
        if (server_fd < 0) {
            std::cerr << "Socket creation failed" << std::endl;
            exit(EXIT_FAILURE);
        }

        sockaddr_in address;
        int addrlen = sizeof(address);
        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) {
            std::cerr << "Bind failed" << std::endl;
            close(server_fd);
            exit(EXIT_FAILURE);
        }

        if (listen(server_fd, 3) < 0) {
            std::cerr << "Listen failed" << std::endl;
            close(server_fd);
            exit(EXIT_FAILURE);
        }

        std::cout << "Server is listening on port " << PORT << std::endl;
    }

    ~Server() {
        close(server_fd);
    }

    void acceptConnection() {
        sockaddr_in address;
        int addrlen = sizeof(address);
        int new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen);
        if (new_socket < 0) {
            std::cerr << "Accept failed" << std::endl;
            return;
        }

        char buffer[BUFFER_SIZE];
        int valread = read(new_socket, buffer, BUFFER_SIZE);
        std::cout << "Message from client: " << buffer << std::endl;

        const char *response = "Hello from server";
        send(new_socket, response, strlen(response), 0);
        std::cout << "Response sent to client" << std::endl;

        close(new_socket);
    }

private:
    int server_fd;
};

int main() {
    Server server;
    while (true) {
        server.acceptConnection();
    }
    return 0;
}

编译:g++ -o server server.cpp

上一篇:数据结构-查找以及效率分析


下一篇:Unity插件-Smart Inspector 免费的,接近虚幻引擎的蓝图Tab管理