进程间通信简介(摘自《Linux网络编程》p85)

  AT&T 在 UNIX System V 中引入了几种新的进程通讯方式,即消息队列( MessageQueues),信号量( semaphores)和共享内存( shared memory),统称为 System V IPC。在Linux 系统编程中,它们有着广泛的应用。
  System V IPC 的一个显著的特点,是它的具体实例在内核中是以对象的形式出现的,我们称之为 IPC 对象。每个 IPC 对象在系统内核中都有一个唯一的标识符。通过标识符内核可以正确的引用指定的 IPC 对象.。需要注意的是,标识符的唯一性只在每一类的 IPC 对象内成立。比如说,一个消息队列和一个信号量的标识符可能是相同的,但绝对不会出现两个有相同标识符的消息队列。

  标识符只在内核中使用, IPC 对象在程序中是通过关键字( key)来访问的。和 IPC 对象标识符一样,关键字也必须是唯一的。而且,要访问同一个 IPC 对象, Server 和 Client必须使用同一个关键字。因此,如何构造新的关键字使之不和已有的关键字冲突,并保证Server 和 Client 使用的关键字是相同的,是建立 IPC 对象时首先要解决的一个问题。(具体在后边的msg通信中详解)

通信方法还有:半双工管道pipe,命名管道fifo,消息队列,信号量,共享内,socket套接字等,下面一一介绍:

①半双工管道:

  int pipe(int filedes[2]);

  管道是将两个进程之间的标准输入输出相互对接的机制

  linux命令中使用的管道 |  : ls -l | grep *.c  //显示文件(输入端)-(|)-(输出端)>找到.c结尾文件

实现:因为半双工缘故,所以只能实现一段输入,一段输出,而不能双向通信。所以:实现为,通过管道连接进程,一端开放读文件描述,一端开放写文件描述

//管道的性质就是,一个进程的输出作为另一个进程的输入
//那么我们可以关闭一个进程读端使之作为输入端,
//另一个进程关闭写端,读取数据,接收数据作为管道输出端 //FIFO命名管道
//文件系统中,命名管道是特殊文件的方式存在的
//不同进程可以通过命名管道共享数据 //命名管道一直是阻塞方式的,且必须是显示的通过open建立连接到管道的通道
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h> #include<sys/types.h> int main()
{
int result = ;
int fd[];
pid_t pid;
int *write_fd = &fd[]; //写文件描述
int *read_fd = &fd[]; //读文件描述 int nbytes;
char str[] = "管道,你好\n";
char readBuffer[];
memset(readBuffer,,sizeof(readBuffer)); result = pipe(fd); //创建管道
if(-==result)
{
printf("管道创建失败!\n");
return -;
} pid = fork(); //进程创建分叉程序
if(- == pid)
{
printf("fork失败");
return -;
} if(==pid) //子进程关闭读端,写入字符
{
close(*read_fd);
result = write(*write_fd,str,strlen(str));
printf("写入%d个数据\n",result);
}
else //父进程关闭写端,读取数据
{
close(*write_fd);
nbytes = read(*read_fd,readBuffer,sizeof(readBuffer));
printf("接收到%d个数据,内容为%s",nbytes,readBuffer);
}
return ;
}

②命名管道

  int mkfifo(const char* pathname,mode_t mode);

  类似于普通管道,只是

  a.在文件系统中以设备特殊文件的形式存在

  b.不同进程之间可以通过命名管道共享数据

操作区别于普通管道:FIFO中必须显式通过open建立连接到管道的通道,且总是处于阻塞状态的

③消息队列

  消息队列是内核地址空间的内部链表,通过内核在各个进程之间传递内容。每个消息队列通过唯一IPC标识符标识,不同队列相对独立。

  

//file: msg.h
/* message buffer for msgsnd and msgrcv calls */
struct msgbuf {
__kernel_long_t mtype; /* type of message */
char mtext[]; /* message text */
}; /* Obsolete, used only for backwards compatibility and libc5 compiles */
struct msqid_ds {
struct ipc_perm msg_perm;
struct msg *msg_first; /* first message on queue,unused */
struct msg *msg_last; /* last message in queue,unused */
__kernel_time_t msg_stime; /* last msgsnd time */
__kernel_time_t msg_rtime; /* last msgrcv time */
__kernel_time_t msg_ctime; /* last change time */
unsigned long msg_lcbytes; /* Reuse junk fields for 32 bit */
unsigned long msg_lqbytes; /* ditto */
unsigned short msg_cbytes; /* current number of bytes on queue */
unsigned short msg_qnum; /* number of messages in queue */
unsigned short msg_qbytes; /* max number of bytes on queue */
__kernel_ipc_pid_t msg_lspid; /* pid of last msgsnd */
__kernel_ipc_pid_t msg_lrpid; /* last receive pid */
};
//filename
/* Obsolete, used only for backwards compatibility and libc5 compiles */
struct ipc_perm
{
__kernel_key_t key;  //函数msgget()使用的键值  
__kernel_uid_t uid;  //用户UID
__kernel_gid_t gid;  //用户GID
__kernel_uid_t cuid;  //创建者UID
__kernel_gid_t cgid;  //创建者GID
__kernel_mode_t mode;   //权限
unsigned short seq;  //序列号
};

  内核中的消息队列

