一级目录
二级目录
三级目录 1、管道
1. 匿名管道2. 命名管道 2、共享内存
1. 创建共享内存(`man shmget`)2. 获取唯一性key(`man get`)3. 删除共享内存(`man shmctl`)4. 将进程关联到共享内存/去关联共享内存(`man shmat`)5. 获取共享内存中的内容6. 把内容写入共享内存 3、消息队列
1. 获取消息队列(`man msgget`)2. 删除消息队列(`man msgctl`)
一级目录 二级目录 三级目录 1、管道 1. 匿名管道匿名管道供具有血缘关系的进程进行通信
匿名管道通信步骤:
1、一个进程分别以读写方式打开同一个文件,这样就有两个文件描述符,一个以read方式指向该文件,一个以write方式指向该文件
2、父进程fork创建一个子进程,因为子进程创建以父进程为模版,则子进程的file_struct的fd_array与父进程一样
3、让父进程read,子进程write,则关闭父进行的write,保持父进程的read打开;关闭子进程的read,保持子进程的write打开
测试1
1 #include2 #include 3 4 int main() { 5 int pipe_fd[2] = {0}; 6 if (pipe(pipe_fd) < 0) { 7 perror("pipe"); 8 return 1; 9 } 10 printf("%d %dn", pipe_fd[0], pipe_fd[1]); 11 return 0; 12 } ~
测试2
1 #include2 #include 3 #include 4 #include 5 #include 6 #include 7 8 9 int main() { 10 int pipe_fd[2] = {0}; 11 if (pipe(pipe_fd) < 0) { 12 perror("pipe"); 13 return 1; 14 } 15 printf("%d %dn", pipe_fd[0], pipe_fd[1]); 16 pid_t id = fork(); 17 if (id < 0) { 18 perror("fork"); 19 } 20 if (id == 0) { //write 21 //child 22 close(pipe_fd[0]); W> 23 char *msg = "hello world, i am child process"; 24 int count = 5; 25 while (count) { 26 write(pipe_fd[1], msg, strlen(msg)); 27 sleep(1); 28 count--; 29 } 30 close(pipe_fd[1]); 31 exit(0); 32 }else { // read 33 //parent 34 close(pipe_fd[1]); 35 ssize_t size = 0; 36 char buf[64] = {0}; 37 while(1) { 38 size = read(pipe_fd[0], buf, sizeof(buf)-1); 39 if (size > 0) { 40 buf[size] = 0; 41 printf("parent get message from child#: %sn", buf); 42 } else if (size == 0) { 43 printf("pipe file close, child quit!n"); 44 break; 45 } 46 } 47 close(pipe_fd[0]); 48 int status = 0; 49 pid_t ret = waitpid(id, &status, 0); 50 if (ret == -1) { 51 perror("waitpid"); 52 return 1; 53 } 54 printf("child is waited, the exit code is %dn", WEXITSTATUS(status)); 55 } 56 return 0; 57 }
测试3:读端不读且关闭了read,写端会怎么样?
系统直接kill了写端,因为没人读,写就是做的无用功,系统不允许任何无用功
#include#include #include #include #include #include int main() { int pipe_fd[2] = {0}; if (pipe(pipe_fd) < 0) { perror("pipe"); return 1; } printf("%d %dn", pipe_fd[0], pipe_fd[1]); pid_t id = fork(); if (id < 0) { perror("fork"); } if (id == 0) { //write //child close(pipe_fd[0]); char *msg = "hello world, i am child process"; int count = 5; while (count) { write(pipe_fd[1], msg, strlen(msg)); sleep(1); count--; } close(pipe_fd[1]); exit(0); }else { // read //parent close(pipe_fd[1]); ssize_t size = 0; char buf[64] = {0}; while(1) { size = read(pipe_fd[0], buf, sizeof(buf)-1); if (size > 0) { buf[size] = 0; printf("parent get message from child#: %sn", buf); } else if (size == 0) { printf("pipe file close, child quit!n"); break; }else{ break; } close(pipe_fd[0]); } //close(pipe_fd[0]); int status = 0; pid_t ret = waitpid(id, &status, 0); if (ret == -1) { perror("waitpid"); return 1; } printf("child is waited, the sig code is %d, the exit code is %dn", (status & 0x7F), WEXITSTATUS(status)); } return 0; }
管道的生命周期是随着进程的生命周期的,因为一个进程关闭了,则该进程打开的文件也会关闭
用于没有血缘关系的两个进程之间的通信
mkfifo:用于创建一个命名管道的命令,mkfifo filename可以只在命令行创建一个名为filename的命名管道文件。
但是,向filename写数据时,我们的数据并不会写到磁盘上,只会写到struct file结构体的缓冲区里。(普通文件需要将数据刷新到磁盘来持久化存储)
测试1:在创建了myfifo的命名管道文件后
在bash1里:
while :; do echo "hello world"; sleep 1; done > myfifo
在bash2里:
cat < myfifo
可以看到“hello world”在bash2中被打印出来
测试2:代码级命名管道通信
int mkfifo(const char *filename, mode_t mode)
成功返回0,失败返回-1
创建一个servre,一个client,client发消息,server接收到消息
//server.c 1 #include "stdio.h" 2 #include3 #include 4 #include 5 #include 6 #include 7 #include 8 9 #define FIFO "./fifo" 10 11 int main() { 12 int ret = mkfifo(FIFO, 0644); 13 if (ret < 0) { 14 perror("mkfifo"); 15 } 16 int fd = open(FIFO, O_RDONLY); 17 if (fd < 0) { 18 perror("open"); 19 return 1; 20 } 21 22 char buf[64] = {0}; 23 24 while (1) { 25 ssize_t s = read(fd, buf, sizeof(buf)-1); 26 if (s > 0) { 27 buf[s] = 0; 28 printf("parent get message from client#: %s", buf); 29 }else if(s == 0) { 30 printf("client quitn"); 31 break; 32 }else { 33 break; 34 } 35 } 36 close(fd); 37 return 0; 38 }
//client.c 1 #include "stdio.h" 2 #include3 #include 4 #include 5 #include 6 #include 7 #include 8 9 #define FIFO "./fifo" 10 11 int main() { 12 int fd = open(FIFO, O_WRONLY); 13 if (fd < 0) { 14 perror("open"); 15 return 1; 16 } 17 18 char buf[128]; 19 20 while (1) { 21 printf("please enter# "); 22 fflush(stdout); 23 buf[0] = 0; 24 ssize_t s = read(0, buf, sizeof(buf)-1); 25 if (s > 0) { 26 buf[s] = 0; 27 write(fd, buf, strlen(buf)); 28 }else if(s == 0) { 29 break; 30 }else { 31 break; 32 } 33 } 34 close(fd); 35 return 0; 36 }
不需要read/write等接口读和写,因为已经映射到内存了
共享内存:在物理内存上申请的一段空间,由OS将其分别通过两个进程的页表映射到各自的虚拟内存中(进程双方就看到了同一份资源),然后将地址返回给用户,就可以通过这段空间进行通信。
系统会对所有的共享内存进行管理:先描述再组织
shmflg后面也可以跟权限:0644,一样的用|分隔
2. 获取唯一性key(man get)grep -ER ‘IPC_CREAT’ /usr/include/:查看IPC_CREAT
可以看到其定义在vim /usr/include/bits/ipc.h中
只要两个进程ftok参数填一样的,那个获得的返回值key也是一样的,也就能指示同一个共享内存(管理共享内存的struct中存在标识它自己的key字段)
在*ctl中可以查看描述其对应资源的结构体(共享内存/消息队列/信号量)
第一个参数为共享内存标识码,第二个参数设置为IPC_RMID表示删除共享内存,最后一个暂时设置为NULL
4. 将进程关联到共享内存/去关联共享内存(man shmat)
第二个参数和第三个参数暂时设为NULL和0
// 用于不断查看共享内存信息 while :; do ipcs -m | head -3 && ipcs -m | grep "xupeng";echo "###########"; sleep 1; done5. 获取共享内存中的内容
(因为已经通过shmat获得到了虚拟内存的地址,直接像打印buffer也就是数组中的内容一样打印)
共享内存生命周期随OS
共享内存不提供任何同步互斥,彼此独立
共享内存通信是最快的;没有拷贝到文件中的操作,没有用户态内核态的转换
shim是用户层操作的概念
key是系统表示唯一性
3、消息队列 1. 获取消息队列(man msgget)grep -ER ‘struct ipc_perm’ /usr/include/ :查找ipc_perm
参数与shmget一样
信号的前缀是sem,semget/semctl…
发送消息时的结构体中的类型,可以指定两个进程进行通信,只有发送类型和接收类型一样的才能进行通信(type=0表示任何进程都可以接收这个消息)。
//client.c
#include "stdio.h"
#include "string.h"
#include "stdlib.h"
#include "unistd.h"
#include "fcntl.h"
#include "sys/ipc.h"
#include "sys/msg.h"
#define SIZE 100
struct Buf{
long type;
char text[SIZE];
};
int main() {
key_t key = ftok("/home/xupeng", 10);
if (key < 0) {
perror("ftok");
return 2;
}
int msgid = msgget(key, IPC_CREAT | 0644);
if (msgid < 0) {
perror("msgid");
return 2;
}
struct Buf bf;
bzero(&bf, sizeof(bf));
bf.type = 1;
bf.text[0] = 0;
strcpy(bf.text, "hello world");
msgsnd(msgid, &bf, strlen(bf.text), 1);
return 0;
}
//server.c
#include "stdio.h"
#include "string.h"
#include "stdlib.h"
#include "unistd.h"
#include "fcntl.h"
#include "sys/ipc.h"
#include "sys/msg.h"
#define SIZE 100
struct Buf{
long type;
char text[SIZE];
};
int main() {
key_t key = ftok("/home/xupeng", 10);
if (key < 0) {
perror("ftok");
return 2;
}
int msgid = msgget(key, IPC_CREAT);
if (msgid < 0) {
perror("msgid");
return 2;
}
struct Buf bf;
size_t size = msgrcv(msgid, &bf, SIZE, 1, 0);
printf("msgrcv return : %d", size);
bf.text[size] = 0;
printf("i get meg from client : %sn", bf.text);
return 0;
}



