python 网络编程 异步io_异步IO实现 小例(程序+驱动程序)

结合阻塞与非阻塞访问、poll 函数可以较好地解决设备的读写,但是如果有了异步通知就更方便了。异步通知的意思是:一旦设备就绪,则主动通知应用程序,这样应用程序根本就不需要查询设备状态,这一点非常类似于硬件上“中断”地概念,比较准确的称谓是:信号驱动(SIGIO)的异步 I/O。可以使用signal()函数来设置对应的信号的处理函数。函数原型是:

void (*signal(int signo,void (*func)(int))) (int)

我们先来看一个使用信号驱动的例子,通过signal(SIGIO,input_handler) 对打开的文件fd 启动信号机制,输入可获得时inputhandler被调用,代码如下:

/*async_io_app.c*/

#include #include#include#include#include#include#include#define MAX_LEN 100 intfd;void input_handler(intnum)

{chardata[MAX_LEN];intlen;//读取并输出 STDIN_FILENO 上的输入 len= read(fd, &data, MAX_LEN);

data[len]= 0;

printf("input available:%s\n", data);

}intmain()

{intoflags;//启动信号驱动机制 fd= open("/dev/CDEV_ZHU", O_RDWR, S_IRUSR |S_IWUSR);if(fd == -1)

{

printf("Device Open Failure !\n");

exit(0);

}

signal(SIGIO, input_handler);

fcntl(fd, F_SETOWN, getpid());

oflags=fcntl(fd, F_GETFL);

fcntl(fd, F_SETFL, oflags|FASYNC);//最后进入一个死循环,程序什么都不干了,只有信号能激发 input_handler 的运行//如果程序中没有这个死循环,会立即执行完毕 while (1);return 0;

}

下面来解释一下上面的代码。为了一个用户在用户空间中能处理一个设备释放的信号,它必须完成一下3份工作:

1)通过F_SETOWN控制指令设置设备文件的拥有者为本进程,这样从设备驱动中发出的信号才能被本进程收到。

2)通过F_SETFL 控制命令设置设备文件支持FASYNC,即异步通知模式。

3)通过signal()链接信号和信号处理函数。

有了信号的发送,那么就一定得有信号的释放了:

在设备驱动和应用程序的异步通知交互中,仅仅在应用程序端捕获信号是不够的,因为信号没有的源头是在驱动端,因此要在适当的时机让设备驱动释放信号。

为了使设备支持异步通知机制,驱动程序中涉及三个操作:

1)支持F_SETOWN命令,能在这个控制命令处理中设置filp->f_owner为对应的进程ID。不过此项工作已由内核完成,设备驱动无须处理。

2)支持F_SETFL命令的处理,每当FASYNC标志改变时,驱动程序中fasync()函数将得以进行。因此,驱动程序必须实现fasync()函数。

3)在设备资源可获得时,调用kill_fasync()函数激发相应的信号。

驱动程序中上面的三步是和应用程序是一一对应的。如下图:

设备驱动中异步通知编程还是比较简单的,主要就是一些数据结构,和两个函数:

数据结构:fasync_struct结构体

函数:1)处理FASYNC标志变更的函数int fasync_helper(int fd, struct file *filp, int mode ,struct fasync_struct **fa);

2) 释放信号用的函数void kill_fasync(struct fasync_struct **fa, int sig, int band);

和其他设备驱动一样,一般将fasync_struct放到设备结构体中。

下面给出驱动程序部分实现支持异步IO的代码:

/* async_io_driver.c */

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

MODULE_LICENSE("GPL");

#define LEN  30

#define init_MUTEX(LOCKNAME) sema_init(LOCKNAME,1)

#define DEVICE_NAME  "CDEV_ZHU"

static struct class *cdev_class;

struct asycIO

{

struct cdev dev_c; /*cdev结构体*/

dev_t  dev;

char  mem[LEN];

int   flag ;

struct semaphore sem; /*并发控制用的信号量*/

wait_queue_head_t r_wait; /*阻塞读用的等待队列头*/

struct fasync_struct *async_queue; /* 异步结构体指针,用于读 */

};

struct asycIO  asyc_device;

