最新消息:XAMPP默认安装之后是很不安全的,我们只需要点击左方菜单的 "安全"选项,按照向导操作即可完成安全设置。

嵌入式linux-03网络编程四种IO模型原理

XAMPP案例 admin 644浏览 0评论
每日心灵鸡汤:无论以何种方式,都不要慢慢离开,要决绝地离开,永远不回头。不要相信过去的时光才更好,它们已经消亡了。过去的岁月看来安全无害,被轻易跨越,而未来藏在迷雾中,叫人看来胆怯。但当你踏足其中,就会云开雾散。–fqes0008

一、网络编程四种IO模型。

1、什么是IO模型?

网络编程对于数据输出输入方法: 阻塞IO,非阻塞IO,多路复用,信号驱动。

 

2、这几种IO模型原理是如何?

1)阻塞IO: 一直阻塞等待某一个套接字的数据到达,如果有数据,则读取并返回,如果无数据,就会一直等待。

read(fd);

recv(fd);

accept(sockfd);

以上的例子,在过去,我们都会觉得是函数阻塞,例如read函数,accept函数阻塞,但是这样想是错误,因为真正阻塞的是套接字/文件描述符,并不是函数本身具有阻塞的属性。

 

因为fd是文件描述符  -> fd默认就是阻塞属性  -> read(fd)  -> 阻塞

 

2)非阻塞IO:读取一个套接字数据,如果有数据,就会读取返回,如果没有数据,直接返回。

因为fd是文件描述符  -> fd默认就是阻塞属性  -> 添加非阻塞属性给fd  -> read(fd)  -> 非阻塞读取。

 

3)

 

4)

 

二、非阻塞IO模型。

1、如果要使用非阻塞IO,思路是如何?

1)先创建一个文件描述符/套接字   -> 默认都是阻塞属性。

2)设置非阻塞的属性给文件描述符  -> 这时候,文件描述符就是非阻塞的。

3)再调用read()/accept()/recv()去处理这个文件描述符时,就会非阻塞。

 

2、如何设置非阻塞属性给文件描述符?  ->  fcntl()  -> man 2 fcntl

 

头文件:

#include <unistd.h>

#include <fcntl.h>

 

原型:

int fcntl(int fd, int cmd, … /* arg */ );

 

参数:

fd: 需要设置属性的文件描述符

cmd:

F_GETFL (void)  -> void代表第三个参数不需要填

Get the file access mode and the file status flags; arg is ignored.

//获取当前文件描述符的属性

 

 

F_SETFL (int)   -> int代表后面那个参数要填

Set the file status flags to the value specified by arg.

 

O_NONBLOCK   -> 非阻塞属性

 

返回值:

成功:

F_GETFL    返回文件的属性

F_SETFL    返回0

失败:

-1

 

例题1: 设置非阻塞属性给监听套接字,看看这个套接字还会不会阻塞等待客户端连接?

 

listen(sockfd);

accept(sockfd);  -> 阻塞   -> 有人连接,accept()返回

没有人连接,就会一直等待

 

listen(sockfd);

设置非阻塞属性给sockfd

accept(sockfd);  -> 非阻塞  -> 有人连接,accept()返回成功

-> 没有人连接,就会返回失败

 

 

 

#include “head.h”

 

int main(int argc,char *argv[])