注:结构list_head 形成一个链表,结构msg_msg之中的m_list使得消息形成链表,查找,插入时,对m_list域进行偏移找到位置

相关函数:

  键值构建 key_t ftok(const char* pathname,int proj_id);

  获取消息 int msgget(key_t key,int msgflg);

  发送消息 int msgsnd(int msqid, const void * msgp,size_t msgsz,int msgflg);

  接收消息 ssize_t msgrcv(int msqid, void * msgp, size_t msgsz, long msgtype, int msgflg);

  消息控制 int msgctl(int msqid, int cmd, struct msqid_ds *buf);  //向内核发送cmd命令判断进行何种操作

一个简单例子

④信号量

  信号量是一种计数器,用来控制对多个进程共享的资源所进行的访问。常用作锁机制(生产者消费者模型是个典型使用)

  信号量结构

//filename sys/sem.h
/* arg for semctl system calls. */
union semun {
int val; /* value for SETVAL */
struct semid_ds *buf; /* buffer for IPC_STAT & IPC_SET */
unsigned short *array; /* 数组结构 */
struct seminfo *__buf; /* 信号量内部结构 */
void *__pad;
};

  相关函数

  新建信号量 int semget(key_t key, int nsems, int semflg);

  //key 来自于ftok()

  信号量操作函数 int semop(int semid,struct sembuf* sops, unsigned nsops);

  //信号量的P,V操作通过向已经建立好的信号量发送命令完成

  控制信号量参数

  int semctl(int semid, int semnum ,int cmd,.....);

  //用于在信号量集合上执行控制操作

#include<stdio.h>
#include<unistd.h>
#include<sys/ipc.h>
#include<sys/sem.h>
#include<sys/types.h> typedef int sem_t;
union semun
{
int val;
struct semid_ds * buf;
unsigned short *array;
}arg; sem_t CreateSem(key_t key, int value)
{
union semun sem;
sem_t semid;
sem.val = value; semid = semget(key,,IPC_CREAT);
if(- == semid)
{
printf("create semaphore error\n");
return -;
} semctl(semid,,SETVAL,sem); return semid;
} int Sem_P(sem_t semid)
{
struct sembuf sops = {,+,IPC_NOWAIT};
return (semop(semid,&sops,));
} int Sem_V(sem_t semid)
{
struct sembuf sops = {,-,IPC_NOWAIT};
return (semop(semid,&sops,));
} void SetvalueSem(sem_t semid , int value)
{
union semun sem;
sem.val = value;
semctl(semid,,SETVAL,sem);
} int GetvalueSem(sem_t semid)
{
union semun sem;
return semctl(semid,,GETVAL,sem);
} void DestroySem(sem_t semid)
{
union semun sem;
sem.val = ;
semctl(semid,,IPC_RMID,sem);
}
int main()
{
key_t key;
int semid;
char i;
int value = ;
key = ftok("/ipc/sem",'a'); semid = CreateSem(key,);
for( i = ;i <= ;++i)
{
Sem_P(semid);
Sem_V(semid);
}
value = GetvalueSem(semid); DestroySem(semid);
return ;
}

⑤共享内存(最快捷的方法)没有中间过程,管道等

  在多个进程之间共享内存区域的一种进程间通信方式,在多个进程之间对内存段进行映射的方式实现内存共享。

  相关函数

  创建共享内存函数 int shmget(key_y key, size_t size, int shmflg);

  获得共享内存地址void * shmat(int shmid,const void* shmaddr, int shmflg);

  删除共享内存函数 int shmdt(const void* shmadddr);

  共享内存控制函数 int shmctl(int shmid ,int cmd, struct shmid_ds * buf);

⑥信号

  用于在一个或多个进程之间传递异步信号。

  相关函数

  信号截取 sighandler signal(int signum ,sighandler handler);

  发送信号 int kill(pid_t pid, int sig);

       int raise(int sig);

  

  

  

  