static int asyc_io_fasync(int fd, struct file *filp, int mode)

{

return fasync_helper(fd, filp, mode, &asyc_device.async_queue);

}

/*文件释放函数*/

int asyc_io_release(struct inode *inode, struct file *filp)

{

/* 将文件从异步通知列表中删除 */

asyc_io_fasync( - 1, filp, 0);

return 0;

}

/*写操作*/

static ssize_t asyc_write(struct file *filp, const char __user *buf,size_t count, loff_t *ppos)

{

int ret = count;

printk("In asyc_write! \n");

down(&asyc_device.sem);  //获取信号量

memset(asyc_device.mem,0,LEN);

if (copy_from_user(asyc_device.mem, buf, count))

{

up(&asyc_device.sem);

return    - EFAULT;

}

printk("kernel recieve: %s  and the length is %d \n",asyc_device.mem,count);

up(&asyc_device.sem);

asyc_device.flag = 1;

if (asyc_device.async_queue)

kill_fasync(&asyc_device.async_queue, SIGIO, POLL_IN);

wake_up_interruptible(&asyc_device.r_wait);

return ret;

}

static ssize_t asyc_read(struct file *filp, char *buf, size_t len, loff_t *off)

{

int ret = len;

printk("In asyc_read \n");

if (wait_event_interruptible(asyc_device.r_wait, asyc_device.flag != 0))

{

return    - ERESTARTSYS;

}

if (down_interruptible(&asyc_device.sem))

{

return    - ERESTARTSYS;

}

asyc_device.flag = 0;

if (copy_to_user(buf, asyc_device.mem, len))

{

up(&asyc_device.sem);

return    - EFAULT;

}

up(&asyc_device.sem);

return ret;

}

struct file_operations asyc_fops =

{

read: asyc_read,

write: asyc_write,

fasync: asyc_io_fasync,

release: asyc_io_release,

};

static int __init asyc_init(void)

{

int ret,err;

ret = alloc_chrdev_region(&(asyc_device.dev),0,1,DEVICE_NAME) ;

if (ret)

{

printk("globalvar register failure");

}

else

{

cdev_init(&(asyc_device.dev_c),&asyc_fops);

err = cdev_add(&(asyc_device.dev_c),asyc_device.dev,1);

if(err)

{

printk(KERN_NOTICE "error %d adding FC_dev\n",err);

unregister_chrdev_region(asyc_device.dev, 1);

return err;

}

else

{

printk("device register success! \n");

}

cdev_class = class_create(THIS_MODULE,DEVICE_NAME);

if(IS_ERR(cdev_class))

{

printk("ERR:cannot create a cdev_class\n");

unregister_chrdev_region(asyc_device.dev, 1);

return -1;

}

device_create(cdev_class, NULL, asyc_device.dev, 0, DEVICE_NAME);

asyc_device.flag = 0;

init_MUTEX(&(asyc_device.sem));

init_waitqueue_head(&(asyc_device.r_wait));

}

return ret;

}

static void __exit asyc_exit(void)

{

device_destroy(cdev_class,asyc_device.dev);

class_destroy(cdev_class);

unregister_chrdev_region(asyc_device.dev,1);

printk(" device exit! \n");

}

module_init(asyc_init);

module_exit(asyc_exit);

应用程序实现写入功能:

/*async_io_app_w.c*/

#include

#include

#include

#include

#include

int main()

{

int fd, num;

char buffer[100] = {0};

fd = open("/dev/CDEV_ZHU", O_RDWR, S_IRUSR | S_IWUSR);

printf("open /dev/CDEV_ZHU fd = %d \n",fd);

if (fd != -1)

{

while (1)

{

memset(buffer,0,sizeof(buffer));

printf("Please input the buffer:\n");

scanf("%s", buffer);

if (buffer[0] == '0') //如果输入 0,退出

{

close(fd);

break;

}

write(fd, buffer, strlen(buffer));

printf("We have written: %s\n",buffer);

}

}

else

{

printf("device open failure\n");

}

return 0;

}