{

//1. 创建一个TCP套接字

int sockfd;

sockfd = socket(AF_INET,SOCK_STREAM,0);

//2. 绑定IP地址,端口号

struct sockaddr_in srvaddr;

socklen_t len = sizeof(srvaddr);

bzero(&srvaddr,len);

srvaddr.sin_family = AF_INET;

srvaddr.sin_port = htons(atoi(argv[1]));

srvaddr.sin_addr.s_addr = htonl(INADDR_ANY);

bind(sockfd,(struct sockaddr *)&srvaddr,len);

//3. 设置监听套接字

listen(sockfd,5);

//sockfd  -> 默认是阻塞属性

//4. 添加非阻塞属性给sockfd

int state;

state = fcntl(sockfd,F_GETFL); //state就是sockfd当前的属性。

state |= O_NONBLOCK;           //state就是新属性了

fcntl(sockfd,F_SETFL,state);

//sockfd  -> 具有非阻塞属性

//5. 等待客户端连接

struct sockaddr_in cliaddr;

bzero(&cliaddr,len);

int connfd;

while(1)

{

connfd = accept(sockfd,(struct sockaddr *)&cliaddr,&len);

if(connfd > 0) //有人连接,就会返回成功

{

printf(“connfd = %d\n”,connfd);

printf(“new connection:%s\n”,inet_ntoa(cliaddr.sin_addr));

break;

}

else{ //没有人连接,就会返回失败

printf(“connect error!\n”);

}

}

close(sockfd);

close(connfd);

 

return 0;

}

 

练习1: 使用非阻塞IO读取TCP套接字上数据。

-> 有数据就打印出来,没有返回失败。

 

参考p1目录。

.c文件:

#include “head.h”

 

int main(int argc,char *argv[])  // ./jack 192.168.14.4 50000

{

//1. 创建TCP套接字

int sockfd;

sockfd = socket(AF_INET,SOCK_STREAM,0);

printf(“sockfd = %d\n”,sockfd);

//2. 准备rose的IP地址。

struct sockaddr_in srvaddr;

socklen_t len = sizeof(srvaddr);

bzero(&srvaddr,len);

srvaddr.sin_family = AF_INET;  //地址族

srvaddr.sin_port = htons(atoi(argv[2]));  //端口号

inet_pton(AF_INET,argv[1],&srvaddr.sin_addr); //设置好Rose的IP地址

//3. 发起连接

//connect调用之前: sockfd  -> 待连接套接字

int ret = connect(sockfd,(struct sockaddr *)&srvaddr,len);

if(ret == 0)

{

printf(“connect success!\n”);

}

//connect调用之后: sockfd  -> 已连接套接字

//4. 发送数据给rose

char buf[100];

while(1)

{

bzero(buf,sizeof(buf));

fgets(buf,sizeof(buf),stdin);

send(sockfd,buf,strlen(buf),0);

if(strncmp(buf,”fenshou”,7) == 0)

{

break;

}

}

//5. 回收TCP套接字的资源

close(sockfd);

return 0;

}

 

.h文件

#ifndef _HEAD_H_

#define _HEAD_H_

 

#include <dirent.h>

#include <fcntl.h>

#include <errno.h>

#include <linux/fb.h>

#include <linux/input.h>

#include <pthread.h>

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <strings.h>

#include <stdbool.h>

#include <syslog.h>

#include <stdint.h>

#include <sys/stat.h>

#include <sys/types.h>

#include <sys/mman.h>

#include <sys/ipc.h>

#include <sys/msg.h>

#include <sys/wait.h>

#include <sys/ioctl.h>

#include  <sys/shm.h>

#include <sys/sem.h>

#include <semaphore.h>

#include <time.h>

#include <unistd.h>

#include <sys/socket.h>

#include <arpa/inet.h>

#include <sys/select.h>

 

#endif

 

.c文件

#include “head.h”

 

int main(int argc,char *argv[])

