• linux高性能服务器编程第六章高级IO函数 (3)


    splice函数 用于在两个文件名描述符之间移动数据, 0拷贝操作

    #include <fcntl.h>
    // fd_in 为文件描述符, 如果为管道文件描述符则 off_in必须为NULL, 否则为读取开始偏移位置
    // len为指定移动的数据长度, flags参数控制数据如何移动.
    // - SPLICE_F_NONBLOCK 非阻塞splice操作, 但会受文件描述符自身的阻塞
    // - SPLICE_F_MORE 给内核一个提示, 后续的splice调用将读取更多的数据???????
    ssize_t splice(int fd_in, loff_t* off_in, int fd_out, loff_t* off_out, size_t len, unsigned int flags);
    
    // 使用splice函数  实现echo服务器
    int main(int argc, char* argv[])
    {
        if (argc <= 2)
        {
            printf("the parmerters is wrong\n");
            exit(errno);
        }
        char *ip = argv[1];
    
        int port = atoi(argv[2]);
        printf("the port is %d the ip is %s\n", port, ip);
    
        int sockfd = socket(PF_INET, SOCK_STREAM, 0);
        assert(sockfd >= 0);
    
        struct sockaddr_in address{};
        address.sin_family = AF_INET;
        address.sin_port = htons(port);
        inet_pton(AF_INET, ip, &address.sin_addr);
    
        int ret = bind(sockfd, (sockaddr*)&address, sizeof(address));
        assert(ret != -1);
    
        ret = listen(sockfd, 5);
    
        int clientfd{};
        sockaddr_in client_address{};
        socklen_t client_addrlen = sizeof(client_address);
    
        clientfd = accept(sockfd, (sockaddr*)&client_address, &client_addrlen);
        if (clientfd < 0)
        {
            printf("accept error\n");
        }
        else
        {
            printf("a new connection from %s:%d success\n", inet_ntoa(client_address.sin_addr), ntohs(client_address.sin_port));
            int fds[2];
            pipe(fds);
            ret = splice(clientfd, nullptr, fds[1], nullptr, 32768, SPLICE_F_MORE);
            assert(ret != -1);
    
            ret = splice(fds[0], nullptr, clientfd, nullptr, 32768, SPLICE_F_MORE);
            assert(ret != -1);
    
            close(clientfd);
        }
        close(sockfd);
        exit(0);
    }

    select 函数 select函数在第二个参数列表 可读的时候返回 或者是等到了规定的时间返回

    返回之后 第二个参数指向fdset的集合 被修改为可读的fd列表 这就需要每次返回后都更新 fdset集合

    返回后 此函数的返回值为可读的fd数量, 遍历fdset集合 同时使用FD_ISSET判断fdset[i] 是否在其中 然后判断此fd是否为listenfd 如果是则接受新的连接 如果不是说明是已经接受的其他fd 判断是有数据可读 还是此连接断开

    #include <fcntl.h> 
    // maxfdp 最大数 FD_SETSIZE
    // struct fd_set 一个集合,可以存储多个文件描述符
    // - FD_ZERO(&fd_set) 清空 -FD_SET(fd, &fd_set) 放入fd FD_CLR(fd, &fd_set)从其中清除fd
    // - FD_ISSET(fd, &fd_set) 判断是否在其中
    // readfds  需要监视的文件描述符读变化, 其中的文件描述符可读的时候返回
    // writefds 需要监视的文件描述符写变化, 其中的文件描述符可写的时候返回
    // errorfds 错误
    // timeout 传入NULL为阻塞, 设置为0秒0微秒则变为非阻塞函数
    // 返回值 负值为错误 等待超时说明文件无变化返回0 有变化返回正值
    int select(int maxfdp,fd_set *readfds,fd_set *writefds,fd_set *errorfds,struct timeval*timeout); 
    
    #define exit_if(r, ...) \
    {   \
        if (r)  \
        {   \
            printf(__VA_ARGS__);    \
            printf("errno no: %d, error msg is %s", errno, strerror(errno));    \
            exit(1);    \
        }   \
    }   \
    
    int main(int argc, char* argv[])
    {
        int keyboard_fd = open("/dev/tty", O_RDONLY | O_NONBLOCK);
        exit_if(keyboard_fd < 0, "open keyboard fd error\n");
        fd_set readfd;
        char recv_buffer = 0;
    
        while (true)
        {
            FD_ZERO(&readfd);
            FD_SET(0, &readfd);
    
            timeval timeout {5, 0};
    
            int ret = select(keyboard_fd + 1, &readfd, nullptr, nullptr, &timeout);
            exit_if(ret == -1, "select error\n");
            if (ret > 0)
            {
                if (FD_ISSET(keyboard_fd, &readfd))
                {
                    recv_buffer = 0;
                    read(keyboard_fd, &recv_buffer, 1);
                    if ('\n' == recv_buffer)
                    {
                        continue;
                    }
                    if ('q' == recv_buffer)
                    {
                        break;
                    }
                    printf("the input is %c\n", recv_buffer);
                }
    
            }
            if (ret == 0)
            {
                printf("timeout\n");
            }
        }
    }
  • 相关阅读:
    MySQL--lsblk命令查看块设备
    MySQL--linux IO调度算法
    一致性哈希
    MySQL--查询表统计信息
    MySQL--区分表名大小写
    MySQL--Online DDL
    MySQL--MODIFY COLUMN和ALTER COLUMN
    MySQL--修改表字段
    MySQL--增加或修改列注释
    鼠标事件
  • 原文地址:https://www.cnblogs.com/mjhjl/p/16229131.html
Copyright © 2020-2023  润新知