将上面的“async_io_app.c”、“async_io_driver.c”、“async_io_app_w.c”进行编译,加载驱动之后,开两个终端,分别运行async_io_app 和 async_io_app_w,当async_io_app_w有数据写入的时候,async_io_app的终端会打印所写入的数据,当然内核也会打印数据,下面是结果:

说明:上面图是三个终端的打印结果,从左到右一次是async_io_app_w , async_io_app 和使用dmesg 打印内核的结果。

注:我本来也想用代码格式,但是感觉在vim上排版很舒服的,上来用代码格式反而还不好看了,于是就这样了

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/567589.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

mysql索引创建和使用注意事项

总结: 1、在使用索引时,一般情况下不建议使用like操作。如果使用,则%放在后面。否则不会使用索引。like ‘%abd%’不会使用索引,而like ‘aaa%’可以使用索引.(最左缀原则) 2、单列索引的使用: 《1》 只…

不同存储结构的文件磁盘io操作次数_MySQL InnoDB存储引擎

第1章 MySQL体系结构和存储引擎1.1数据库和实例数据库:物理操作系统文件或其他形式文件类型的集合。实例:MySQL数据库由后台线程以及一个共享内存区组成。共享内存可以被运行 的后台线程所共享。数据库实例才是真正用于操作数据库文件的。启动MySQL数据库…

我的模型--

from skimage import io, transform # skimage模块下的io transform(图像的形变与缩放)模块 import glob # glob 文件通配符模块 import os # os 处理文件和目录的模块 import tensorflow as tf import numpy as np # 多维数据处理模块 import time import matplotlib.pypl…

python蚁群算法 路径规划_蚁群算法(1) - Python实现

1 importnumpy as np2 importmatplotlib.pyplot as plt345 #建立“蚂蚁”类6 classAnt(object):7 def __init__(self, path):8 self.path path #蚂蚁当前迭代整体路径9 self.length self.calc_length(path) #蚂蚁当前迭代整体路径长度1011 def calc_length(self, path_): #pa…

win10-PC端无法输入中文

试过 任务管理器中,的 MscCtfMonitor任务,先选择结束,然后再选择运行。关闭后输入法就可重新使用了---不行 当出现Win10无法输入中文汉字时,首先我们需要重启一下“输入法”程序: 右击桌面“Windows”图标&#xff0c…

python变量和数据类型_python的变量和数据类型