{

//1. 创建一个TCP套接字

int sockfd;

sockfd = socket(AF_INET,SOCK_STREAM,0);

//2. 绑定IP地址,端口号

struct sockaddr_in srvaddr;

socklen_t len = sizeof(srvaddr);

bzero(&srvaddr,len);

srvaddr.sin_family = AF_INET;

srvaddr.sin_port = htons(atoi(argv[1]));

srvaddr.sin_addr.s_addr = htonl(INADDR_ANY);

bind(sockfd,(struct sockaddr *)&srvaddr,len);

//3. 设置监听套接字

listen(sockfd,5);

//sockfd  -> 默认是阻塞属性

//4. 添加非阻塞属性给sockfd

int state;

state = fcntl(sockfd,F_GETFL); //state就是sockfd当前的属性。

state |= O_NONBLOCK;           //state就是新属性了

fcntl(sockfd,F_SETFL,state);

//sockfd  -> 具有非阻塞属性

//5. 等待客户端连接

struct sockaddr_in cliaddr;

bzero(&cliaddr,len);

int connfd;

while(1)

{

connfd = accept(sockfd,(struct sockaddr *)&cliaddr,&len);

if(connfd > 0) //有人连接,就会返回成功

{

printf(“connfd = %d\n”,connfd);

printf(“new connection:%s\n”,inet_ntoa(cliaddr.sin_addr));

break;

}

else{ //没有人连接,就会返回失败

printf(“connect error!\n”);

}

}

//connfd -> 阻塞

//设置非阻塞属性给connfd

state = fcntl(connfd,F_GETFL); //state就是sockfd当前的属性。

state |= O_NONBLOCK;           //state就是新属性了

fcntl(connfd,F_SETFL,state);

//connfd -> 非阻塞

char buf[100];

while(1)

{

bzero(buf,sizeof(buf));

if( recv(connfd,buf,sizeof(buf),0) >= 0)

{

printf(“from jack:%s”,buf);

}

/*

else{

printf(“recv error!\n”);

}

*/

if(strncmp(buf,”quit”,4) == 0)

{

break;

}

}

close(sockfd);

close(connfd);

 

return 0;

}

 

 

 

三、多路复用。

1、什么是多路复用?

就是先将需要监听的文件描述符加入到一个集合中,然后在规定的时间内/无限等待去监听这个集合,如果规定的时间内/无限等待过程中有数据到达,则其他没有数据到达的文件描述符就会被自动剔除到集合之外,我们用户只需要观察集合中有哪个文件描述符存在就可以。

 

2、如何实现多路复用?

1)定义一个集合。  ->  man 2 select

fd_set set;

 

2)删除、添加、清空,判断集合?

void FD_CLR(int fd, fd_set *set);    -> 把集合中的fd删除掉

int  FD_ISSET(int fd, fd_set *set);  -> 判断fd是不是在集合中

void FD_SET(int fd, fd_set *set);    -> 将fd添加到集合中

void FD_ZERO(fd_set *set);           -> 清空集合中所有的文件描述符

 

fd: 需要处理的文件描述符。

set:集合的地址

 

返回值:

在集合中:  1

不在集合中:0

 

3)如何监听一个集合中?  -> select()  -> man 2 select

 

头文件:

#include <sys/select.h>

#include <sys/time.h>

#include <sys/types.h>

#include <unistd.h>

 

int select(int nfds, fd_set *readfds, fd_set *writefds,

fd_set *exceptfds, struct timeval *timeout);

参数:

nfds:所有正在监测的套接字的最大值加1

readfds:读就绪文件描述符集合   -> 把所有需要监听的文件描述符加入到这个集合中即可。

writefds:写就绪文件描述符集合  -> NULL

exceptfds:异常就绪文件描述符集合  -> NULL

timeout:超时控制                 -> NULL (代表无限等待)

 

返回值:

成功:就绪文件描述符总数

失败:-1

 

 

例题2: 实现客户端与服务器互相收发,不能实现线程,要求使用多路复用。

 

服务器端:

#include “head.h”

 

int main(int argc,char *argv[])

