99精品伊人亚洲|最近国产中文炮友|九草在线视频支援|AV网站大全最新|美女黄片免费观看|国产精品资源视频|精彩无码视频一区|91大神在线后入|伊人终合在线播放|久草综合久久中文

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

如何實(shí)現(xiàn)一套linux進(jìn)程間通信的機(jī)制

科技綠洲 ? 來(lái)源:Linux開(kāi)發(fā)架構(gòu)之路 ? 作者:Linux開(kāi)發(fā)架構(gòu)之路 ? 2023-11-10 14:56 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

我們知道linux的進(jìn)程的間通信的組件有管道,消息隊(duì)列,socket, 信號(hào)量,共享內(nèi)存等。但是我們?nèi)绻约簩?shí)現(xiàn)一套進(jìn)程間通信的機(jī)制的話,要怎么做?了解android 開(kāi)發(fā)的可能會(huì)知道,android里面有個(gè)binder機(jī)制,簡(jiǎn)單來(lái)說(shuō),就是一個(gè)進(jìn)程往binder里面寫數(shù)據(jù),另一個(gè)進(jìn)程從binder里面讀出數(shù)據(jù)。

圖片

所以我們也可以按照binder的思路來(lái)設(shè)計(jì)一個(gè)自己的進(jìn)程間通信組件。

原理

圖片

我們的設(shè)計(jì)思路很簡(jiǎn)單,我們首先需要注冊(cè)一個(gè)字符設(shè)備文件叫**/dev/channel**, 同時(shí)需要為這個(gè)設(shè)備編寫驅(qū)動(dòng),此時(shí)某個(gè)進(jìn)程A向設(shè)備文件寫數(shù)據(jù),同時(shí)如果該設(shè)備可讀,我們就通知另一個(gè)進(jìn)程B去讀該進(jìn)程。 我們?cè)趺粗涝撛O(shè)備是否可讀可寫呢?使用poll來(lái)管理,因?yàn)樵撛O(shè)備驅(qū)動(dòng)屬于一個(gè)IO, 打開(kāi)一個(gè)設(shè)備就有fd, 有了fd我們就可以使用poll來(lái)管理。

代碼實(shí)現(xiàn)

首先驅(qū)動(dòng)程序:

#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); //設(shè)備讀了多少次
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); // 創(chuàng)建一個(gè)主設(shè)備號(hào)為96,次設(shè)備號(hào)為0的設(shè)備
if (channel_major) {
reslut = register_chrdev_region(devno, CHANNEL_NR_DEVS, "channel"); // 注冊(cè)設(shè)備
} else {
reslut = alloc_chrdev_region(&devno, 0, CHANNEL_NR_DEVS, "channel");
}

if (reslut < 0) return reslut;

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

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

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); // 設(shè)備初始化
module_exit(channel_exit); //設(shè)備退出

編寫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, 創(chuàng)建一個(gè)/dev/channel 的字符設(shè)備,主設(shè)備號(hào)為96,次設(shè)備號(hào)為0;

編寫我們的應(yīng)用程序:

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;
}

應(yīng)用程序很簡(jiǎn)單,我們使用 gcc -o channel_app channel_app.c , 編譯出可執(zhí)行文件,在一個(gè)進(jìn)程中執(zhí)行channel_app, 另一個(gè)進(jìn)程使用echo " " > /dev/channel 去向設(shè)備文件中寫就可以了。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 數(shù)據(jù)
    +關(guān)注

    關(guān)注

    8

    文章

    7256

    瀏覽量

    91833
  • 通信
    +關(guān)注

    關(guān)注

    18

    文章

    6206

    瀏覽量

    137802
  • Linux
    +關(guān)注

    關(guān)注

    87

    文章

    11509

    瀏覽量

    213748
  • 字符
    +關(guān)注

    關(guān)注

    0

    文章

    237

    瀏覽量

    25593
  • 組件
    +關(guān)注

    關(guān)注

    1

    文章

    532

    瀏覽量

    18420