1.Python的变量不用定义类型,每个语句后面也不用使用分号结束语句(不像java,C,C#要在变量声明后加上分号)如:message"hello python world"print(message)-----------------------------------age19print(age)2.字符串(1).在Python中用引号括起来的都是字符串, 其中的…

函数声明是形参类型省略

如果参数类型省略&#xff0c;默认为int类型。&#xff08;此为古老写法&#xff09; #include<stdio.h>float average(a,n) int a[]; {int j;float s0;float aver;for(j0;j<0;j){sa[j];}avers/n;return aver; }main() {int a[12]{10,4,2,7,3,12,5,34,5,9,6,8};print…

因果图中的约束关系

E:互斥&#xff0c;exclude&#xff0c;表示abc最多只能有一个1&#xff0c;即abc000&#xff0c;100&#xff0c;010&#xff0c;001&#xff0c;只能有1个1或者全0&#xff08;可不选&#xff0c;要选最多选一个&#xff09;。I:包含&#xff0c;include&#xff0c;表示abc不…

如何销毁一个实例化对象_JAVA中如何创建和销毁对象

第1条 考虑用静态方法代替构造器类可以通过静态工厂方法来提供它的客户端&#xff0c;而不是通过构造器。提供静态工厂方法而不是公有构造器&#xff0c;这样做具有几大优势。1.静态工厂方法与构造器不同的第一大优势在于&#xff0c;它们有名称。例如&#xff0c;构造器BigInt…

因果图-交通一卡通自动充值软件系统-实例分析

因果图法测试用例的设计步骤 &#xff08;1&#xff09;确定软件规格(需求)中的原因和结果 &#xff08;2&#xff09;确定原因和结果之间的逻辑关系 &#xff08;3&#xff09;确定因果图中的各个约束(constraints) &#xff08;4&#xff09;画出因果图并转换为决策表 &…

如何区分电梯卡为id卡ic卡_电梯刷卡系统基本属性

电梯刷卡控制系统的发展是十分迅速的&#xff0c;在这点上相信大家都有所体会。但是为了节约成本费用&#xff0c;很多地产商都是安装的基本常见的电梯刷卡控制系统&#xff0c;这种常见的电梯&#xff0c;能够满足基本上的用户需求&#xff0c;在零件上面也是能够与大多数的零…

python应用体系_python-大型django应用程序体系结构

如何适当地构建一个较大的Django网站,以保持可测试性和可维护性&#xff1f;本着最好的django精神(我希望),我们开始时不太关心网站不同部分之间的去耦.我们确实将其分为不同的应用程序,但是通过共同使用模型类和直接方法调用,它们直接相互依赖.这变得越来越纠结.例如,我们的一…

Postman入门到精通01

1、什么是接口&#xff1f; 电脑&#xff1a;USB&#xff0c;投影仪 作用&#xff1a;数据传输 软件&#xff1a;API&#xff08;application Program Interface&#xff09;&#xff0c;微信提现和充值接口&#xff0c;支付宝支付&#xff0c;银联支付接口&#xff08;鉴权…

python oracle orm_Python ORM

本章内容ORM介绍如果写程序用pymysql和程序交互&#xff0c;那是不是要写原生sql语句。如果进行复杂的查询&#xff0c;那sql语句就要进行一点一点拼接&#xff0c;而且不太有重用性&#xff0c;扩展不方便。而且写的sql语句可能不高效&#xff0c;导致程序运行也变慢。为了避免…

前端校验和后端校验区别

前台验证数据格式 后台验证的是数据的正确性 当下流行的系统架构方案中&#xff0c;前端和后端都是分离开的。 目的&#xff1a;① 为了方便前端开发人员和后端开发人员可以同时开发&#xff1b;② 前后端分离也使得前后端的代码可以分开进行管理&#xff0c;方便了各自的版…

unittest-ddt报错AttributeError: type object ‘forTestDDT‘ has no attribute ‘test_2‘

unittest 添加多个ddt数据驱动后&#xff0c;报错&#xff1a; FAILED (errors1)Error Traceback (most recent call last):File "D:\Anaconda3\lib\unittest\case.py", line 60, in testPartExecutoryieldFile "D:\Anaconda3\lib\unittest\case.py", lin…

socket timeout是什么引起的_MySQL C API 参数 MYSQL_OPT_READ_TIMEOUT 的一些行为分析

作者&#xff1a;戴岳兵MYSQL_OPT_READ_TIMEOUT 是 MySQL c api 客户端中用来设置读取超时时间的参数。在 MySQL 的官方文档中&#xff0c;该参数的描述是这样的&#xff1a;MYSQL_OPT_READ_TIMEOUT (argument type: unsigned int *)The timeout in seconds for each attempt t…

python动态爬取知乎_python爬虫从小白到高手 Day2 动态页面的爬取

今天我们说说动态页面的抓取&#xff0c;动态页面的概念不是说网页上的内容是活动的&#xff0c;而是刷新的内容由Ajax加载&#xff0c;页面的URL没有变化&#xff0c;具体概念问度娘。就以男人都喜欢的美女街拍为例&#xff0c;对象为今日头条。chrome打开今日头条 ->搜索开…

Python操作文件,报FileNotFoundError: [Error 2] No such file or directory错误

python操作文件时&#xff0c;报No such file or directory错误。 多次检查目录、文件名、语法都是对的。 折腾一番后&#xff0c;打开文件所在文件夹&#xff0c;并显示所有文件后缀名&#xff0c;才发现此文件并没有txt后缀名 解决方法&#xff1a; 添加文件的.txt后缀名&a…

python多标签分类_如何通过sklearn实现多标签分类?

sklearn支持多类别(Multiclass)分类和多标签(Multilabel)分类&#xff1a;多类别分类&#xff1a;超过两个类别的分类任务。多类别分类假设每个样本属于且仅属于一个标签&#xff0c;类如一个水果可以是苹果或者是桔子但是不能同时属于两者。多标签分类&#xff1a;给每个样本分…