{

//1. 创建一个TCP套接字

int sockfd;

sockfd = socket(AF_INET,SOCK_STREAM,0);

//2. 绑定IP地址,端口号

struct sockaddr_in srvaddr;

socklen_t len = sizeof(srvaddr);

bzero(&srvaddr,len);

srvaddr.sin_family = AF_INET;

srvaddr.sin_port = htons(atoi(argv[1]));

srvaddr.sin_addr.s_addr = htonl(INADDR_ANY);

bind(sockfd,(struct sockaddr *)&srvaddr,len);

//3. 设置监听套接字

listen(sockfd,5);

//4. 等待对方的连接

int connfd;

struct sockaddr_in cliaddr;

bzero(&cliaddr,len);

connfd = accept(sockfd,(struct sockaddr *)&cliaddr,&len);

if(connfd > 0)

{

printf(“connfd = %d\n”,connfd);

printf(“new connection:%s\n”,inet_ntoa(cliaddr.sin_addr));

}

//5. 定义一个集合

fd_set set;

char buf[100];

int max_fd = connfd > STDIN_FILENO ? connfd : STDIN_FILENO;

//6. 不断监听这个集合,看看谁留下来了。

while(1)

{

FD_ZERO(&set);

FD_SET(connfd,&set);

FD_SET(STDIN_FILENO,&set);

//7. 一直阻塞等待

select(max_fd+1,&set,NULL,NULL,NULL);

//8. 只要集合中任意一个文件描述符有数据到达,那么select就会返回。

if(FD_ISSET(connfd,&set))  //connfd还在,说明我要收数据

{

bzero(buf,sizeof(buf));

recv(connfd,buf,sizeof(buf),0);

printf(“from client:%s”,buf);

if(strncmp(buf,”quit”,4) == 0)

{

break;

}

}

if(FD_ISSET(STDIN_FILENO,&set))  //STDIN_FILENO还在,说明要发送数据给对方。

{

bzero(buf,sizeof(buf));

fgets(buf,sizeof(buf),stdin);

send(connfd,buf,strlen(buf),0);

if(strncmp(buf,”quit”,4) == 0)

{

break;

}

}

}

close(connfd);

close(sockfd);

return 0;

}

 

客户端:

#include “head.h”

 

int main(int argc,char *argv[])  // ./jack 192.168.14.4 50000

{

//1. 创建TCP套接字

int sockfd;

sockfd = socket(AF_INET,SOCK_STREAM,0);

//printf(“sockfd = %d\n”,sockfd);

//2. 准备rose的IP地址。

struct sockaddr_in srvaddr;

socklen_t len = sizeof(srvaddr);

bzero(&srvaddr,len);

srvaddr.sin_family = AF_INET;  //地址族

srvaddr.sin_port = htons(atoi(argv[2]));  //端口号

inet_pton(AF_INET,argv[1],&srvaddr.sin_addr); //设置好Rose的IP地址

//3. 发起连接

//connect调用之前: sockfd  -> 待连接套接字

int ret = connect(sockfd,(struct sockaddr *)&srvaddr,len);

if(ret == 0)

{

printf(“connect success!\n”);

}

//connect调用之后: sockfd  -> 已连接套接字

//5. 定义一个集合

fd_set set;

char buf[100];

int max_fd = sockfd > STDIN_FILENO ? sockfd : STDIN_FILENO;

//6. 不断监听这个集合,看看谁留下来了。

while(1)

{

FD_ZERO(&set);

FD_SET(sockfd,&set);

FD_SET(STDIN_FILENO,&set);

//7. 一直阻塞等待

select(max_fd+1,&set,NULL,NULL,NULL);

//8. 只要集合中任意一个文件描述符有数据到达,那么select就会返回。

if(FD_ISSET(sockfd,&set))  //sockfd还在,说明我要收数据

{

bzero(buf,sizeof(buf));

recv(sockfd,buf,sizeof(buf),0);

printf(“from client:%s”,buf);

if(strncmp(buf,”quit”,4) == 0)

{

break;

}

}

if(FD_ISSET(STDIN_FILENO,&set))  //STDIN_FILENO还在,说明要发送数据给对方。

{

bzero(buf,sizeof(buf));

fgets(buf,sizeof(buf),stdin);

send(sockfd,buf,strlen(buf),0);

if(strncmp(buf,”quit”,4) == 0)

{

break;

}

}

}

 

//5. 回收TCP套接字的资源

close(sockfd);

return 0;

}

 

 

2、如何使用poll实现多路复用?

 

作业1: 写一个TCP协议服务器,最多可以接受20(无限)个用户的连接,可以随时接受客户端的连接,每一个客户端的数据使用数组(链表)来储存,只要连接上该服务器的客户端有消息发送给服务器,服务器就会打印出来,要求使用非阻塞IO完成。

 

#include <dirent.h>

