栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 系统运维 > 运维 > Linux

Linux下编写内核模块实现1对1聊天以及多发多收实现

Linux 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Linux下编写内核模块实现1对1聊天以及多发多收实现

Linux内核模块聊天程序 一对一聊天程序

设计一个信号量,当有人写入时唤醒读出程序,从内核缓冲区读出数据

内核的新建,实例与卸载相关代码可以自行查询,一对一只需设置一个信号量即可实现

内核驱动
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define MAXNUM 100
#define MAJOR_NUM 290

struct dev{
	struct cdev devm;  //字符设备
	struct semaphore sem; //PV操作
	wait_queue_head_t outq;
	int flag; //唤醒标志
	char buffer[MAXNUM + 1];
	char *rd, *wr, *end;
}globalvar;

static struct class *my_class;

int major = MAJOR_NUM;

static ssize_t globalvar_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos)
{
    if(wait_event_interruptible(globalvar.outq, globalvar.flag!=0)) //不可读时 阻塞读进程
    {
        return -ERESTARTSYS;
    }
    
    if(down_interruptible(&globalvar.sem)) //P 操作
    {
        return -ERESTARTSYS;
    }
    
    globalvar.flag = 0;
    
    if(globalvar.rd < globalvar.wr)
        len = min(len,(size_t)(globalvar.wr - globalvar.rd)); //更新读写长度
    else
        len = min(len,(size_t)(globalvar.end - globalvar.rd));
  
    if(copy_to_user(buf,globalvar.rd,len))
    {
        printk(KERN_alert"copy failedn");
        up(&globalvar.sem);
        return -EFAULT;
    }
    
    globalvar.rd = globalvar.rd + len;
    
    if(globalvar.rd == globalvar.end)
        globalvar.rd = globalvar.buffer; //字符缓冲区循环
    
    up(&globalvar.sem); //V 操作
    
    return len;
}

static ssize_t globalvar_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos)
{
	if(down_interruptible(&globalvar.sem)) //P 操作
    {
        return -ERESTARTSYS;
    }
    
    if(globalvar.rd <= globalvar.wr)
        len = min(len,(size_t)(globalvar.end - globalvar.wr));
    else
        len = min(len,(size_t)(globalvar.rd - globalvar.wr-1));
    
    if(copy_from_user(globalvar.wr,buf,len))
    {
        up(&globalvar.sem); //V 操作
        return -EFAULT;
    }

    globalvar.wr = globalvar.wr + len;
    
    if(globalvar.wr == globalvar.end)
    	globalvar.wr = globalvar.buffer; //循环
    
    up(&globalvar.sem);//V 操作
    
    globalvar.flag = 1; //条件成立,可以唤醒读进程
    
    wake_up_interruptible(&globalvar.outq); //唤醒读进程
    
    return len;
}

static int globalvar_open(struct inode *inode,struct file *filp)
{
	try_module_get(THIS_MODULE); //模块计数加一
    printk("This chrdev is in openn");
    return(0);
}

static int globalvar_release(struct inode *inode,struct file *filp)
{
    module_put(THIS_MODULE); //模块计数减一
    printk("This chrdev is in releasen");
    return(0);
}

struct file_operations globalvar_fops =
{
	.read = globalvar_read,
	.write = globalvar_write,
	.open = globalvar_open,
	.release = globalvar_release,
};

int globalvar_init(void)
{
	dev_t dev = MKDEV(major, 0);

	int result;

	if(major)
    {
        //静态申请设备编号
        result = register_chrdev_region(dev, 1, "charmem");
    }
    else
    {
        //动态分配设备号
        result = alloc_chrdev_region(&dev, 0, 1, "charmem");
        major = MAJOR(dev);
    }

	if(result < 0)
		return result;

	cdev_init(&globalvar.devm, &globalvar_fops);
	globalvar.devm.owner = THIS_MODULE;
	cdev_add(&globalvar.devm, dev, 1);

	sema_init(&globalvar.sem, 1);
	init_waitqueue_head(&globalvar.outq);
	globalvar.rd = globalvar.buffer;
	globalvar.wr = globalvar.buffer;
	globalvar.end = globalvar.buffer + MAXNUM;
	globalvar.flag = 0;

    my_class = class_create(THIS_MODULE, "chardev0");
    device_create(my_class, NULL, dev, NULL, "chardev0");

    return 0;
}

static void globalvar_exit(void)
{
	device_destroy(my_class, MKDEV(major, 0));
    class_destroy(my_class);
    cdev_del(&globalvar.devm);
    unregister_chrdev_region(MKDEV(major, 0), 1);
}

module_init(globalvar_init);
module_exit(globalvar_exit);
MODULE_LICENSE("GPL");
读者模块
#include   //read
#include
#include
#include
#include
#include
int main()
{
    int fd,i;
    char msg[101];
    fd= open("/dev/chardev0",O_RDWR,S_IRUSR|S_IWUSR);
    
    if(fd!=-1)
    {
        while(1)
        {
            for(i=0;i<101;i++)  //初始化
                msg[i]='';
            
            read(fd,msg,100);
            printf("%sn",msg);
            
            if(strcmp(msg,"quit()")==0)
            {
                close(fd);
                break;
            }
        }
    }
    else
    {
        printf("device open failure,%dn",fd);
    }
    return 0;
}
写者模块
#include   //writer
#include
#include
#include
#include
#include
int main()
{
    int fd;
    char msg[100];
    fd= open("/dev/chardev0",O_RDWR,S_IRUSR|S_IWUSR);
    
    if(fd!=-1)
    {
        while(1)
        {
            printf("Please input the globar:n");
            scanf("%s",msg);
            write(fd,msg,strlen(msg));
            
            if(strcmp(msg,"quit()")==0)
            {
                close(fd);
                break;
            }
        }
    }
    else
    {
        printf("device open failuren");
    }
    return 0;
}
Makefile文件
CONFIG_MODULE_SIG=n

