高级IO
一. 实际现实问题出发
1.1. 一个进程中如何既获取键盘键值也同时获取鼠标值?
1.1.1. 使用while轮询
a. 效率低下。
1.1.2. 使用IO多路复用
a. 高效,响应及时。
1.1.3. 通过异步IO实现
二. 使用IO多路复用
2.2. IO多路复用相关API函数
2.2.1. select函数
a. 函数原型
PSELECT(P) POSIX Programmer's Manual PSELECT(P) NAME pselect, select - synchronous I/O multiplexing SYNOPSIS #include <sys/select.h> int pselect(int nfds, fd_set *restrict readfds, fd_set *restrict writefds, fd_set *restrict errorfds, const struct timespec *restrict timeout, const sigset_t *restrict sigmask); int select(int nfds, fd_set *restrict readfds, fd_set *restrict writefds, fd_set *restrict errorfds, struct timeval *restrict timeout); void FD_CLR(int fd, fd_set *fdset); int FD_ISSET(int fd, fd_set *fdset); void FD_SET(int fd, fd_set *fdset); void FD_ZERO(fd_set *fdset);
b. 实际应用
#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, ret = -1; char buf[200]; fd_set myset; struct timeval tm; fd = open("/dev/input/mouse1", O_RDONLY); if (fd < 0) { perror("open:"); return -1; } // 当前有2个fd,一共是fd一个是0 // 处理myset FD_ZERO(&myset); FD_SET(fd, &myset); FD_SET(0, &myset); tm.tv_sec = 10; 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, 50); printf("鼠标读出的内容是:[%s].\n", buf); } } return 0; }
2.2.2. poll函数
a. 函数原型
POLL(P) POSIX Programmer's Manual POLL(P) NAME poll - input/output multiplexing SYNOPSIS #include <poll.h> int poll(struct pollfd fds[], nfds_t nfds, int timeout); DESCRIPTION
b. 实际应用
#include <stdio.h> #include <unistd.h> #include <string.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <poll.h> int main(void) { // 读取鼠标 int fd = -1, ret = -1; char buf[200]; struct pollfd myfds[2] = {0}; fd = open("/dev/input/mouse1", O_RDONLY); if (fd < 0) { perror("open:"); return -1; } // 初始化我们的pollfd myfds[0].fd = 0; // 键盘 myfds[0].events = POLLIN; // 等待读操作 myfds[1].fd = fd; // 鼠标 myfds[1].events = POLLIN; // 等待读操作 ret = poll(myfds, fd+1, 10000); if (ret < 0) { perror("poll: "); return -1; } else if (ret == 0) { printf("超时了\n"); } else { // 等到了一路IO,然后去监测到底是哪个IO到了,处理之 if (myfds[0].events == myfds[0].revents) { // 这里处理键盘 memset(buf, 0, sizeof(buf)); read(0, buf, 5); printf("键盘读出的内容是:[%s].\n", buf); } if (myfds[1].events == myfds[1].revents) { // 这里处理鼠标 memset(buf, 0, sizeof(buf)); read(fd, buf, 50); printf("鼠标读出的内容是:[%s].\n", buf); } } return 0; }
三. 异步IO
3.1. 为何可以使用异步IO信号
a. 当发送鼠标或键盘事件是,内核层定义好了异步事件给应用层
3.2. 相关函数
3.2.1. fcntl函数
FCNTL(P) POSIX Programmer's Manual FCNTL(P) NAME fcntl - file control SYNOPSIS #include <unistd.h> #include <fcntl.h> int fcntl(int fildes, int cmd, ...);
3.2.2. signal或者sigaction(SIGIO)
3.3. 实际应用
#include <stdio.h> #include <unistd.h> #include <string.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <signal.h> int mousefd = -1; // 绑定到SIGIO信号,在函数内处理异步通知事件 void func(int sig) { char buf[200] = {0}; if (sig != SIGIO) return; read(mousefd, buf, 50); printf("鼠标读出的内容是:[%s].\n", buf); } int main(void) { // 读取鼠标 char buf[200]; int flag = -1; mousefd = open("/dev/input/mouse1", O_RDONLY); if (mousefd < 0) { perror("open:"); return -1; } // 把鼠标的文件描述符设置为可以接受异步IO flag = fcntl(mousefd, F_GETFL); flag |= O_ASYNC; fcntl(mousefd, F_SETFL, flag); // 把异步IO事件的接收进程设置为当前进程 fcntl(mousefd, F_SETOWN, getpid()); // 注册当前进程的SIGIO信号捕获函数 signal(SIGIO, func); // 读键盘 while (1) { memset(buf, 0, sizeof(buf)); //printf("before 键盘 read.\n"); read(0, buf, 5); printf("键盘读出的内容是:[%s].\n", buf); } return 0; }
四. 存储映射IO
4.1. 何为存储映射IO
a. IPC之共享内存
b. 也可以内核与进程间内存共享
4.2. mmap函数
NAME mmap - map pages of memory SYNOPSIS #include <sys/mman.h> void *mmap(void *addr, size_t len, int prot, int flags, int fildes, off_t off);
4.3. 存储映射IO的特点
a. 共享而不是复制,减少内存操作
b. 处理大文件时效率高,小文件不划算
4.4. 实际应用
/* author : yaofeng date: 2018-12-24 description: screen operation ***********************************************************/ #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/mman.h> #include <linux/fb.h> #include <unistd.h> #include <sys/ioctl.h> #include <string.h> #include <fb.h> #define FB_DEV "/dev/fb0" static struct fb_var_screeninfo varScreenInfo; static struct fb_fix_screeninfo fixScreenInfo; static unsigned int *pfb_buffer = NULL; static int fd = -1; int fb_open(void) { int ret = -1; fd = open(FB_DEV, O_RDWR); if(fd < 0) { perror("open error"); close(fd); return -1; } ret = ioctl(fd, FBIOGET_FSCREENINFO,&fixScreenInfo); if(ret < 0) { perror("ioctl error"); close(fd); return ret; } ret = ioctl(fd, FBIOGET_VSCREENINFO,&varScreenInfo); if(ret < 0) { perror("ioctl error"); close(fd); return ret; } printf("smem_len = %d\n",fixScreenInfo.smem_len); printf("xres = %d; yres = %d\n",varScreenInfo.xres,varScreenInfo.yres); printf("xres_virtual = %d; yres_virtual = %d\n",varScreenInfo.xres_virtual,varScreenInfo.yres_virtual); pfb_buffer = mmap(NULL, fixScreenInfo.smem_len, PROT_READ|PROT_WRITE, MAP_SHARED,fd,0); return 0; } void fb_draw_point(unsigned int x,unsigned int y,unsigned int color) { x %=varScreenInfo.xres; y %=varScreenInfo.yres; *(pfb_buffer + y*varScreenInfo.xres + x ) = color; } void fb_draw_line(unsigned int x0,unsigned int y0,unsigned int x1,unsigned int y1,unsigned int color) { unsigned int x=0,y=0; float setp = (y1-y0)/(float)(x1-x0); for(x=x0,y=y0;x<x1;x++) { fb_draw_point(x,y,color); y = y0+setp*(x-x0) ; } } void fb_draw_back(unsigned int color) { unsigned int x=0,y=0; for(;y<varScreenInfo.yres;y++) { for(x=0;x<varScreenInfo.xres;x++) fb_draw_point(x,y,color); } } void fb_draw_picture(int x0,int y0,const t_picInfo *picInfo) { unsigned int show_y= 0,show_x= 0,x,y; unsigned int pdataoffset = 0; unsigned int pfboffset = 0; unsigned int color = 0; if(NULL == picInfo->pdata) { fprintf(stderr,"pleans input valid pdata\n"); return ; } DEBUG_Printf("ewsolution = %d * %d \n",picInfo->xWidth,picInfo->yHeight); DEBUG_Printf("picture bpp = %d RGBmode = %d\n",picInfo->bpp,picInfo->RGBmode); if(x0<0) x0 = (varScreenInfo.xres - picInfo->xWidth)/2; if(y0<0) y0 = (varScreenInfo.yres - picInfo->yHeight)/2; x0 %=varScreenInfo.xres; y0 %=varScreenInfo.yres; if(picInfo->xWidth<(varScreenInfo.xres -x0)) show_x = picInfo->xWidth; else show_x = (varScreenInfo.xres -x0); if(picInfo->yHeight<(varScreenInfo.yres -y0)) show_y = picInfo->yHeight; else show_y = (varScreenInfo.yres -y0) ; if(24 == picInfo->bpp) { for(y=0;y<show_y;y++,y0++) { pfboffset = y0*varScreenInfo.xres+x0; for(x=0;x<show_x;x++) { if(picInfo->RGBmode == PICRGB) color = ((*(picInfo->pdata+pdataoffset+3*x))<<16)|((*(picInfo->pdata+pdataoffset+3*x+1))<<8)|((*(picInfo->pdata+pdataoffset+3*x+2))<<0); else color = ((*(picInfo->pdata+pdataoffset+3*x))<<0)|((*(picInfo->pdata+pdataoffset+3*x+1))<<8)|((*(picInfo->pdata+pdataoffset+3*x+2))<<16); fb_draw_point(x0+x,y0,color); } pdataoffset += picInfo->xWidth*3; } } else if(32 == picInfo->bpp) { for(y=0;y<show_y;y++,y0++) { pfboffset = y0*varScreenInfo.xres+x0; memcpy(pfb_buffer+pfboffset,(unsigned int*)picInfo->pdata+pdataoffset,sizeof(unsigned int)*show_x); pdataoffset += picInfo->xWidth; } } else { fprintf(stderr,"bpp = %d invalid ,please input bpp=24/32 picture\n",picInfo->bpp); return ; } } /*void fb_draw_bpp32_picture(unsigned int x0,unsigned int y0,const t_picInfo *picInfo) { unsigned int show_y= 0,show_x= 0,y; unsigned int pdataoffset = 0; unsigned int pfboffset = 0; if(NULL == picInfo.pdata) { printf("pleans input valid pdata\n"); return ; } x0 %=varScreenInfo.xres; y0 %=varScreenInfo.yres; if(picInfo->xWidth<(varScreenInfo.xres -x0)) show_x = picInfo->xWidth; else show_x = (varScreenInfo.xres -x0); if(picInfo->yheight<(varScreenInfo.yres -y0)) show_y = picInfo->yheight; else show_y = (varScreenInfo.yres -y0) ; for(y=0;y<show_y;y++,y0++) { pfboffset = y0*varScreenInfo.xres+x0; memcpy(pfb_buffer+pfboffset,(unsigned int*)picInfo->pdata+pdataoffset,sizeof(unsigned int)*show_x); pdataoffset += picInfo->xWidth; } }*/ void fb_close(void) { close(fd); }