#include <fcntl.h>

#include <errno.h>

#include <linux/fb.h>

#include <linux/input.h>

#include <pthread.h>

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <strings.h>

#include <stdbool.h>

#include <syslog.h>

#include <stdint.h>

#include <sys/stat.h>

#include <sys/types.h>

#include <sys/mman.h>

#include <sys/ipc.h>

#include <sys/msg.h>

#include <sys/wait.h>

#include <sys/ioctl.h>

#include  <sys/shm.h>

#include <sys/sem.h>

#include <semaphore.h>

#include <time.h>

#include <unistd.h>

#include <sys/socket.h>

#include <arpa/inet.h>

#include <sys/select.h>

 

struct client{

int clifd[20];  //存放那些已经连接到服务器上的客户端的已连接套接字

int count;//已经连接到服务器上的客户端的个数

};

 

int init_cli(struct client *cli)

{

int i;

for(i=0;i<20;i++)

{

(cli->clifd)[i] = -1; //全部的套接字都设置为-1

}

cli->count = 0; //当前没有人连接进来

return 0;

}

 

int add_cli(struct client *cli,int connfd)

{

if(cli->count >= 20)

{

return -1; //满人了,不好意思

}

int i;

for(i=0;i<20;i++)

{

if((cli->clifd)[i] == -1)  //找到空位

{

(cli->clifd)[i] = connfd;  //就把connfd赋值到这个空位上

break;

}

}

cli->count++;

return 0;

}

 

int main(int argc,char *argv[])

{

//0. 初始化结构体状态

struct client *cli = malloc(sizeof(struct client));

init_cli(cli);

//1. 创建一个TCP套接字

int sockfd;

sockfd = socket(AF_INET,SOCK_STREAM,0);

//2. 绑定IP地址,端口号

struct sockaddr_in srvaddr;

socklen_t len = sizeof(srvaddr);

bzero(&srvaddr,len);

srvaddr.sin_family = AF_INET;

srvaddr.sin_port = htons(atoi(argv[1]));

srvaddr.sin_addr.s_addr = htonl(INADDR_ANY);

bind(sockfd,(struct sockaddr *)&srvaddr,len);

//3. 设置监听套接字

listen(sockfd,5);

//4. 想非阻塞等待连接,就要添加非阻塞属性给sockfd。

int state;

state = fcntl(sockfd,F_GETFL);

state |= O_NONBLOCK;

fcntl(sockfd,F_SETFL,state);

int connfd,ret,i;

char buf[100];

struct sockaddr_in cliaddr;

while(1)

{

//5. 非阻塞地等待客户端的连接

connfd = accept(sockfd,(struct sockaddr *)&cliaddr,&len);

//6. 如果真的有人连接进来。

if(connfd >= 0)

{

//7. 设置connfd为非阻塞的状态

state = fcntl(connfd,F_GETFL);

state |= O_NONBLOCK;

fcntl(connfd,F_SETFL,state);

//8. 将这个connfd存储到数组中

ret = add_cli(cli,connfd);

if(ret == -1)

{

printf(“add cli error!\n”);

close(connfd);

}

//9. 打印谁连接进来吧

printf(“new connection:%s\n”,inet_ntoa(cliaddr.sin_addr));

}

//7. 如果没有人连接,就开始询问连接进来的客户端有没有话说。

for(i=0;i<20;i++)

{

bzero(buf,sizeof(buf));

//如果是空位,

if((cli->clifd)[i] == -1)

{

//就继续问下一个客户端

continue;

}

//如果不是空位,而且又说话了

if( recv(cli->clifd[i],buf,sizeof(buf),0) >= 0)

{

//就打印这个用户说的话

printf(“from %d client: %s”,cli->clifd[i],buf);

//如果这个人说了quit

if(strncmp(buf,”quit”,4) == 0)

{

close(cli->clifd[i]);

cli->clifd[i] = -1;

cli->count–;

}

}

//如果不是空位,但是又不说话,就继续问下一个客户端。

else{

continue;

}

}

}

close(sockfd);

return 0;

}

 