Linux网络编程--进程间通信(一)的更多相关文章

  1. linux网络编程_1

    本文属于转载,稍有改动,以利于学习. (一)Linux网络编程--网络知识介绍 Linux网络编程--网络知识介绍客户端和服务端         网络程序和普通的程序有一个最大的区别是网络程序是由两个 ...

  2. Linux网络编程入门 (转载)

    (一)Linux网络编程--网络知识介绍 Linux网络编程--网络知识介绍客户端和服务端         网络程序和普通的程序有一个最大的区别是网络程序是由两个部分组成的--客户端和服务器端. 客户 ...

  3. [转] - Linux网络编程 -- 网络知识介绍

    (一)Linux网络编程--网络知识介绍 Linux网络编程--网络知识介绍客户端和服务端         网络程序和普通的程序有一个最大的区别是网络程序是由两个部分组成的--客户端和服务器端. 客户 ...

  4. 【转】Linux网络编程入门

    (一)Linux网络编程--网络知识介绍 Linux网络编程--网络知识介绍客户端和服务端         网络程序和普通的程序有一个最大的区别是网络程序是由两个部分组成的--客户端和服务器端. 客户 ...

  5. 《转》Linux网络编程入门

    原地址:http://www.cnblogs.com/duzouzhe/archive/2009/06/19/1506699.html (一)Linux网络编程--网络知识介绍 Linux网络编程-- ...

  6. Linux网络编程学习计划

    由于网络编程是很重要的一块,自己这一块也比较欠缺,只知道一些皮毛,从今天开始系统学习<Linux网络编程>一书,全书分为十四个章节: 第一章   概论   P1-16 第二章   UNIX ...

  7. 很全的linux网络编程技巧

    本文转载自:http://www.cnblogs.com/jfyl1573/p/6476607.html 1. LINUX网络编程基础知识 1 1.1. TCP/IP协议概述 1 1.2. OSI参考 ...

  8. TCP/UDP Linux网络编程详解

    本文主要记录TCP/UDP网络编程的基础知识,采用TCP/UDP实现宿主机和目标机之间的网络通信. 内容目录 1. 目标2.Linux网络编程基础2.1 嵌套字2.2 端口2.3 网络地址2.3.1 ...

  9. Linux 网络编程的5种IO模型:信号驱动IO模型

    Linux 网络编程的5种IO模型:信号驱动IO模型 背景 上一讲 Linux 网络编程的5种IO模型:多路复用(select/poll/epoll) 我们讲解了多路复用等方面的知识,以及有关例程. ...

随机推荐

  1. Appium-Java滑动操作

    Java滑动操作,通常可以直接使用API中AndroidDriver类中的swipe方法,直接进行调用 swipe(int startx, int starty, int endx, int endy ...

  2. oracle的字符集设置与乱码

    oracle的字符集设置与乱码 字符集问题一直叫人头疼,究其原因还是不能完全明白其运作原理. 在整个运行环节中,字符集在3个环节中发挥作用: 1.软件在操作系统上运作时的对用户的显示,此时采用操作系统 ...

  3. java static成员变量方法和非static成员变量方法的区别 ( 二 )

    原创文章,未经作者允许,禁止转载!!! 静态成员变量不用new对象,在类加载的过程中就已经初始化存放在数据区域,静态成员变量是类和所有对象共有的,类和对象都可以改变它的值,每一次改变值之后,静态成员变 ...

  4. 无线路由MAC地址过滤安全可靠性讨论

    无线路由MAC地址过滤安全可靠性讨论/如何实现,真的有效吗,如何防范       [内容导航] 什么是MAC地址过滤 突破MAC地址过滤步骤 捕获的无线客户端MAC地址 更改MAC地址来伪造身份 在W ...

  5. SHUOJ Arithmetic Sequence (FFT)

    链接:http://acmoj.shu.edu.cn/problem/533/ 题意:求一个序列中,有多少三元组(其中元素不重复)在任意的排列下能构成等差数列. 分析:等差数列:\(A_j-A_i=A ...

  6. python3.5实现购物车

    一.购物车实现: 购物车功能: 用户登录:密码错误三次锁定账户. 商品列表分页显示:输入页码查看指定页数商品信息. 已购买商品列表:显示已购买的物品列表:可以模糊查询已购买的商品并在终端打印. 充值: ...

  7. cocos2dx 3.x 精灵重叠时点击最上层的精灵

    ps. 这个方法只适用设置精灵的触摸.. //注册触摸事件..3.X后可以在这样写..不需要重新声明 EventListenerTouchOneByOne *listener = EventListe ...

  8. JQuery归纳总结(增加中...)

    一.this与$(this)的区别 this指向标签本身对象,而$(this)会将其封装成JQuery对象 如: $(" img").mousemove( function(e){ ...

  9. 【Python】IO编程

    文件读写 StringIO和BytesIO 操作文件和目录 序列化 学习廖老师的py官网的笔记 1.stream的概念.数据交换通常需要建立两根“水管”. 2.同步IO和异步IO.异步性能高,但是编程 ...

  10. Django学习笔记之Django的url反向解析

    0x00 URL反向解析和三种不同的反向解析方式 Django中提供了关于URL的映射的解决方案,可以做两个方向的使用: 1.普通解析过程:由客户端的浏览器发起一个url请求,Django根据URL解 ...