收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評(píng)論

    相關(guān)推薦
    熱點(diǎn)推薦

    Linux進(jìn)程如何實(shí)現(xiàn)共享內(nèi)存通信

    這次我們來(lái)講Linux進(jìn)程通信中重要的通信方式:共享內(nèi)存作為Linux軟件開(kāi)發(fā)攻城獅,
    發(fā)表于 04-26 17:14 ?820次閱讀

    linux操作系統(tǒng)下的進(jìn)程通信設(shè)計(jì)

    )的進(jìn)程通信機(jī)制。Linux則把兩者繼承了下來(lái),如圖示:其中,最初Unix IPC包括:管道、FIFO、信號(hào);System V IPC包括
    發(fā)表于 04-16 09:17

    Linux進(jìn)程通信方式-管道

    Linux進(jìn)程通信方式-管道分享到: 本文關(guān)鍵字: linux 管道通信,
    發(fā)表于 08-29 15:29

    Linux進(jìn)程通信

    華清遠(yuǎn)見(jiàn)嵌入式linux學(xué)習(xí)資料《Linux進(jìn)程通信》,通過(guò)前面的學(xué)習(xí),讀者已經(jīng)知道了進(jìn)程
    發(fā)表于 09-04 10:07

    Linux學(xué)習(xí)雜談】之進(jìn)程通信

    本帖最后由 michael_llh 于 2016-10-17 13:14 編輯 我們?cè)?b class='flag-5'>Linux應(yīng)用編程當(dāng)中如果需要用到多個(gè)進(jìn)程來(lái)完成個(gè)任務(wù)的話那么我們就沒(méi)有辦法避開(kāi)進(jìn)程
    發(fā)表于 10-15 14:45

    Linux進(jìn)程通信——使用共享內(nèi)存

    Linux進(jìn)程通信——使用共享內(nèi)存 圖文詳情見(jiàn)附件
    發(fā)表于 11-21 10:53

    Linux現(xiàn)有的所有進(jìn)程IPC方式

    在開(kāi)始回答前,先簡(jiǎn)單概括性地說(shuō)說(shuō)Linux現(xiàn)有的所有進(jìn)程IPC方式:1. **管道:**在創(chuàng)建時(shí)分配個(gè)page大小的內(nèi)存,緩存區(qū)大小比較有限;2. 消息隊(duì)列:信息復(fù)制兩次,額外的C
    發(fā)表于 08-20 06:17

    哪些方式可以實(shí)現(xiàn)Linux系統(tǒng)下的進(jìn)程通信

    哪些方式可以實(shí)現(xiàn)Linux系統(tǒng)下的進(jìn)程通信進(jìn)程與線程有哪些不同之處呢?
    發(fā)表于 12-24 06:38

    進(jìn)程通信Linux進(jìn)程通信概述

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

    進(jìn)程與線程通信方式

    進(jìn)程通信則不同,它的數(shù)據(jù)空間的獨(dú)立性決定了它的通信相對(duì)比較復(fù)雜,需要通過(guò)操作系統(tǒng)。以前進(jìn)程
    的頭像 發(fā)表于 04-09 15:58 ?9162次閱讀
    <b class='flag-5'>進(jìn)程</b><b class='flag-5'>間</b>與線程<b class='flag-5'>間</b>的<b class='flag-5'>通信</b>方式

    你知道linux socket進(jìn)程通信是怎樣實(shí)現(xiàn)的?

    socket進(jìn)程通信與網(wǎng)絡(luò)通信使用的是統(tǒng)一套接口,只是地址結(jié)構(gòu)與某些參數(shù)不同
    發(fā)表于 04-23 14:49 ?2775次閱讀
    你知道<b class='flag-5'>linux</b> socket<b class='flag-5'>進(jìn)程</b><b class='flag-5'>通信</b>是怎樣<b class='flag-5'>實(shí)現(xiàn)</b>的?

    Linux進(jìn)程通信

    、進(jìn)程通信概述進(jìn)程通信有如下
    發(fā)表于 04-02 14:46 ?585次閱讀

    Linux進(jìn)程通信方式——管道

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

    Linux進(jìn)程通信方法之管道

    上文中我們介紹了進(jìn)程通信的方法之:信號(hào),本文將繼續(xù)介紹另進(jìn)程
    的頭像 發(fā)表于 05-14 15:47 ?2235次閱讀
    <b class='flag-5'>Linux</b><b class='flag-5'>進(jìn)程</b><b class='flag-5'>間</b><b class='flag-5'>通信</b>方法之管道

    進(jìn)程通信機(jī)制有哪些

    比較難,Linux內(nèi)核提供了多種進(jìn)程通信機(jī)制。 同個(gè)進(jìn)
    的頭像 發(fā)表于 07-21 11:23 ?1297次閱讀
    <b class='flag-5'>進(jìn)程</b><b class='flag-5'>間</b><b class='flag-5'>通信</b>的<b class='flag-5'>機(jī)制</b>有哪些