作业2: 使用多路复用完成以下的效果。

在开发板运行: ./xxx bmp_dir/

 

1)先显示目录下第一张图片。

2)这时候点击屏幕右边松开  或者  输入”next”  都可以显示下一张图片。

这时候点击屏幕左边松开  或者  输入”prev”  都可以显示上一张图片。

 

 

#include <dirent.h>

#include <fcntl.h>

#include <errno.h>

#include <linux/fb.h>

#include <linux/input.h>

#include <pthread.h>

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <strings.h>

#include <stdbool.h>

#include <syslog.h>

#include <stdint.h>

#include <sys/stat.h>

#include <sys/types.h>

#include <sys/mman.h>

#include <sys/ipc.h>

#include <sys/msg.h>

#include <sys/wait.h>

#include <sys/ioctl.h>

#include  <sys/shm.h>

#include <sys/sem.h>

#include <semaphore.h>

#include <time.h>

#include <unistd.h>

#include <sys/socket.h>

#include <arpa/inet.h>

#include <sys/select.h>

 

 

struct list_node{

/* 数据域 */

char picname[10];  //图片路径

/* 指针域 */

struct list_node *next;

struct list_node *prev;

};

 

int mmap_show_bmp(const char *bmp_path)

{

FILE *fp;

int n,lcd;

int i,j;

int x,y;

int k;

char bmp_buf[800*480*3] = {0};

char lcd_buf[800*480*4] = {0};

char show_buf[800*480*4] = {0};

/*1. 打开图片 */

fp = fopen(bmp_path,”r”); //默认在最开头

if(fp == NULL)

printf(“fopen error!\n”);

/*2. 打开lcd设备 */

lcd = open(“/dev/fb0”,O_RDWR);

if(lcd < 0)

printf(“open fb0 error!\n”);

/*3. 先跳过54个头数据 */

fseek(fp,54,SEEK_SET);

/*4. 将图片的数据读取到缓冲区中 */

n = fread(bmp_buf,800*480*3,1,fp);

if(n!=1)

printf(“fread error!\n”);

/*5. 将24位转32位 */

for(i=0,j=0;i<800*480*4;i+=4,j+=3)

{

lcd_buf[i] = bmp_buf[j];

lcd_buf[i+1] = bmp_buf[j+1];

lcd_buf[i+2] = bmp_buf[j+2];

lcd_buf[i+3] = 0;

}

/* 6. 上下颠倒 */

for(y=0;y<480;y++)

{

for(x=0;x<800*4;x++)

{

show_buf[800*4*y+x] = lcd_buf[800*4*(479-y)+x];

}

}

/* 7. 产生一片内存空间,作为映射 */

char *p = (char *)mmap(NULL,800*480*4,PROT_READ|PROT_WRITE,MAP_SHARED,lcd,0);

if(p == (void *)-1)

printf(“mmap error!\n”);

/* 8. 将数据拷贝到内存上 */

for(k=0;k<800*480*4;k++)

{

memcpy(p+k,&show_buf[k],1);

}

/* 7. 关闭文件 */

munmap(p,800*480*4);

fclose(fp);

close(lcd);

return 0;

}

 

struct list_node *init_list_head()

{

//1. 为头节点申请空间

struct list_node *head = NULL;

head = (struct list_node *)malloc(sizeof(struct list_node));

if(head == NULL)

printf(“malloc error!\n”);

//2. 为头节点指针域赋值。

head->next = NULL;

head->prev = NULL;

return head;

}

 

int add_node_to_tail(struct list_node *head,char *picname)

{

//1. 为新节点申请空间

struct list_node *new = NULL;

new = (struct list_node *)malloc(sizeof(struct list_node));

if(new == NULL)

printf(“malloc new error!\n”);

 

//2. 为新节点的数据域与指针域赋值

strcpy(new->picname,picname);

new->next = NULL;

//3. 寻找最后一个节点

struct list_node *p = NULL;

for(p=head;p->next!=NULL;p=p->next);

//4. 从循环中出来时,p就是最后一个节点

p->next = new;

new->prev = p;

return 0;

}

 

