python 网络编程 异步io_异步IO实现 小例(程序+驱动程序)
結(jié)合阻塞與非阻塞訪問、poll 函數(shù)可以較好地解決設(shè)備的讀寫,但是如果有了異步通知就更方便了。異步通知的意思是:一旦設(shè)備就緒,則主動(dòng)通知應(yīng)用程序,這樣應(yīng)用程序根本就不需要查詢設(shè)備狀態(tài),這一點(diǎn)非常類似于硬件上“中斷”地概念,比較準(zhǔn)確的稱謂是:信號驅(qū)動(dòng)(SIGIO)的異步 I/O。可以使用signal()函數(shù)來設(shè)置對應(yīng)的信號的處理函數(shù)。函數(shù)原型是:
void (*signal(int signo,void (*func)(int))) (int)
我們先來看一個(gè)使用信號驅(qū)動(dòng)的例子,通過signal(SIGIO,input_handler) 對打開的文件fd 啟動(dòng)信號機(jī)制,輸入可獲得時(shí)inputhandler被調(diào)用,代碼如下:
/*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;//啟動(dòng)信號驅(qū)動(dòng)機(jī)制 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);//最后進(jìn)入一個(gè)死循環(huán),程序什么都不干了,只有信號能激發(fā) input_handler 的運(yùn)行//如果程序中沒有這個(gè)死循環(huán),會(huì)立即執(zhí)行完畢 while (1);return 0;
}
下面來解釋一下上面的代碼。為了一個(gè)用戶在用戶空間中能處理一個(gè)設(shè)備釋放的信號,它必須完成一下3份工作:
1)通過F_SETOWN控制指令設(shè)置設(shè)備文件的擁有者為本進(jìn)程,這樣從設(shè)備驅(qū)動(dòng)中發(fā)出的信號才能被本進(jìn)程收到。
2)通過F_SETFL 控制命令設(shè)置設(shè)備文件支持FASYNC,即異步通知模式。
3)通過signal()鏈接信號和信號處理函數(shù)。
有了信號的發(fā)送,那么就一定得有信號的釋放了:
在設(shè)備驅(qū)動(dòng)和應(yīng)用程序的異步通知交互中,僅僅在應(yīng)用程序端捕獲信號是不夠的,因?yàn)樾盘枦]有的源頭是在驅(qū)動(dòng)端,因此要在適當(dāng)?shù)臅r(shí)機(jī)讓設(shè)備驅(qū)動(dòng)釋放信號。
為了使設(shè)備支持異步通知機(jī)制,驅(qū)動(dòng)程序中涉及三個(gè)操作:
1)支持F_SETOWN命令,能在這個(gè)控制命令處理中設(shè)置filp->f_owner為對應(yīng)的進(jìn)程ID。不過此項(xiàng)工作已由內(nèi)核完成,設(shè)備驅(qū)動(dòng)無須處理。
2)支持F_SETFL命令的處理,每當(dāng)FASYNC標(biāo)志改變時(shí),驅(qū)動(dòng)程序中fasync()函數(shù)將得以進(jìn)行。因此,驅(qū)動(dòng)程序必須實(shí)現(xiàn)fasync()函數(shù)。
3)在設(shè)備資源可獲得時(shí),調(diào)用kill_fasync()函數(shù)激發(fā)相應(yīng)的信號。
驅(qū)動(dòng)程序中上面的三步是和應(yīng)用程序是一一對應(yīng)的。如下圖:
設(shè)備驅(qū)動(dòng)中異步通知編程還是比較簡單的,主要就是一些數(shù)據(jù)結(jié)構(gòu),和兩個(gè)函數(shù):
數(shù)據(jù)結(jié)構(gòu):fasync_struct結(jié)構(gòu)體
函數(shù):1)處理FASYNC標(biāo)志變更的函數(shù)int fasync_helper(int fd, struct file *filp, int mode ,struct fasync_struct **fa);
2) 釋放信號用的函數(shù)void kill_fasync(struct fasync_struct **fa, int sig, int band);
和其他設(shè)備驅(qū)動(dòng)一樣,一般將fasync_struct放到設(shè)備結(jié)構(gòu)體中。
下面給出驅(qū)動(dòng)程序部分實(shí)現(xiàn)支持異步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結(jié)構(gòu)體*/
dev_t? dev;
char? mem[LEN];
int?? flag ;
struct semaphore sem; /*并發(fā)控制用的信號量*/
wait_queue_head_t r_wait; /*阻塞讀用的等待隊(duì)列頭*/
struct fasync_struct *async_queue; /* 異步結(jié)構(gòu)體指針,用于讀 */
};
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);
}
/*文件釋放函數(shù)*/
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);
應(yīng)用程序?qū)崿F(xiàn)寫入功能:
/*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”進(jìn)行編譯,加載驅(qū)動(dòng)之后,開兩個(gè)終端,分別運(yùn)行async_io_app 和 async_io_app_w,當(dāng)async_io_app_w有數(shù)據(jù)寫入的時(shí)候,async_io_app的終端會(huì)打印所寫入的數(shù)據(jù),當(dāng)然內(nèi)核也會(huì)打印數(shù)據(jù),下面是結(jié)果:
說明:上面圖是三個(gè)終端的打印結(jié)果,從左到右一次是async_io_app_w , async_io_app 和使用dmesg 打印內(nèi)核的結(jié)果。
注:我本來也想用代碼格式,但是感覺在vim上排版很舒服的,上來用代碼格式反而還不好看了,于是就這樣了
總結(jié)
以上是生活随笔為你收集整理的python 网络编程 异步io_异步IO实现 小例(程序+驱动程序)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python数据预测代码_手把手教你用P
- 下一篇: perl python ruby_per