ifneq ($(KERNELRELEASE),)
        obj-m :=dev.o
else
        KERNELDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
modules:
	$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
clean:
	$(MAKE) -C $(KERNELDIR) M=$(PWD) clean
endif
多对多群聊

这里实现的是多写者多读者
这里需要设计一下,因为一对一是只要有写者写了,读者就会被唤醒,但是当有多个读者时,如何唤醒多个读者?如何确保每个读者只读一次?
这里修改了原本的唤醒信号量flag,又增加了一个等待队列,用来存放已经读了一次数据的读者。

Flag值为拥有的读进程个数,有几个读进程就有几个flag,因此读一次可以唤醒n个写进程
还需要另外一个互斥量,就是当多个读者一起读时,每个进程只能读一次,因此:

当读者读了一次时,并且还有其他读者没读(flag!=0),需要把读进程阻塞,当且仅当最后一个读进程读完时,读进程被唤醒。

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

//.................
#include 
//...................

#include 

#define MAXNUM 100
#define MAJOR_NUM 290

struct dev{
	struct cdev devm;  //zi fu she bei
	struct semaphore sem; //PV
	wait_queue_head_t outq,que;
	int flag; //huan xing
	char buffer[MAXNUM + 1];
	char *rd, *wr, *end;
}globalvar;

//................
static struct class *my_class;
//................

int major = MAJOR_NUM;
int num = -1;
int copy_num;

static ssize_t globalvar_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos)
{
    if(wait_event_interruptible(globalvar.outq, globalvar.flag!=0)) //不可读时 阻塞读进程,0 sleep   1wake up
    {
        return -ERESTARTSYS;
    }
    
    // bu bei zu se
    if(down_interruptible(&globalvar.sem)) //P 操作
    {
        return -ERESTARTSYS;
    }
    
    //yao rang bie ren du
    globalvar.flag--;
    if(copy_to_user(buf,globalvar.rd,len))
    {
        printk(KERN_alert"copy failedn");
        up(&globalvar.sem);
        return -EFAULT;
    }
    copy_num--;
    up(&globalvar.sem); //V 操作
    if(wait_event_interruptible(globalvar.que, copy_num == 0)) //不可读时 阻塞读进程,0 sleep   1wake up
    {
        return -ERESTARTSYS;
    }
    if(copy_num==0) wake_up_interruptible(&globalvar.que);
    return len;
}

static ssize_t globalvar_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos)
{
	if(down_interruptible(&globalvar.sem)) //P 操作
    {
        return -ERESTARTSYS;
    }
    
    if(copy_from_user(globalvar.wr,buf,100))
    {
        up(&globalvar.sem); //V 操作
        return -EFAULT;
    }
    up(&globalvar.sem);//V 操作
    
    globalvar.flag = num; //条件成立,可以唤醒读进程
    copy_num = num;
    wake_up_interruptible(&globalvar.outq); //唤醒读进程
    
    return len;
}

static int globalvar_open(struct inode *inode,struct file *filp)
{
	num++;
	try_module_get(THIS_MODULE); //模块计数加一
    	printk("This chrdev is in openn");
    	return(0);
}

static int globalvar_release(struct inode *inode,struct file *filp)
{
    num--;
    module_put(THIS_MODULE); //模块计数减一
    printk("This chrdev is in releasen");
    return(0);
}

struct file_operations globalvar_fops =
{
	.read = globalvar_read,
	.write = globalvar_write,
	.open = globalvar_open,
	.release = globalvar_release,
};

int globalvar_init(void)
{
	//major and mijor to the place in table
	dev_t dev = MKDEV(major, 0);
	int err = 0;
	int result = 0;
	//register
	if(major)
    {
        //静态申请设备编号
        result = register_chrdev_region(dev, 1, "charmem");
    }
    else
    {
        //动态分配设备号
        result = alloc_chrdev_region(&dev, 0, 1, "charmem");
        major = MAJOR(dev);
    }
	//failure
	if(result < 0)
		return result;

	cdev_init(&globalvar.devm, &globalvar_fops);
	globalvar.devm.owner = THIS_MODULE;
	err = cdev_add(&globalvar.devm, dev, 1);
	if(err)
		printk(KERN_INFO"Error %d adding char_mem device",err);
	else{
	//sema init
	sema_init(&globalvar.sem, 1);
	//waitquere init
	init_waitqueue_head(&globalvar.outq);
	init_waitqueue_head(&globalvar.que);
	
	globalvar.rd = globalvar.buffer;
	globalvar.wr = globalvar.buffer;
	globalvar.end = globalvar.buffer + MAXNUM;
	globalvar.flag = 0;
	}
    	
    	//.............................
    	my_class = class_create(THIS_MODULE, "chardev0");
    	device_create(my_class, NULL, dev, NULL, "chardev0");
	//..............................
    return 0;
}

static void globalvar_exit(void)
{
	//...........................................
	device_destroy(my_class, MKDEV(major, 0));
	class_destroy(my_class);
	//.............................................
	
	cdev_del(&globalvar.devm);
	unregister_chrdev_region(MKDEV(major, 0), 1);
}

module_init(globalvar_init);
module_exit(globalvar_exit);
MODULE_LICENSE("GPL");

读写程序和Makefile文件相同

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/746747.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号