Linux网络编程--进程间通信(一)
进程间通信简介(摘自《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 = 1;int fd[2];pid_t pid;int *write_fd = &fd[1]; //写文件描述int *read_fd = &fd[0]; //读文件描述int nbytes;char str[] = "管道,你好\n"; char readBuffer[80];memset(readBuffer,0,sizeof(readBuffer));result = pipe(fd); //创建管道if(-1==result){printf("管道创建失败!\n");return -1;}pid = fork(); //进程创建分叉程序if(-1 == pid){printf("fork失败");return -1;}if(0==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 0; }
②命名管道
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[1]; /* 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,0,IPC_CREAT);if(-1 == semid){printf("create semaphore error\n");return -1;}semctl(semid,0,SETVAL,sem);return semid; }int Sem_P(sem_t semid) { struct sembuf sops = {0,+1,IPC_NOWAIT}; return (semop(semid,&sops,1)); }int Sem_V(sem_t semid) {struct sembuf sops = {0,-1,IPC_NOWAIT};return (semop(semid,&sops,1)); }void SetvalueSem(sem_t semid , int value) {union semun sem;sem.val = value;semctl(semid,0,SETVAL,sem); }int GetvalueSem(sem_t semid) {union semun sem;return semctl(semid,0,GETVAL,sem); }void DestroySem(sem_t semid) {union semun sem;sem.val = 0;semctl(semid,0,IPC_RMID,sem); } int main() {key_t key;int semid;char i;int value = 0;key = ftok("/ipc/sem",'a');semid = CreateSem(key,100);for( i = 0;i <= 3;++i){Sem_P(semid);Sem_V(semid); }value = GetvalueSem(semid); DestroySem(semid); return 0; }
⑤共享内存(最快捷的方法)没有中间过程,管道等
在多个进程之间共享内存区域的一种进程间通信方式,在多个进程之间对内存段进行映射的方式实现内存共享。
相关函数
创建共享内存函数 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);
转载于:https://www.cnblogs.com/lang5230/p/5502771.html
Linux网络编程--进程间通信(一)相关推荐
- linux网络编程常用函数详解与实例(socket--bind--listen--accept)
常用的网络命令: netstat 命令netstat是用来显示网络的连接,路由表和接口统计等网络的信息.netstat有许多的选项我们常用的选项是 -an 用来显示详细的网络状态.至于其它的选项我们可 ...
- linux网络编程之字节序
进程间通信 特点:依赖于内核,造成缺陷--无法实现多机通信. 网络编程 地址:由IP地址和端口号构成,端口号用来判断客户端接入哪个服务器. 数据的交流:涉及到协议(http,tcp,udp),其实就是 ...
- [Linux网络编程学习笔记]索引
一.Linux基本知识 [学习笔记]Linux平台的文件I/O操作 [学习笔记]Linux平台的文件,目录及操作 [Linux学习笔记]标准输入输出 [Linux学习笔记]进程概念及控制 [Linux ...
- Linux网络编程基础
2019独角兽企业重金招聘Python工程师标准>>> (一)Linux网络编程--网络知识介绍 Linux网络编程--网络知识介绍 客户端和服务端 网络程序和普通的程序有一个最大的 ...
- Linux网络编程——千峰物联网笔记
B站视频:千峰物联网学科linux网络编程 网址:https://www.bilibili.com/video/BV1RJ411B761?p=1 目录 第一章:计算机网络概述 1.1计算机网络发展简史 ...
- Linux网络编程基础知识
Linux网络编程基础知识 1. 协议的概念 1.1 什么是协议 1.2 典型协议 2 网络应用程序设计模式 2.1 C/S模式 2.2 B/S模式 2.3 优缺点 3 分层模型 3.1 OSI七层模 ...
- Linux网络编程——socket、bind、listen、accpet、connect、read和write
Linux网络编程 基础理论 1.TCP/UDP/端口号 2.字节序 一.socket服务器与客户端的开发步骤 二.具体使用步骤 1.socket(创建连接协议) 2.bind(地址准备好) 3.li ...
- Linux网络编程入门
(一)Linux网络编程--网络知识介绍 linux网络编程--网络知识介绍 客户端和服务端 网络程序和普通的程序有一个最大的区别是网络程序是由两个部分组成的--客户端和服务器端. ...
- Linux网络编程 入门
Linux网络编程入门 (转载) (一)Linux网络编程--网络知识介绍 Linux网络编程--网络知识介绍 客户端和服务端 网络程序和普通的程序有一个最大的区别是网络程序是由两个 ...
最新文章
- 【像程序员一样思考】 读书笔记2
- Android中APK直接通过JNI访问驱动
- 修改mysql存储过程的权限调用权限 definer invoker
- Python数据分析学习笔记之Pandas入门
- P1133 教主的花园 (动态规划)
- Excel数据批量导入到数据库
- [Remoting]在.NET環境實作Flex 3 Remoting - (2) Flex Builder 環境設定
- cnn输入层_基于 CNN 的文本分类算法
- 如何判断是否是webservice接口
- RNN梯度消失和爆炸的原因
- java 两张图片合并_java实现把两张图片合并(Graphics2D)
- Justinmind恢复30天试用 For Mac
- python中e怎么计算_蒙特卡洛法计算自然常数e——python编程及可视化
- 输入一个三位数,输出它 个位、十位、百位 数字之和
- 淘宝视频内容标签的结构化分析和管理
- 苹果WatchKit轻松入门
- antd vue form 手动校验_Ant Design 4.0 的一些杂事儿 - Form 篇
- InetAddress类常用方法
- wap手机广告形式有哪些形式——手机站点广告代码
- java.lang.RuntimeException:Canvas: trying to use a recycled bitmap