六、Linux应用编程和网络编程之高级IO

    xiaoxiao2023-09-30  176

    目录

    1、阻塞和非阻塞

    2、IO多路复用原理

    3、异步IO

    4、存储映射IO


    1、阻塞和非阻塞

    1.1、阻塞

    (1)常见的阻塞:wait、pause、sleep等函数;read或write某些文件时

    read或write本身没有阻塞与非阻塞的属性,关键在于他们操作的文件是否为阻塞。read普通文件时,不会被阻塞,但如果是一个IO设备,就会被阻塞

    (2)阻塞式好处:简单,好实现,效率高

     

    1.2、非阻塞

    (1)为什么要实现非阻塞

    阻塞式在多路IO时会有问题,在单路IO时效率会非常高

    (2)如何实现非阻塞IO访问:O_NONBLOCK和fcntl

    (3)并发式IO的解决方案之非阻塞式IO

    #include <stdio.h> #include <string.h> #include <unistd.h> #include <fcntl.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> int main (void) { int flag = -1; char buf[200]; int fd = -1; int ret = -1; fd = open("/dev/input/mouse0", O_RDONLY | O_NONBLOCK); if (fd < 0) { perror("open"); _exit(-1); } flag = fcntl(0, F_GETFL); flag |= O_NONBLOCK; fcntl(0, F_SETFL, flag); while (1) { memset(buf, 0, sizeof(buf)); ret = read(0, buf, 10); if (ret > 0) { printf("键盘读到的字符为:[%s]\n", buf); } memset(buf, 0, sizeof(buf)); ret = read(fd, buf, 10); if (ret > 0) { printf("鼠标读到的字符为:[%s]\n", buf); } } return 0; }

    2、IO多路复用原理

    (1)应用场合:多路非阻塞式IO。

    (2)select和poll

    外部阻塞式,内部非阻塞式自动轮询多路阻塞式IO

    (3)代码实践

    #include <stdio.h> #include <unistd.h> #include <string.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/select.h> #include <sys/time.h> int main(void) { int fd = -1; int ret = -1; char buf[200]; fd_set myset; struct timeval tm; // fd_set为128字节,则最多可以表示128*8个fd printf("fd_set = %d\n", sizeof(myset)); fd = open("/dev/input/mouse0", O_RDONLY); if (fd < 0) { perror("open:"); return -1; } // 处理myset FD_ZERO(&myset); FD_SET(fd, &myset); FD_SET(0, &myset); tm.tv_sec = 5; tm.tv_usec = 0; ret = select(fd+1, &myset, NULL, NULL, &tm); if (ret < 0) { perror("select"); return -1; } else if (ret == 0) { printf("超时\n"); } else //等到了一路IO,去监测到底是哪个IO到了 { if (FD_ISSET(0, &myset)) { // 处理键盘 memset(buf, 0, sizeof(buf)); read(0, buf, 5); printf("键盘读出的内容是:[%s].\n", buf); } if (FD_ISSET(fd, &myset)) { // 这里处理鼠标 memset(buf, 0, sizeof(buf)); read(fd, buf, 5); printf("鼠标读出的内容是:[%s].\n", buf); } } return 0; }

    3、异步IO

    (1)工作方式:

    当前进程注册一个异步IO事件(使用signal注册一个信号SIGIO的处理函数),然后当前进程可以正常处理自己的事情,当异步事件发生后当前进程会收到一个SIGIO信号从而执行绑定的处理函数去处理这个异步事件。

    #include <stdio.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <signal.h> int fd = -1; // 定义鼠标fd的全局变量 // 绑定SIGIO信号,在函数内部实现异步通知事件 void func(int sig) { char buf[200] = {0}; if (sig != SIGIO) return; read(fd, buf, 3); printf("鼠标读到的字符为:[%s]\n", buf); } int main (void) { // 读鼠标 char buf[200]; int flag = -1; fd = open("/dev/input/mouse0", O_RDONLY); if (fd < 0) { perror("open"); return -1; } // 设置fd为可以接受异步IO:O_ASYNC flag = fcntl(fd, F_GETFL); flag |= O_ASYNC; fcntl(fd, F_SETFL, flag); // 把异步IO事件的接收进程设置为当前进程 fcntl(fd, F_SETOWN, getpid()); // 注册当前进程的SIGIO信号捕获函数 signal(SIGIO, func); // 把键盘事件看作主程序,把鼠标事件看作中断 while (1) { memset(buf, 0, sizeof(buf)); read(0, buf, 50); printf("键盘读到的字符为:[%s]\n", buf); } return 0; }

    4、存储映射IO

    (1)mmap函数

    (2)LCD显示和IPC之共享内存

    (3)存储映射IO的特点

    共享而不是复制,减少内存操作处理大文件时效率高,小文件不划算

    文章参考朱友鹏老师物联网课程整理

    最新回复(0)