int delete_list(struct list_node *head)

{

struct list_node *p = NULL;

struct list_node *q = NULL;

for(p=q=head;p!=NULL;p=q)

{

q=p->next;

free(p);

}

return 0;

}

 

int main(int argc,char *argv[])

{

//1. 初始化链表头

struct list_node *head = NULL;

head = init_list_head();

//2. 打开目录,并读取目录下的所有图片的名字

DIR *dp = NULL;

dp = opendir(“./bmp2_dir”);

if(dp == NULL)

printf(“opendir error!\n”);

//3. 切换到目录下

chdir(“./bmp2_dir”);

//4. 读取

struct dirent *ep = NULL;

while(1)

{

ep = readdir(dp);

if(ep == NULL)

{

break;

}

if(ep->d_name[0] == ‘.’)

{

continue;

}

add_node_to_tail(head,ep->d_name);

}

 

//4.5 寻找最后一个节点

struct list_node *last = NULL;

for(last=head;last->next!=NULL;last=last->next);

//从循环出来时,last就是指向最后一节点。

//5. 显示第一张图片(即头节点的下一个节点)

struct list_node *p = head->next;   //这个p就是指向当前显示的张数的节点

mmap_show_bmp(p->picname);

//6. 进入触摸屏状态

int fd,x;

struct input_event buf;

char w_buf[100];

fd = open(“/dev/input/event0”,O_RDONLY);

if(fd < 0)

{

printf(“open fd error!\n”);

}

//7. 不断监听触摸屏与键盘

fd_set set;

int maxfd = fd > STDIN_FILENO ? fd : STDIN_FILENO;

while(1)

{

FD_ZERO(&set);

FD_SET(fd,&set);

FD_SET(STDIN_FILENO,&set);

//一直阻塞等待,只要集合中的文件描述符有数据到达,这个函数就会马上返回。

select(maxfd+1,&set,NULL,NULL,NULL);

if(FD_ISSET(fd,&set)) //如果fd还在,说明触摸屏有数据到达

{

bzero(&buf,sizeof(buf));

read(fd,&buf,sizeof(buf));

if(buf.type == EV_ABS && buf.code == ABS_X)

x = buf.value;

if(buf.type == EV_KEY && buf.code == BTN_TOUCH && buf.value == 0)

{

if(x < 500) //点击了左边

{

if(p == head->next) //说明当前显示的是第一张。

{

p = last; //当前p就是指向最后一个节点。

}

else{  //说明当前显示的不是第一张

p = p->prev;

}

}

if(x > 500) //点击了右边

{

if(p->next == NULL) // 说明当前显示的是最后一张

{

p = head->next; //把p挪动到头节点的下一个节点

}

else{

p = p->next;

}

}

if(x == 500)

{

break;

}

mmap_show_bmp(p->picname);

}

}

if(FD_ISSET(STDIN_FILENO,&set)) //代表键盘在里面,说明键盘中有数据

{

bzero(w_buf,sizeof(w_buf));

fgets(w_buf,sizeof(w_buf),stdin);

if(strncmp(w_buf,”next”,4) == 0)  //键盘输入next下一张

{

if(p->next == NULL) // 说明当前显示的是最后一张

{

p = head->next; //把p挪动到头节点的下一个节点

}

else{

p = p->next;

}

}

if(strncmp(w_buf,”prev”,4) == 0)   //键盘输入prev上一张

{

if(p == head->next) //说明当前显示的是第一张。

{

p = last; //当前p就是指向最后一个节点。

}

else{  //说明当前显示的不是第一张

p = p->prev;

}

}

if(strncmp(w_buf,”quit”,4) == 0)

{

break;

}

mmap_show_bmp(p->picname);

}

}

delete_list(head);

chdir(“..”);

closedir(dp);

close(fd);

return 0;

}

 

转载请注明:XAMPP中文组官网 » 嵌入式linux-03网络编程四种IO模型原理

您必须 登录 才能发表评论!