• 常用I/O复用模型 --> 一、单线程Accept(无IO复用)


    一、前言

    单线程Accept(无IO复用)是网络最基础的模型,常供学习使用。

    下面是我的GitHub仓库,记录笔者从0开始到完整的高性能服务器构建过程,如有帮助给个star吧!
    TinyWebServer

    二、I/O复用中最基础的知识点

    1、流

    1. 定义: 可以进行I/O操作的内核对象,包括文件、管道、套接字
    2. 流的入口: 文件描述符(fd)

    2、I/O操作

    对流的读写操作

    3、阻塞等待

    1. 定义: 在阻塞I/O模式下,I/O操作会导致进程或线程阻塞,直到I/O操作完成。
    2. 优点: 不占用CPU时间。
    3. 缺点: 同一阻塞,如果多个I/O同时完成,只能处理一个流的阻塞监听。

    4、非阻塞,忙轮询

    1. 定义: 忙轮询是一种等待条件满足的方式,其中进程或线程不断地检查条件是否满足,而不进行任何休眠或让出CPU。
    2. 缺点: 占用CPU,系统资源

    5、多路I/O复用

    1. 定义: 既能阻塞等待不浪费资源,也能够同一时刻监听多个I/O请求状态。

    这个就是用多路I/O复用的原因。

    三、单线程Accept(无IO复用)

    这个就是最基础的阻塞等待模型。

    • INADDR_ANY: 泛指本机的意思,也就是表示本机的所有IP
    • htons: 主机字节序转化到二进制形式
    • inet_pton: 转换IPv4地址从文本到二进制形式
      单Accept(无IO复用)

    1、服务端

    绑定本地ip,监听本地端口

    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    using namespace std;
    const int PORT = 8080;
        
    int main(){
        int server_fd, new_socket;
    
        // socket()
        if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
            cerr << "Socket 创建失败" << endl;
            return -1;
        }
    
        sockaddr_in address;
        int addrlen = sizeof address;
        address.sin_family = AF_INET;
        address.sin_addr.s_addr = INADDR_ANY;
        address.sin_port = htons(PORT) ;
    
        // bind()
        if (bind(server_fd, (sockaddr*)&address, addrlen) < 0) {
            cerr << "Bind 失败" << endl;
            return -1;
        }
    
        // listen()
        if (listen(server_fd, 3) < 0){
            cerr << "Listen failed" << endl;
            return -1;
        } 
        cout << "服务器监听端口:" << PORT << endl;
    
        // accept()
        if ((new_socket = accept(server_fd, (sockaddr*)&address, (socklen_t*)&addrlen)) < 0) {
            cerr << "Accept 失败" << endl;
            return -1;
        }
    
        // I/O操作
        string buffer(1024, 0);
        int recv_len = recv(new_socket, buffer.data(), buffer.size(), 0);
        cout << "从客户端接收到的消息:" << buffer.substr(0, recv_len) << endl;
    
        string msg = "file.txt";
        send(new_socket, msg.data(), msg.size(), 0);
        cout << "向客户端发送消息:" << msg << endl;
    
        // close()
        close(new_socket);
        close(server_fd);
        return 0;
    }
    

    2、客户端

    绑定服务端ip,监听服务端端口

    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    using namespace std;
    const int PORT = 8080;
    
    int main(){
        // socket()
        int sock = socket(AF_INET, SOCK_STREAM, 0);
        if (sock < 0) {
            cerr << "Socket 创建失败" << endl;
            return -1;
        }
    
        sockaddr_in serv_addr;
        serv_addr.sin_family = AF_INET;
        serv_addr.sin_port = htons(PORT);
    
        if (!inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr)) {
            cerr << "地址非法/ 地址不支持" << endl;
            return -1;
        }
    
        // 连接
        if (connect(sock, (sockaddr*)&serv_addr, sizeof serv_addr) < 0) {
            cerr << "连接失败" << endl;
            return -1;
        }
    
        // I/O操作
        string msg = "请求文件file.txt";
        send(sock, msg.data(), msg.size(), 0);
        cout << "向服务端发送消息:" << msg << endl;
    
        string buffer(1024, 0);
        int recv_len = recv(sock, buffer.data(), buffer.size(), 0);
        cout << "从服务器接收消息:" << buffer.substr(0, recv_len) << endl;
    
        // close()
        close(sock);
        return 0;
    }
    
  • 相关阅读:
    RabbitMQ-高级篇-黑马程序员
    RFID智能锁控系统在物流安全运输中的应用与效益分析
    前缀和+差分+ 树状数组
    【Spark】Spark 高频面试题英语版(1)
    深入理解java虚拟机:虚拟机类加载机制(2)
    Flink - 最新 StateBackend 状态后端详解
    Python中的Super详解
    2024年最新测评,6款好用的在线代码编辑器推荐
    力扣-240.搜索二维矩阵(2)
    AVL树的插入详解
  • 原文地址:https://blog.csdn.net/Ten_years_star/article/details/140395553