2023/6/27 通信之间的实现,目的是为了,方便回顾时立马能使用。具体的比如什么情况选用什么通信,各自的优点,没有记录。原因是,本人目前实战经验较少,还处于学习状态,对此的理解还停留在管道方便,共享内存效率高,控制操作用消息队列
前提
答:7种,分别为无名管道、有名管道、信号、消息队列、共享内存、信号灯集、套接字
答:
- 无名管道:只能用于情缘关系的进程间通信,半双工,固定读写端,看成特殊的文件,围绕文件描述符,fd[0]读,fd[1]写,遵循先进先出,通过文件IO来操作
- 有名管道:互不相关的进程互相通信,在文件系统可见,通过文件IO来操作,遵循先进先出,不支持lseek()操作
- 信号:软件层次上中断机制的模拟,异步通信,直接进行用户空间进程和内核进程间的交互。内核可以利用它来通知用户空间进程发送那些系统事件。
- 消息队列:是IPC对象的一种,由消息队列ID来唯一标识,是一个消息的列表,用户可以在消息队列中添加消息、读取消息。
- 共享内存:最为高效的进程间通信,进程可以直接读写内存,而不需要任何数据拷贝。进程直接读写内核开辟的内存区,不需要进行数据拷贝,但是因为多个进程共享一段内存,因此需要信号量和互斥锁来同步。
- 信号灯集:也叫信号量,不同进程或一个进程内部不同线程同步的机制
- 套接字:为网络编程的一种通信机制,因为通信的进程都是在一台计算机中,所以套接字也是一种进程间通信。
答:如下所示
无名管道
函数接口
- int pipe(int fd[2])
- 功能:创建无名管道
- 参数:文件描述符 fd[0]:读端 fd[1]:写端
- 返回值:成功 0
- 失败 -1
复制代码 注意事项
a. 当管道中无数据时,读操作会阻塞;
管道中无数据时,将写端关闭,读操作会立即返回
b. 管道中装满(管道大小64K)数据写阻塞,一旦有4k空间,写继续
c. 只有在管道的读端存在时,向管道中写入数据才有意义。否则,会导致管道破裂,向管道中写入数据的进程将收到内核传来的SIGPIPE信号 (通常Broken pipe错误)。
功能实现
父进程循环从终端输入字符串,子进程将字符串循环输出- #include <stdio.h>
- #include <sys/types.h>
- #include <unistd.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/wait.h>
- int main(int argc, char const *argv[])
- {
- char buf[32] = "";
- pid_t id;
- int fd[2] = {0};
- if(pipe(fd) < 0)
- {
- perror("pipe err");
- return -1;
- }
- if ((id = fork()) < 0)
- {
- perror("fork err");
- return -1;
- }
- else if (id == 0)//子进程
- {
- while(1)
- {
- char buf[32] = "";
- read(fd[0], buf, 32);
- if(strcmp(buf, "quit") == 0)
- break;
- printf("buf:%s\n", buf);
- }
- exit(0);
- }
- else//父进程
- {
- while(1)
- {
- char buf[32] = "";
- // scanf("%s", buf);
- fgets(buf, 32, stdin);
- write(fd[1], buf, strlen(buf)+1);
- if(strcmp(buf, "quit") == 0)
- break;
- }
- wait(NULL);
- }
- return 0;
- }
复制代码 有名管道
函数接口
- int mkfifo(const char *filename,mode_t mode);
- 功能:创健有名管道
- 参数:filename:有名管道文件名
- mode:权限
- 返回值:成功:0
- 失败:-1,并设置errno号
- 注意对错误的处理方式:
- 如果错误是file exist时,注意加判断,如:if(errno == EEXIST)
复制代码 注意事项
a. 只写方式,写阻塞,一直到另一个进程把读打开
b. 只读方式,读阻塞,一直到另一个进程把写打开
c. 可读可写,如果管道中没有数据,读阻塞
功能实现
读写操作- #include <stdio.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <errno.h>
- #include <unistd.h>
- #include <string.h>
- #include <fcntl.h>
- int main(int argc, char const *argv[])
- {
- int fd;
- //创建管道
- if (mkfifo("./fifo", 0666) < 0)
- {
- if (errno == EEXIST)
- printf("file exists\n");
- else
- {
- perror("mkfifo err");
- return -1;
- }
- }
- printf("mkfifo ok\n");
- //打开管道
- fd = open("./fifo", O_RDWR);
- if(fd < 0)
- {
- perror("open err");
- return -1;
- }
- char buf[32] = "hello";
- char data[32] = "";
- write(fd, buf, strlen(buf));
- read(fd, data, 32);
- printf("%s\n", data);
- return 0;
- }
复制代码 信号
函数接口
- int kill(pid_t pid, int sig);
- 功能:信号发送
- 参数:pid:指定进程
- sig:要发送的信号
- 返回值:成功 0
- 失败 -1
- int raise(int sig);
- 功能:进程向自己发送信号
- 参数:sig:信号
- 返回值:成功 0
- 失败 -1
- signal(SIGINT, SIG_IGN);//忽略信号
- signal(SIGINT, SIG_DFL); //执行默认操作
- signal(SIGINT, handler); //捕捉信号
- void handler(int sig)//捕捉到该信号执行该函数操作
- {
- printf("ctrl+c\n");
- }
复制代码 注意事项
SIGKILL:结束进程,不能被忽略不能被捕捉
SIGSTOP:结束进程,不能被忽略不能被捕捉
SIGCHLD:子进程状态改变时给父进程发的信号,不会结束进程
SIGINT:结束进程,对应快捷方式ctrl+c
SIGTSTP:暂停信号,对应快捷方式ctrl+z
SIGQUIT:退出信号,对应快捷方式ctrl+
SIGALRM:闹钟信号,alarm函数设置定时,当到设定的时间时,内核会向进程发送此信号结束进程。
SIGTERM:结束终端进程,kill 使用时不加数字默认是此信号
功能实现
用信号的知识实现司机和售票员问题。
1)售票员捕捉SIGINT(代表开车)信号,向司机发送SIGUSR1信号,司机打印(let's gogogo)
2)售票员捕捉SIGQUIT(代表停车)信号,向司机发送SIGUSR2信号,司机打印(stop the bus)
3)司机捕捉SIGTSTP(代表到达终点站)信号,向售票员发送SIGUSR1信号,售票员打印(please get off the bus)
4)司机等待售票员下车,之后司机再下车。- #include <stdio.h>
- #include <signal.h>
- #include <unistd.h>
- #include <stdlib.h>
- #include <sys/types.h>
- #include <sys/wait.h>
- pid_t pid;
- void driver(int sig)
- {
- if (sig == SIGUSR1)
- printf("let's gogogo\n");
- else if (sig == SIGUSR2)
- printf("stop the bus\n");
- else if (sig == SIGTSTP)
- {
- kill(pid, SIGUSR1);
- wait(NULL);
- exit(0);
- }
- }
- void saler(int sig)
- {
- if (sig == SIGINT)
- kill(getppid(), SIGUSR1);
- else if (sig == SIGQUIT)
- kill(getppid(), SIGUSR2);
- else if (sig == SIGUSR1)
- {
- printf("please get off the bus\n");
- exit(0);
- }
- }
- int main(int argc, char const *argv[])
- {
- if ((pid = fork()) < 0)
- {
- perror("fork err");
- return -1;
- }
- else if (pid == 0)
- {
- signal(SIGINT, saler);
- signal(SIGQUIT, saler);
- signal(SIGUSR1, saler);
- signal(SIGTSTP, SIG_IGN);
- }
- else
- {
- signal(SIGUSR1, driver);
- signal(SIGUSR2, driver);
- signal(SIGTSTP, driver);
- signal(SIGINT, SIG_IGN);
- signal(SIGQUIT, SIG_IGN);
- }
- while (1)
- pause();
- return 0;
- }
复制代码 消息队列
函数接口
- 步骤:
- 1)创建key值 ftok
- 2)创建或打开消息队列 msgget
- 3)添加消息/读取消息 msgsnd/msgrcv
- 4)删除消息队列 msgctl
- 命令:
- ipcs -q :查看消息队列
- ipcrm -q msgid :删除消息队列
- int msgget(key_t key, int flag);
- 功能:创建或打开一个消息队列
- 参数: key值
- flag:创建消息队列的权限IPC_CREAT|IPC_EXCL|0666
- 返回值:成功:msgid
- 失败:-1
- int msgsnd(int msqid, const void *msgp, size_t size, int flag);
- 功能:添加消息
- 参数:msqid:消息队列的ID
- msgp:指向消息的指针。常用消息结构msgbuf如下:
- struct msgbuf{
- long mtype; //消息类型
- char mtext[N]}; //消息正文
- size:发送的消息正文的字节数
- flag:IPC_NOWAIT消息没有发送完成函数也会立即返回
- 0:直到发送完成函数才返回
- 返回值:成功:0
- 失败:-1
- 使用:msgsnd(msgid, &msg,sizeof(msg)-sizeof(long), 0)
- 注意:消息结构除了第一个成员必须为long类型外,其他成员可以根据应用的需求自行定义。
- int msgrcv(int msgid, void* msgp, size_t size, long msgtype, int flag);
- 功能:读取消息
- 参数:msgid:消息队列的ID
- msgp:存放读取消息的空间
- size:接受的消息正文的字节数
- msgtype:0:接收消息队列中第一个消息。
- 大于0:接收消息队列中第一个类型为msgtyp的消息.
- 小于0:接收消息队列中类型值不小于msgtyp的绝对值且类型值又最小的消息。
- flag:0:若无消息函数会一直阻塞
- IPC_NOWAIT:若没有消息,进程会立即返回ENOMSG
- 返回值:成功:接收到的消息的长度
- 失败:-1
- int msgctl ( int msgqid, int cmd, struct msqid_ds *buf );
- 功能:对消息队列的操作,删除消息队列
- 参数:msqid:消息队列的队列ID
- cmd:
- IPC_STAT:读取消息队列的属性,并将其保存在buf指向的缓冲区中。
- IPC_SET:设置消息队列的属性。这个值取自buf参数。
- IPC_RMID:从系统中删除消息队列。
- buf:消息队列缓冲区
- 返回值:成功:0
- 失败:-1
- 用法:msgctl(msgid, IPC_RMID, NULL)
复制代码 功能代码
基础实现- struct msgbuf{
- long type;
- int num;
- char buf[32];
- };
- int main(int argc, char const *argv[])
- {
- key_t key;
- int msgid;
- //创建key值
- key = ftok("./app", 'b');
- if (key < 0)
- {
- perror("ftok err");
- return -1;
- }
- printf("%#x\n", key);
- //创建消息队列
- msgid = msgget(key, IPC_CREAT|IPC_EXCL|0666);
- if(msgid < 0)
- {
- if(errno == EEXIST)
- msgid = msgget(key, 0666);
- else
- {
- perror("msgget err");
- return -1;
- }
- }
- //添加消息
- int size = sizeof(struct msgbuf)-sizeof(long);
- struct msgbuf msg = {1, 100, "hello"};
- struct msgbuf msg1 = {2, 200, "world"};
- msgsnd(msgid, &msg, size, 0);
- msgsnd(msgid, &msg1, size, 0);
- //读取消息
- struct msgbuf m;
- msgrcv(msgid, &m, size, 2, 0);
- printf("%d %s\n", m.num, m.buf);
- //删除消息队列
- msgctl(msgid, IPC_RMID, NULL);
- return 0;
- }
复制代码 两个进程通过消息队列进行通信,一个进程从终端输入下发的指令,另一个进程接收指令,并打印对应操作语句。
如果输入LED ON,另一个进程输出 “开灯”
如果输入LED OFF,另一个进程输出 “关灯”- //send端
- #include <stdio.h>
- #include <stdio.h>
- #include <sys/types.h>
- #include <sys/ipc.h>
- #include <errno.h>
- #include <string.h>
- #include <sys/msg.h>
- struct msgbuf
- {
- long type;
- char buf[32];
- };
- int main(int argc, char const *argv[])
- {
- key_t key;
- int msgid;
- //创建key值
- key = ftok("./app", 'b');
- if (key < 0)
- {
- perror("ftok err");
- return -1;
- }
- printf("%#x\n", key);
- //创建消息队列
- msgid = msgget(key, IPC_CREAT|IPC_EXCL|0666);
- if(msgid < 0)
- {
- if(errno == EEXIST)
- msgid = msgget(key, 0666);
- else
- {
- perror("msgget err");
- return -1;
- }
- }
- struct msgbuf msg;
- msg.type = 1;
- int s = sizeof(struct msgbuf)-sizeof(long);
- while(1)
- {
- scanf("%s", msg.buf);
- msgsnd(msgid, &msg, s, 0);
- }
- return 0;
- }
复制代码- //recv端
- #include <stdio.h>
- #include <stdio.h>
- #include <sys/types.h>
- #include <sys/ipc.h>
- #include <errno.h>
- #include <string.h>
- #include <sys/msg.h>
- struct msgbuf
- {
- long type;
- char buf[32];
- };
- int main(int argc, char const *argv[])
- {
- key_t key;
- int msgid;
- //创建key值
- key = ftok("./app", 'b');
- if (key < 0)
- {
- perror("ftok err");
- return -1;
- }
- printf("%#x\n", key);
- //创建消息队列
- msgid = msgget(key, IPC_CREAT|IPC_EXCL|0666);
- if(msgid < 0)
- {
- if(errno == EEXIST)
- msgid = msgget(key, 0666);
- else
- {
- perror("msgget err");
- return -1;
- }
- }
- struct msgbuf msg;
- int s = sizeof(struct msgbuf)-sizeof(long);
- while(1)
- {
- msgrcv(msgid, &msg, s, 1, 0);
- if(strcmp(msg.buf, "LEDON") == 0)
- printf("开灯\n");
- else if(strcmp(msg.buf, "LEDOFF") == 0)
- printf("关灯\n");
- }
-
- return 0;
- }
复制代码 共享内存
函数接口
- //步骤
- 0)创建key值
- 1)创建或打开共享内存
- 2)映射
- 3)取消映射
- 4)删除共享内存
- key_t ftok(const char *pathname, int proj_id);
- 功能:创建key值
- 参数:pathname:文件名
- proj_id:取整型数的低8位数值
- 返回值:成功:key值
- 失败:-1
- int shmget(key_t key, size_t size, int shmflg);
- 功能:创建或打开共享内存
- 参数:
- key 键值
- size 共享内存的大小
- shmflg IPC_CREAT|IPC_EXCL|0777
- 返回值:成功 shmid
- 出错 -1
- void *shmat(int shmid,const void *shmaddr,int shmflg);
- 功能:映射共享内存,即把指定的共享内存映射到进程的地址空间用于访问
- 参数:
- shmid 共享内存的id号
- shmaddr 一般为NULL,表示由系统自动完成映射
- 如果不为NULL,那么有用户指定
- shmflg:SHM_RDONLY就是对该共享内存只进行读操作
- 0 可读可写
- 返回值:成功:完成映射后的地址,
- 出错:-1的地址
- 用法:if((p = (char *)shmat(shmid,NULL,0)) == (char *)-1)
- int shmdt(const void *shmaddr);
- 功能:取消映射
- 参数:要取消的地址
- 返回值:成功0
- 失败的-1
- int shmctl(int shmid,int cmd,struct shmid_ds *buf);
- 功能:(删除共享内存),对共享内存进行各种操作
- 参数:
- shmid 共享内存的id号
- cmd IPC_STAT 获得shmid属性信息,存放在第三参数
- IPC_SET 设置shmid属性信息,要设置的属性放在第三参数
- IPC_RMID:删除共享内存,此时第三个参数为NULL即可
- 返回:成功0
- 失败-1
- 用法:shmctl(shmid,IPC_RMID,NULL);
复制代码 功能代码
基础- int main(int argc, char const *argv[])
- {
- key_t key;
- int shmid;
- //创建key值
- key = ftok("./app", 'b');
- if (key < 0)
- {
- perror("ftok err");
- return -1;
- }
- printf("%#x\n", key);
- //创建或打印共享内存
- shmid = shmget(key, 128, IPC_CREAT | IPC_EXCL | 0666);
- if (shmid < 0)
- {
- if (errno == EEXIST)
- shmid = shmget(key, 128, 0666);
- else
- {
- perror("shmget err");
- return -1;
- }
- }
- printf("shmid:%d\n", shmid);
- //映射
- char *p = NULL;
- p = shmat(shmid, NULL, 0); //NULL:系统自动进行映射 0:可读可写
- if(p == (char *)-1)
- {
- perror("shmat err");
- return -1;
- }
- strcpy(p, "hello");
- printf("%s\n", p);
- //取消映射
- shmdt(p);
- //删除共享内存
- shmctl(shmid, IPC_RMID, NULL);
- return 0;
- }
复制代码 练习:一个进程从终端输入,另一个进程将数据输出,借助共享内存通信。
要求:当输入quit时程序退出
同步:标志位- //read.c
- #include <stdio.h>
- #include <sys/types.h>
- #include <sys/ipc.h>
- #include <sys/shm.h>
- #include <errno.h>
- #include <string.h>
- struct msg
- {
- int flg;
- char buf[32];
- };
- int main(int argc, char const *argv[])
- {
- key_t key;
- int shmid;
- //创建key值
- key = ftok("./app", 'b');
- if (key < 0)
- {
- perror("ftok err");
- return -1;
- }
- printf("%#x\n", key);
- //创建或打印共享内存
- shmid = shmget(key, 128, IPC_CREAT | IPC_EXCL | 0666);
- if (shmid < 0)
- {
- if (errno == EEXIST)
- shmid = shmget(key, 128, 0666);
- else
- {
- perror("shmget err");
- return -1;
- }
- }
- printf("shmid:%d\n", shmid);
- //映射
- struct msg *p = NULL;
- p = (struct msg *)shmat(shmid, NULL, 0); //NULL:系统自动进行映射 0:可读可写
- if(p == (struct msg *)-1)
- {
- perror("shmat err");
- return -1;
- }
- p->flg = 0;
- while(1)
- {
- scanf("%s", p->buf);
- p->flg = 1;
- if(strcmp(p->buf, "quit") == 0)
- break;
- }
- return 0;
- }
复制代码- //write.c
- #include <stdio.h>
- #include <sys/types.h>
- #include <sys/ipc.h>
- #include <sys/shm.h>
- #include <errno.h>
- #include <string.h>
- struct msg
- {
- int flg;
- char buf[32];
- };
- int main(int argc, char const *argv[])
- {
- key_t key;
- int shmid;
- //创建key值
- key = ftok("./app", 'b');
- if (key < 0)
- {
- perror("ftok err");
- return -1;
- }
- printf("%#x\n", key);
- //创建或打印共享内存
- shmid = shmget(key, 128, IPC_CREAT | IPC_EXCL | 0666);
- if (shmid < 0)
- {
- if (errno == EEXIST)
- shmid = shmget(key, 128, 0666);
- else
- {
- perror("shmget err");
- return -1;
- }
- }
- printf("shmid:%d\n", shmid);
- //映射
- struct msg *p = NULL;
- p = shmat(shmid, NULL, 0); //NULL:系统自动进行映射 0:可读可写
- if (p == (struct msg *)-1)
- {
- perror("shmat err");
- return -1;
- }
- p->flg = 0;
- while (1)
- {
- if (p->flg == 1)
- {
- if (strcmp(p->buf, "quit") == 0)
- break;
- printf("data:%s\n", p->buf);
- p->flg = 0;
- }
- }
- //取消映射
- shmdt(p);
- //删除共享内存
- shmctl(shmid, IPC_RMID, NULL);
- return 0;
- }
复制代码 信号灯集
函数接口
- 步骤
- 0)创建key值
- 1)创建或打开信号灯集 semget
- 2)初始化信号灯集 semctl
- 3)pv操作 semop
- 4)删除信号灯集 semctl
- int semget(key_t key, int nsems, int semflg);
- 功能:创建/打开信号灯
- 参数:key:ftok产生的key值
- nsems:信号灯集中包含的信号灯数目
- semflg:信号灯集的访问权限,通常为IPC_CREAT |0666
- 返回值:成功:信号灯集ID
- 失败:-1
- int semop ( int semid, struct sembuf *opsptr, size_t nops);
- 功能:对信号灯集合中的信号量进行PV操作
- 参数:semid:信号灯集ID
- opsptr:操作方式
- nops: 要操作的信号灯的个数 1个
- 返回值:成功 :0
- 失败:-1
- struct sembuf {
- short
- ; // 要操作的信号灯的编号
- short sem_op; // 0 : 等待,直到信号灯的值变成0
- // 1 : 释放资源,V操作
- // -1 : 分配资源,P操作
- short sem_flg; // 0(阻塞),IPC_NOWAIT, SEM_UNDO
- };
- 用法:
- 申请资源 P操作:
- mysembuf.sem_num = 0;
- mysembuf.sem_op = -1;
- mysembuf.sem_flg = 0;
- semop(semid, &mysembuf, 1);
- 释放资源 V操作:
- mysembuf.sem_num = 0;
- mysembuf.sem_op = 1;
- mysembuf.sem_flg = 0;
- semop(semid, &mysembuf, 1);
- int semctl ( int semid, int semnum, int cmd…/*union semun arg*/);
- 功能:信号灯集合的控制(初始化/删除)
- 参数:semid:信号灯集ID
- semnum: 要操作的集合中的信号灯编号
- cmd:
- GETVAL:获取信号灯的值,返回值是获得值
- SETVAL:设置信号灯的值,需要用到第四个参数:共用体
- IPC_RMID:从系统中删除信号灯集合
- 返回值:成功 0
- 失败 -1
- 用法:初始化:
- union semun{
- int val; //信号灯的初值
- }mysemun;
- mysemun.val = 10;
- semctl(semid, 0, SETVAL, mysemun);
- 获取信号灯值:函数semctl(semid, 0, GETVAL)的返回值
- 删除信号灯集:semctl(semid, 0, IPC_RMID);
- ipcs -s:查看信号灯集
- ipcrm -s semid:删除信号灯集
复制代码 功能实现
- union semun {
- int val; //信号灯的初值
- };
- int main(int argc, char const *argv[])
- {
- key_t key;
- int semid;
- key = ftok("./app", 'b');
- if (key < 0)
- {
- perror("ftok err");
- return -1;
- }
- printf("%#x\n", key);
- //创建或打开信号灯集
- semid = semget(key, 2, IPC_CREAT | IPC_EXCL | 0666);
- if (semid < 0)
- {
- if (errno == EEXIST)
- semid = semget(key, 2, 0666);
- else
- {
- perror("semget err");
- return -1;
- }
- }
- else
- {
- //初始化
- union semun sem;
- sem.val = 10;
- semctl(semid, 0, SETVAL, sem); //对编号为0的信号灯初值设置为10
- sem.val = 0;
- semctl(semid, 1, SETVAL, sem); //对编号为1的信号灯初值设置为0
- }
- printf("semid:%d\n", semid);
- printf("%d\n",semctl(semid, 0, GETVAL));//获取编号为0的信号灯的值
- printf("%d\n",semctl(semid, 1, GETVAL));//获取编号为1的信号灯的值
- //pv操作
- //p操作:申请资源
- struct sembuf buf;
- buf.sem_num = 0; //信号灯的编号
- buf.sem_op = -1; //p操作
- buf.sem_flg = 0; //阻塞
- semop(semid, &buf, 1);
- //v操作:释放资源
- buf.sem_num = 1;
- buf.sem_op = 1; //v操作
- buf.sem_flg = 0;
- semop(semid, &buf, 1);
- printf("%d\n",semctl(semid, 0, GETVAL));//获取编号为0的信号灯的值
- printf("%d\n",semctl(semid, 1, GETVAL));//获取编号为1的信号灯的值
- //删除信号灯集
- semctl(semid, 0, IPC_RMID); //指定任意一个编号即可删除信号灯集
- return 0;
-
复制代码- #include <stdio.h>
- #include <sys/types.h>
- #include <sys/ipc.h>
- #include <sys/sem.h>
- #include <errno.h>
- union semun {
- int val; //信号灯的初值
- };
- //初始化
- void seminit(int semid, int snum, int val)
- {
- union semun sem;
- sem.val = val;
- semctl(semid, snum, SETVAL, sem);
- }
- //pv操作
- void sem_op(int semid, int num, int op)
- {
- struct sembuf buf;
- buf.sem_num = num;
- buf.sem_op = op;
- buf.sem_flg = 0;
- semop(semid, &buf, 1);
- }
- int main(int argc, char const *argv[])
- {
- key_t key;
- int semid;
- key = ftok("./app", 'b');
- if (key < 0)
- {
- perror("ftok err");
- return -1;
- }
- printf("%#x\n", key);
- //创建或打开信号灯集
- semid = semget(key, 2, IPC_CREAT | IPC_EXCL | 0666);
- if (semid < 0)
- {
- if (errno == EEXIST)
- semid = semget(key, 2, 0666);
- else
- {
- perror("semget err");
- return -1;
- }
- }
- else
- {
- //初始化
- seminit(semid, 0, 10);
- seminit(semid, 1, 0);
- }
- printf("semid:%d\n", semid);
- printf("%d\n", semctl(semid, 0, GETVAL)); //获取编号为0的信号灯的值
- printf("%d\n", semctl(semid, 1, GETVAL)); //获取编号为1的信号灯的值
- //pv操作
- //p操作:申请资源
- sem_op(semid, 0, -1);
- //v操作:释放资源
- sem_op(semid, 1, 1);
- printf("%d\n", semctl(semid, 0, GETVAL)); //获取编号为0的信号灯的值
- printf("%d\n", semctl(semid, 1, GETVAL)); //获取编号为1的信号灯的值
- //删除信号灯集
- semctl(semid, 0, IPC_RMID);
- return 0;
- }
复制代码 套接字
网络内容,笔者认为只写传输,脱离了我写这个目的(回顾,然后快速上手),所以放在了网络里面再写吧
其他补充
有名与无名管道的区别
无名管道有名管道特点只能在亲缘关系进程间使用半双工通信方式有固定的读端和写端,fd[0]:读,fd[1]:写端通过文件IO进行操作步骤:创建管道、读写操作不相关的任意进程间使用在路径中有管道文件,实际数据存在内核空间通过文件IO进行操作步骤:创建管道、打开管道、读写操作函数pipemkfifo读写特性当管道中没有数据,读阻塞当写满管道时,写阻塞当管道中没有数据,读阻塞当写满管道时,写阻塞IPC通讯的ftok函数
系统使用IPC通讯也就是消息队列,信号量,共享内存。这些操作都一个步骤就是使用这个函数接口ftok这个函数后面有2个参数const char *pathname, int proj_id第一个为我们创建的文件名,第二个为自己设置的ID值。- key = ftok("./app.c", 'a');
- if (key < 0)
- {
- perror("ftok err");
- return -1;
- }
- printf("%#x\n", key);
- //打印结果为0x6130008e
复制代码比如指定文件的索引节点号为65538,换算成16进制为0x010002,而你指定的ID值为38,换算成16进制为0x26,则最后的key_t返回值为0x26010002。
一个key值是由2部分确定,对应的key值才能通讯。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |