在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

如何實現一套linux進程間通信的機制

科技綠洲 ? 來源:Linux開發架構之路 ? 作者:Linux開發架構之路 ? 2023-11-10 14:56 ? 次閱讀

我們知道linux的進程的間通信的組件有管道,消息隊列,socket, 信號量,共享內存等。但是我們如果自己實現一套進程間通信的機制的話,要怎么做?了解android 開發的可能會知道,android里面有個binder機制,簡單來說,就是一個進程往binder里面寫數據,另一個進程從binder里面讀出數據。

圖片

所以我們也可以按照binder的思路來設計一個自己的進程間通信組件。

原理

圖片

我們的設計思路很簡單,我們首先需要注冊一個字符設備文件叫**/dev/channel**, 同時需要為這個設備編寫驅動,此時某個進程A向設備文件寫數據,同時如果該設備可讀,我們就通知另一個進程B去讀該進程。 我們怎么知道該設備是否可讀可寫呢?使用poll來管理,因為該設備驅動屬于一個IO, 打開一個設備就有fd, 有了fd我們就可以使用poll來管理。

代碼實現

首先驅動程序:

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


#ifndef CHANNEL_MAJOR
#define CHANNEL_MAJOR 96
#endif

#ifndef CHANNEL_NR_DEVS
#define CHANNEL_NR_DEVS 2
#endif

#ifndef CHANNEL_SIZE
#define CHANNEL_SIZE 4096
#endif

#define ENABLE_POLL 1

struct channel {
char *data;
unsigned long size;
#if ENABLE_POLL
wait_queue_head_t inq;
#endif
};

static int channel_major = CHANNEL_MAJOR;
module_param(channel_major, int, S_IRUGO);

struct channel *channel_devp;
struct cdev cdev;

char have_data = 0;

int channel_open (struct inode *inode, struct file *filp) {
struct channel *channel;

int num = MINOR(inode->i_rdev); //設備讀了多少次
if (num >= CHANNEL_NR_DEVS)
return -ENODEV;

channel = &channel_devp[num];
filp->private_data = channel;

return 0;
}

int channel_release (struct inode *inode, struct file *filp) {
return 0;
}

#if ENABLE_POLL
unsigned int channel_poll (struct file *filp, struct poll_table_struct *wait) {
struct channel *channel = filp->private_data;
unsigned int mask = 0;

poll_wait(filp, &channel->inq, wait); // poll 阻塞

if (have_data)
mask |= (POLLIN | POLLRDNORM);

return mask;
}
#endif


int channel_mmap (struct file *filp, struct vm_area_struct *vma) {
struct channel *channel = filp->private_data;

vma->vm_flags |= VM_IO;
vma->vm_flags |= (VM_DONTEXPAND | VM_DONTDUMP);

if (remap_pfn_range(vma, vma->vm_start, virt_to_phys(channel->data) >> PAGE_SHIFT,
vma->vm_end-vma->vm_start, vma->vm_page_prot)) {
return -EAGAIN;
}

return 0;
}

ssize_t channel_read (struct file *filp, char __user * buffer, size_t size, loff_t *ppos) {
unsigned long p = *ppos;
unsigned int count = size;

int ret = 0;
struct channel *channel = filp->private_data; // 讀私有空間

if (p >= CHANNEL_SIZE) return 0;
if (count > CHANNEL_SIZE- p)
count = CHANNEL_SIZE- p;

#if ENABLE_POLL
while (!have_data) {
if (filp->f_flags & O_NONBLOCK) return -EAGAIN;

wait_event_interruptible(channel->inq, have_data);
}
#endif
if (copy_to_user(buffer, (void*)(channel->data + p), count)) { //拷貝到用戶空間
ret = -EFAULT;
} else {
ret = strlen(buffer);
channel->size -= ret;
printk(KERN_INFO "read %d byte(s) from %ldn", ret, p);
}

have_data = 0;
return ret;
}

ssize_t channel_write (struct file *filp , const char __user * buffer, size_t size, loff_t *ppos) {
int ret = 0;
unsigned long p = *ppos;
unsigned int count = size;

struct channel *channel = filp->private_data; // 寫道文件的私有空間
if (p >= CHANNEL_SIZE) return 0;
if (count > CHANNEL_SIZE- p)
count = CHANNEL_SIZE- p;

if (copy_from_user(channel->data +p, buffer, count)) { // 從user -> kernel
return -EFAULT;
} else {
*ppos += count;
ret = count;
channel->size += count;
*(channel->data+p + count) = '?';

printk(KERN_INFO "written %d byte(s) from %ldn", count, p);
}

#if ENABLE_POLL
have_data = 1;
wake_up(&channel->inq);
#endif

return ret;
}

loff_t channel_llseek (struct file *filp, loff_t offset, int whence) { //偏移
loff_t newpos;

switch (whence)
{
case 0:
newpos = offset;
break;
case 1:
newpos = filp->f_pos + offset;
break;
case 2:
newpos = CHANNEL_SIZE - 1 + offset;
break;
default:
return -EINVAL;
}

if (newpos < 0 || newpos > CHANNEL_SIZE) return -EINVAL;

filp->f_pos = newpos;

return newpos;
}

