ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

进程间的通信

进程间的通信 一、概念进程间通信Inter-Process CommunicationIPC是指在不同进程之间进行信息交换和同步的机制。二、实现方式1、管道1无名管道原理它是一种半双工的通信方式数据只能单向流动并且只能在具有亲缘关系如父子进程的进程之间使用。无名管道在内核中通过一个环形缓冲区来实现管道的两端分别是读端和写端。特点创建简单使用方便但功能相对有限数据传输的方向性强适用于亲缘关系进程间的简单数据传递进程间的通信方式——pipe管道-CSDN博客man 2 pipeint pipe(int pipefd[2]);功能创建操作管道的两个文件描述符参数pipefd: 存放文件描述符的数组pipefd[0]:读文件描述符用于从管道中读取数据。pipefd[1]:写文件描述符用于向管道中写入数据。返回值成功返回0失败返回-1#include stdio.h #include public.h char tmpbuff[4096] {0}; int main(int argc, const char **argv) { pid_t pid; int pipefd[2]; int ret 0; ret pipe(pipefd); if (-1 ret) { ERR_MSG(fail to pipe); return -1; } pid fork(); if (-1 pid) { ERR_MSG(fail to fork); return -1; } if (0 pid) { close(pipefd[0]); //用不到读所以先关掉如上图3 strcpy(tmpbuff, hello world); write(pipefd[1], tmpbuff, strlen(tmpbuff)); //将 tmpbuff 中的数据写入管道。 close(pipefd[1]); //写用完了关掉 } else if (pid 0) { close(pipefd[1]); //用不到写所以先关掉如上图3 read(pipefd[0], tmpbuff, sizeof(tmpbuff)); //将管道中的数据读到 tmpbuff 中。 printf(tmpbuff %s\n, tmpbuff); close(pipefd[0]); //读完了关掉 } return 0; }2有名管道原理它是一种特殊的文件在文件系统中以文件名的形式存在突破了无名管道只能在亲缘关系进程间通信的限制不同进程可以通过该文件名来访问管道进行通信。特点有自己的文件路径可以在不相关的进程间使用实现了不同进程在文件系统层面的通信接口。man 3 mkfifoint mkfifo(const char *pathname, mode_t mode);功能创建管道文件参数pathname:管道文件名mode:权限返回值成功返回0失败返回-1用有名管道实现单工通信send.c文件#include stdio.h #include public.h int main(int argc, const char **argv) { int fd 0; char tmpbuff[1024] {0}; int ret mkfifo(/tmp/myfifo, 0777); if(-1 ret errno ! EEXIST) //EEXIST:它表示在尝试创建文件或目录时目标文件或目录已经存在。 //errno ! EEXIST表示错误原因不是因为文件已经存在了 { perror(mkfifo error); return -1; } fd open(/tmp/myfifo, O_RDWR); if (-1 fd) { ERR_MSG(fail to open); return -1; } gets(tmpbuff); write(fd, tmpbuff, strlen(tmpbuff)); close(fd); return 0; }recv.c文件#include stdio.h #include public.h int main(int argc, const char **argv) { int fd 0; char tmpbuff[1024] {0}; int ret mkfifo(/tmp/myfifo, 0777); if(-1 ret errno ! EEXIST) //EEXIST:它表示在尝试创建文件或目录时目标文件或目录已经存在。 //errno ! EEXIST表示错误原因不是因为文件已经存在了 { perror(mkfifo error); return -1; } fd open(/tmp/myfifo, O_RDWR); if (-1 fd) { ERR_MSG(fail to open); return -1; } read(fd, tmpbuff, sizeof(tmpbuff)); printf(RECV:%s\n, tmpbuff); close(fd); remove(myfifo); //读完删除管道文件 return 0; }编译send.c文件生成可执行文件send编译recv.c文件生成可执行文件recv执行send文件向管道中输入hello与此同时在执行当中的recv文件会从管道中接收到hello并打印出来3管道的特点管道本质是内核中的一段缓冲区默认64K字节遵循队列存储方式(FFO)。1.写阻塞当管道的读写端都存在时管道写满数据时再写会发生写阻塞。2.读阻塞当管道的读写端都存在时管道为空时再读管道会发生读阻塞。3.读返回0当管道没有写端只有读端时管道中有数据则读出数据无数据时不再读阻塞读管道(read)函数的返回值返回0。4.管道破裂当管道没有读端向管道中写数据发生管道破裂异常用有名管道实现半双工通信send.c文件#include stdio.h #include public.h int main(int argc, const char **argv) { int fatob 0; int fbtoa 0; char tmpbuff[4096] {0}; mkfifo(/tmp/ATOB, 0777); mkfifo(/tmp/BTOA, 0777); fatob open(/tmp/ATOB, O_WRONLY); //send.c文件中打开写端等待recv.c文件打开读端口管道才会打开成功 if (-1 fatob) { ERR_MSG(fail to open); return -1; } fbtoa open(/tmp/BTOA, O_RDONLY); //同理 if (-1 fbtoa) { ERR_MSG(fail to open); return -1; } printf(管道打开成功!\n); while (1) { gets(tmpbuff); write(fatob, tmpbuff, strlen(tmpbuff)); memset(tmpbuff, 0, sizeof(tmpbuff)); read(fbtoa, tmpbuff, sizeof(tmpbuff)); printf(RECV:%s\n, tmpbuff); } close(fatob); close(fbtoa); return 0; }recv.c文件#include stdio.h #include public.h int main(int argc, const char **argv) { int fatob 0; int fbtoa 0; char tmpbuff[4096] {0}; mkfifo(/tmp/ATOB, 0777); mkfifo(/tmp/BTOA, 0777); fatob open(/tmp/ATOB, O_RDONLY); if (-1 fatob) { ERR_MSG(fail to open); return -1; } fbtoa open(/tmp/BTOA, O_WRONLY); if (-1 fbtoa) { ERR_MSG(fail to open); return -1; } printf(管道打开成功!\n); while (1) { memset(tmpbuff, 0, sizeof(tmpbuff)); read(fatob, tmpbuff, sizeof(tmpbuff)); printf(RECV:%s\n, tmpbuff); gets(tmpbuff); write(fbtoa, tmpbuff, strlen(tmpbuff)); } close(fatob); close(fbtoa); return 0; }用有名管道实现全双工通信老王.c#include stdio.h #include public.h int fatob 0; int fbtoa 0; void *sendfun(void *arg) { char tmpbuff[4096] {0}; while (1) { gets(tmpbuff); if (0 strcmp(tmpbuff, .quit)) { break; } write(fbtoa, tmpbuff, strlen(tmpbuff)); } close(fbtoa); return NULL; } void *recvfun(void *arg) { char tmpbuff[4096] {0}; ssize_t nret 0; while (1) { memset(tmpbuff, 0, sizeof(tmpbuff)); nret read(fatob, tmpbuff, sizeof(tmpbuff)); if (0 nret) { break; } printf(RECV:%s\n, tmpbuff); } return NULL; } int main(int argc, const char **argv) { pthread_t tid_send; pthread_t tid_recv; char tmpbuff[4096] {0}; mkfifo(/tmp/ATOB, 0777); mkfifo(/tmp/BTOA, 0777); fatob open(/tmp/ATOB, O_RDONLY); if (-1 fatob) { ERR_MSG(fail to open); return -1; } fbtoa open(/tmp/BTOA, O_WRONLY); if (-1 fbtoa) { ERR_MSG(fail to open); return -1; } printf(管道打开成功!\n); pthread_create(tid_send, NULL, sendfun, NULL); pthread_create(tid_recv, NULL, recvfun, NULL); pthread_join(tid_send, NULL); pthread_join(tid_recv, NULL); #if 0 while (1) { gets(tmpbuff); write(fatob, tmpbuff, strlen(tmpbuff)); memset(tmpbuff, 0, sizeof(tmpbuff)); read(fbtoa, tmpbuff, sizeof(tmpbuff)); printf(RECV:%s\n, tmpbuff); } #endif close(fatob); return 0; }老李.c#include stdio.h #include public.h int fatob 0; int fbtoa 0; void *sendfun(void *arg) { char tmpbuff[4096] {0}; while (1) { gets(tmpbuff); if (0 strcmp(tmpbuff, .quit)) { break; } write(fatob, tmpbuff, strlen(tmpbuff)); } close(fatob); return NULL; } void *recvfun(void *arg) { char tmpbuff[4096] {0}; ssize_t nret 0; while (1) { memset(tmpbuff, 0, sizeof(tmpbuff)); nret read(fbtoa, tmpbuff, sizeof(tmpbuff)); if (0 nret) { break; } printf(RECV:%s\n, tmpbuff); } return NULL; } int main(int argc, const char **argv) { pthread_t tid_send; pthread_t tid_recv; char tmpbuff[4096] {0}; mkfifo(/tmp/ATOB, 0777); mkfifo(/tmp/BTOA, 0777); fatob open(/tmp/ATOB, O_WRONLY); if (-1 fatob) { ERR_MSG(fail to open); return -1; } fbtoa open(/tmp/BTOA, O_RDONLY); if (-1 fbtoa) { ERR_MSG(fail to open); return -1; } printf(管道打开成功!\n); pthread_create(tid_send, NULL, sendfun, NULL); pthread_create(tid_recv, NULL, recvfun, NULL); pthread_join(tid_send, NULL); pthread_join(tid_recv, NULL); #if 0 while (1) { gets(tmpbuff); write(fatob, tmpbuff, strlen(tmpbuff)); memset(tmpbuff, 0, sizeof(tmpbuff)); read(fbtoa, tmpbuff, sizeof(tmpbuff)); printf(RECV:%s\n, tmpbuff); } #endif close(fbtoa); return 0; }2、信号1概念进程间通知机制不携带数据信号可以看作是一种轻量级的软件中断它能够在进程运行过程中异步地通知进程某一特定事件已经发生。当信号发送给进程时进程会暂停当前正在执行的任务转而去处理该信号对应的事件。处理完毕后进程可能会继续执行之前暂停的任务也可能根据信号的处理结果做出其他操作。例如在 Linux 系统中用户按下Ctrl C组合键会产生一个SIGINT信号发送给当前正在运行的前台进程通知该进程要终止运行。1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP 6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1 11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM 16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP 21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ 26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR 31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN1 36) SIGRTMIN2 37) SIGRTMIN3 38) SIGRTMIN4 39) SIGRTMIN5 40) SIGRTMIN6 41) SIGRTMIN7 42) SIGRTMIN8 43) SIGRTMIN9 44) SIGRTMIN10 45) SIGRTMIN11 46) SIGRTMIN12 47) SIGRTMIN13 48) SIGRTMIN14 49) SIGRTMIN15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12 53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7 58) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2 63) SIGRTMAX-1 64) SIGRTMAX 2 SIGINT:ctrl c 让一个进程被打断 3 SIGQUIT:ctrl \ 让一个进程结束 9 SIGKILL: 强制让一个进程结束 11SIGSEGV: 让一个进程结束(段错误) 13SIGPIPE: 让一个进程结束(管道破裂) 14SIGALRM: 让一个进程结束(定时时间到达) 17SIGCHLD: 子进程结束时发送给父进程 18SIGCONT: 让停止态的进程继续执行 19SIGSTOP: 让运行态的进程进入停止态暂停强制停止 20SIGTSTP: ctrl z 让进程进入暂停态后台进程 来自终端的停止信号 10 SIGUSR1 12 SIGUSR2 专门预留给程序员使用的未定义信号。2注册信号sighandler_t signal(int signum, sighandler_t handler);功能注册一个信号参数signum 要注册的信号的编号handler对信号的处理方式SIG_IGN : 按忽略方式处理SIG_DFL 按照缺省方式处理自定义的函数按照捕获方式处理返回值成功handler失败SIG_ERR信号处理方式1. 忽略 不处理2. 缺省 按照操作系统默认方式处理3. 捕获 按照自定义方式处理#include stdio.h #include unistd.h #include signal.h void handler(int signum) { printf(%d signal comming\n, signum); } int main(void) { // signal(SIGINT, SIG_IGN); //信号的处理方式一: 不处理即不对SIGINT信号做处理终端一直打印hello world,按下ctrlc进程结束不了。 // signal(SIGINT, SIG_DFL); //方式二按照操作系统默认方式处理终端一直打印hello world,按下ctrlc进程结束。 signal(SIGINT, handler); //方式三按照自定义方式处理自定义方式遵循handler函数执行终端一直打印hello world,按下ctrlc进程不结束打印一句signal comming后继续打印hello world。 while (1) { printf(hello world\n); sleep(1); } return 0; }3、消息队列4、共享内存5、信号灯6、套接字
返回列表