static const struct file_operations channel_fops =
{
.owner = THIS_MODULE,
.llseek = channel_llseek,
.read = channel_read,
.write = channel_write,
.open = channel_open,
.release = channel_release,
.poll = channel_poll,
.mmap = channel_mmap,
};


static int channel_init(void) {
int reslut;
int i;

dev_t devno = MKDEV(channel_major, 0); // 創建一個主設備號為96,次設備號為0的設備
if (channel_major) {
reslut = register_chrdev_region(devno, CHANNEL_NR_DEVS, "channel"); // 注冊設備
} else {
reslut = alloc_chrdev_region(&devno, 0, CHANNEL_NR_DEVS, "channel");
}

if (reslut < 0) return reslut;

cdev_init(&cdev, &channel_fops); //初始化字符設備
cdev.owner = THIS_MODULE;

cdev_add(&cdev, MKDEV(channel_major, 0), CHANNEL_NR_DEVS); //添加到字符設備中

channel_devp = kmalloc(CHANNEL_NR_DEVS *sizeof(struct channel), GFP_KERNEL); //為 我們的buffer 分配一塊空間
if (!channel_devp) {
reslut = -ENOMEM;
goto fail_malloc;
}
memset(channel_devp, 0, sizeof(struct channel));

for (i = 0; i < CHANNEL_NR_DEVS; i++) {
channel_devp[i].size = CHANNEL_SIZE;
channel_devp[i].data = kmalloc(CHANNEL_SIZE, GFP_KERNEL);
memset(channel_devp[i].data, 0, CHANNEL_SIZE);
#if ENABLE_POLL
init_waitqueue_head(&(channel_devp[i].inq));
#endif
}
printk(KERN_INFO "ntychannel_init");

return 0;
fail_malloc:
unregister_chrdev_region(devno, 1);
return reslut;
}

static void channel_exit(void) {
printk(KERN_INFO "channel_exit");
cdev_del(&cdev);
kfree(channel_devp);

unregister_chrdev_region(MKDEV(channel_major, 0), 2);
}


MODULE_AUTHOR("birate");
MODULE_LICENSE("GPL");

module_init(channel_init); // 設備初始化
module_exit(channel_exit); //設備退出

編寫Makefile文件:

obj-m += channel.o
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
all:
make -C $(KERNELDIR) M=$(PWD) modules
clean:
make -C $(KERNELDIR) M=$(PWD) clean
  1. 使用 make 命令。編譯出我們需要的channel.ko文件。
  2. 使用 insmod channel.ko, 向kernel中插入 我們的module
  3. 使用mknod /dev/channel c 96 0, 創建一個/dev/channel 的字符設備,主設備號為96,次設備號為0;

編寫我們的應用程序:

channel_app.c

#include
#include
#include

#include
#include
#include
#include
#include

#include

#define BUFFER_LENGTH 128

int main () {
int fd = open("/dev/channel", O_RDWR);
if (fd < 0) {
printf("open failed: errno : %sn", strerror(errno));
return -1;
}

char *buffer = (char *)malloc(BUFFER_LENGTH);
memset(buffer, 0, BUFFER_LENGTH);

char *start = mmap(NULL, BUFFER_LENGTH, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);

fd_set rds;
FD_ZERO(&rds);
FD_SET(fd, &rds);

while(1) {
int ret = select(fd+1, &rds, NULL, NULL, NULL);
if (ret < 0) {
printf("select errorn");
exit(1);
}
if (FD_ISSET(fd, &rds)) {
#if 0
strcpy(buffer, start);
printf("channel: %sn", buffer);
#else
read(fd, buffer, BUFFER_LENGTH);
printf("channel: %sn", buffer);
#endif
}
}

munmap(start, BUFFER_LENGTH);
free(buffer);
close(fd);

return 0;
}

應用程序很簡單,我們使用 gcc -o channel_app channel_app.c , 編譯出可執行文件,在一個進程中執行channel_app, 另一個進程使用echo " " > /dev/channel 去向設備文件中寫就可以了。

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 數據
    +關注

    關注

    8

    文章

    7246

    瀏覽量

    91251
  • 通信
    +關注

    關注

    18

    文章

    6183

    瀏覽量

    137458
  • Linux
    +關注

    關注

    87

    文章

    11473

    瀏覽量

    212988
  • 字符
    +關注

    關注

    0

    文章

    234

    瀏覽量

    25500
  • 組件
    +關注

    關注

    1

    文章

    531

    瀏覽量

    18332
收藏 人收藏

    評論

    相關推薦
    熱點推薦

    Linux進程如何實現共享內存通信

    這次我們來講Linux進程通信中重要的通信方式:共享內存作為Linux軟件開發攻城獅,
    發表于 04-26 17:14 ?799次閱讀

    linux操作系統下的進程通信設計

    )的進程通信機制Linux則把兩者繼承了下來,如圖示:其中,最初Unix IPC包括:管道、FIFO、信號;System V IPC包括
    發表于 04-16 09:17

    Linux進程通信方式-管道

    Linux進程通信方式-管道分享到: 本文關鍵字: linux 管道通信
    發表于 08-29 15:29

    Linux進程通信

    華清遠見嵌入式linux學習資料《Linux進程通信》,通過前面的學習,讀者已經知道了進程
    發表于 09-04 10:07

    Linux學習雜談】之進程通信

    本帖最后由 michael_llh 于 2016-10-17 13:14 編輯 我們在Linux應用編程當中如果需要用到多個進程來完成個任務的話那么我們就沒有辦法避開進程
    發表于 10-15 14:45

    Linux進程通信——使用共享內存

    Linux進程通信——使用共享內存 圖文詳情見附件
    發表于 11-21 10:53

    Linux現有的所有進程IPC方式

    在開始回答前,先簡單概括性地說說Linux現有的所有進程IPC方式:1. **管道:**在創建時分配個page大小的內存,緩存區大小比較有限;2. 消息隊列:信息復制兩次,額外的C
    發表于 08-20 06:17

    哪些方式可以實現Linux系統下的進程通信

    哪些方式可以實現Linux系統下的進程通信進程與線程有哪些不同之處呢?
    發表于 12-24 06:38

    進程通信Linux進程通信概述

    人們現在廣泛使用的手機等方式。本章就是講述如何建立這些不同的通話方式,就像人們有多種通信方式樣。 Linux下的進程通信手段基本上是從UN
    發表于 10-18 16:21 ?0次下載

    進程與線程通信方式

    進程通信則不同,它的數據空間的獨立性決定了它的通信相對比較復雜,需要通過操作系統。以前進程
    的頭像 發表于 04-09 15:58 ?9137次閱讀
    <b class='flag-5'>進程</b><b class='flag-5'>間</b>與線程<b class='flag-5'>間</b>的<b class='flag-5'>通信</b>方式

    你知道linux socket進程通信是怎樣實現的?

    socket進程通信與網絡通信使用的是統一套接口,只是地址結構與某些參數不同
    發表于 04-23 14:49 ?2757次閱讀
    你知道<b class='flag-5'>linux</b> socket<b class='flag-5'>進程</b><b class='flag-5'>通信</b>是怎樣<b class='flag-5'>實現</b>的?

    Linux進程通信

    進程通信概述進程通信有如下
    發表于 04-02 14:46 ?576次閱讀

    Linux進程通信方式——管道

    管道是Linux進程通信種方式,它把個程序的輸出直接連接到另
    發表于 06-01 09:13 ?1601次閱讀
    <b class='flag-5'>Linux</b><b class='flag-5'>進程</b><b class='flag-5'>間</b><b class='flag-5'>通信</b>方式——管道

    Linux進程通信方法之管道

    上文中我們介紹了進程通信的方法之:信號,本文將繼續介紹另進程
    的頭像 發表于 05-14 15:47 ?2188次閱讀
    <b class='flag-5'>Linux</b><b class='flag-5'>進程</b><b class='flag-5'>間</b><b class='flag-5'>通信</b>方法之管道

    進程通信機制有哪些

    比較難,Linux內核提供了多種進程通信機制。 同
    的頭像 發表于 07-21 11:23 ?1246次閱讀
    <b class='flag-5'>進程</b><b class='flag-5'>間</b><b class='flag-5'>通信</b>的<b class='flag-5'>機制</b>有哪些
    主站蜘蛛池模板: 色男人综合 | 日产精品卡二卡三卡四卡无卡乱码 | 日日碰狠狠添天天爽五月婷 | 三级黄色在线 | 日韩午夜r电影在线观看 | 黄色a毛片 | 欧美色图日韩色图 | 日韩精品一区二区在线观看 | 1024手机在线看片 | 中文字幕一区在线观看 | 亚洲综合区图片小说区 | 五月天婷婷一区二区三区久久 | 手机看片国产免费现在观看 | 狠狠要 | 久久在线播放 | 粉嫩尤物在线456 | 免费高清一级欧美片在线观看 | 人人草人人干 | 亚洲伦理一区二区三区 | 护士一级aaaaaa毛片 | 欧美一级欧美三级在线观看 | 美女扒开腿让男生桶爽网站 | 一级一片一a一片 | 黄色录像大全 | 你懂在线| 手机看片福利盒子久久青 | 26uuu欧美性色 | 天天做天天干 | 高清不卡毛片免费观看 | 性福利视频 | 一级特黄aaa大片在线观看视频 | 狠狠干网| 天堂视频在线 | 你懂的手机在线观看 | 亚洲午夜久久 | 第一福利在线 | 天天寡妇色 | 天堂资源在线播放 | 色九| 网色| 免费视频黄 |