LINUX 进程间通信程序设计一
来源:互联网 发布:淘宝crm解决方案论文 编辑:程序博客网 时间:2024/05/19 09:17
1、管道(pipe)和有名管道(FIFO)
2、信号(signal)
3、共享内存
4、消息队列
6、套接字(socket)(研究通讯时再讲)
1、管道通信
管道是单向的、先进先出的,它把一个进程的输出和另一个进程的输入连接在一起。一个进程(写进程)在管道的尾部写入数据,另一个进程(读进程)从管道的头部读出数据。
数据被一个进程读出后,将被从管道中删除,其它读进程将不能再读到这些数据。管道提供了简单的流控制机制,进程试图读空管道时,进程将阻塞。同样,管道已经满时,进程再试图向管道写入数据,进程将阻塞。
管道包括无名管道和有名管道两种,前者用于父进程和子进程间的通信,后者可用于运行于同一系统中的任意两个进程间的通信。
无名管道由pipe()函数创建:int pipe(int filedis[2]);
当一个管道建立时,它会创建两个文件描述符:filedis[0] 用于读管道, filedis[1] 用于写管道。
管道关闭:关闭管道只需将这两个文件描述符关闭即可,可以使用普通的close函数逐个关闭。
#include <unistd.h>#include <errno.h>#include <stdio.h>#include <stdlib.h>int main(){ int pipe_fd[2]; if(pipe(pipe_fd)<0) { printf("pipe create error\n"); return -1; } else printf("pipe create success\n"); close(pipe_fd[0]); close(pipe_fd[1]);}
管道用于不同进程间通信。通常先创建一个管道,再通过fork函数创建一个子进程,该子进程会继承父进程所创建的管道。
注意:必须在系统调用fork( )前调用pipe( ),否则子进程将不会继承文件描述符。
#include <unistd.h>#include <sys/types.h>#include <errno.h>#include <stdio.h>#include <string.h>#include <stdlib.h>int main(){int pipe_fd[2];pid_t pid;char buf_r[100];char* p_wbuf;int r_num;memset(buf_r,0,sizeof(buf_r));/*创建管道*/if(pipe(pipe_fd)<0){printf("pipe create error\n");return -1;}/*创建子进程*/if((pid=fork())==0) //子进程执行序列{printf("\n");close(pipe_fd[1]);//子进程先关闭了管道的写端sleep(2); /*让父进程先运行,这样父进程先写子进程才有内容读*/if((r_num=read(pipe_fd[0],buf_r,100))>0){printf("%d numbers read from the pipe is %s\n",r_num,buf_r);}close(pipe_fd[0]);exit(0); }else if(pid>0) //父进程执行序列{close(pipe_fd[0]); //父进程先关闭了管道的读端if(write(pipe_fd[1],"Hello",5)!=-1)printf("parent write1 Hello!\n");if(write(pipe_fd[1]," Pipe",5)!=-1)printf("parent write2 Pipe!\n");close(pipe_fd[1]);waitpid(pid,NULL,0); /*等待子进程结束*/exit(0);}return 0;}
命名管道(FIFO)
命名管道和无名管道基本相同,但也有不同点:无名管道只能由父子进程使用;但是通过命名管道,不相关的进程也能交换数据。
1)创建
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char * pathname, mode_t mode)
参数:
pathname:FIFO文件名
mode:属性一旦创建了一个FIFO,就可用open打开它,一般的文件访问函数(close、read、write等)都可用于FIFO。
函数说明:
#include <sys/types.h>#include <sys/stat.h>#include <errno.h>#include <fcntl.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#define FIFO_SERVER "/tmp/myfifo"int main(int argc,char** argv){int fd;char w_buf[100];int nwrite; /*创建有名管道*/if((mkfifo(FIFO_SERVER,O_CREAT|O_EXCL|O_RDWR)<0)&&(errno!=EEXIST))printf("cannot create fifoserver\n");/*打开管道*/fd=open(FIFO_SERVER,O_RDWR|O_NONBLOCK,0);if(fd==-1){ perror("open");exit(1);}/*入参检测*/if(argc==1){printf("Please send something\n");exit(-1);}strcpy(w_buf,argv[1]);/* 向管道写入数据 */if((nwrite=write(fd,w_buf,100))==-1){if(errno==EAGAIN)printf("The FIFO has not been read yet.Please try later\n");}else printf("write %s to the FIFO\n",w_buf);close(fd); //关闭管道return 0;}
fifo_read.c
#include <sys/types.h>#include <sys/stat.h>#include <errno.h>#include <fcntl.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#define FIFO "/tmp/myfifo"int main(int argc,char** argv){char buf_r[100];int fd;int nread;printf("Preparing for reading bytes...\n");memset(buf_r,0,sizeof(buf_r));/* 打开管道 */fd=open(FIFO,O_RDONLY|O_NONBLOCK,0);if(fd==-1){perror("open");exit(1);}while(1){memset(buf_r,0,sizeof(buf_r));if((nread=read(fd,buf_r,100))==-1){if(errno==EAGAIN)printf("no data yet\n");}printf("read %s from FIFO\n",buf_r);sleep(1);} //后面三句话是不会被运行到的,但不会影响程序运行的效果当程序在上面的死循环中执行时收到信号后会马上结束运行而没有执行后面的三句话。这些会在后面的信号处理中讲到,现在不理解没有关系,这个问题留给大家学习了信号处理之后来解决。close(fd); //关闭管道pause(); /*暂停,等待信号*/unlink(FIFO); //删除文件}
2、信号通信
信号(signal)机制是Unix系统中最为古老的进程间通信机制,很多条件可以产生一个信号:
1)、当用户按某些按键时,产生信号。
2)、硬件异常产生信号:除数为0、无效的存储访问等等。这些情况通常由硬件检测到,将其通知内核,然后内核产生适当的信号通知进程,例
如,内核对正访问一个无效存储区的进程产生一个SIGSEGV信号。
3)、进程用kill函数将信号发送给另一个进程。
4)、用户可用kill命令将信号发送给其他进程。
信号类型
下面是几种常见的信号:
§ SIGHUP: 从终端上发出的结束信号
§ SIGINT: 来自键盘的中断信号(Ctrl-C)
§ SIGKILL:该信号结束接收信号的进程
§ SIGTERM:kill 命令发出的信号
§ SIGCHLD:标识子进程停止或结束的信号
§ SIGSTOP:来自键盘(Ctrl-Z)或调试程序的停止执行信号
当某信号出现时,将按照下列三种方式中的一种进行处理:
1)、忽略此信号
大多数信号都按照这种方式进行处理,但有两种信号却决不能被忽略。它们是:SIGKILL和SIGSTOP。这两种信号不能被忽略的原因是:它们向超级用户提供了一种终止或停止进程的方法。
2)、执行用户希望的动作
通知内核在某种信号发生时,调用一个用户函数。在用户函数中,执行用户希望的处理。
3)、执行系统默认动作
对大多数信号的系统默认动作是终止该进程。
发送信号的主要函数有 kill和raise。
区别:
Kill既可以向自身发送信号,也可以向其他进程发送信号。与kill函数不同的是,raise函数是向进程自身发送信号。
#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int signo)
函数说明
返回值 执行成功则返回0,如果有错误则返回-1。
#include <signal.h>
int raise(int signo)
使用alarm函数可以设置一个时间值(闹钟时间),当所设置的时间到了时,产生SIGALRM信号。如果不捕捉此信号,则默认动作是终止该进程。
#include <unistd.h>
unsigned int alarm(unsigned int seconds)
Seconds:
经过了指定的seconds秒后会产生信号SIGALRM。
返回值:
每个进程只能有一个闹钟时间。如果在调用alarm时,以前已为该进程设置过闹钟时间,而且它还没有超时,以前登记的闹钟时间则被新值代换。
如果有以前登记的尚未超过的闹钟时间,而这次seconds值是0,则表示取消以前的闹钟。
Pause
pause函数使调用进程挂起直至捕捉到一个信号。
#include <unistd.h>
int pause(void)
函数说明:只有执行了一个信号处理函数后,挂起才结束。pause()会令目前的进程暂停(进入睡眠状态),直到被信号(signal)所中断。
返回值: 只返回-1。
signal
#include <signal.h>
void (*signal (int signo, void (*func)(int)))(int)
如何理解?
typedef void (*sighandler_t)(int)
sighandler_t signal(int signum, sighandler_t handler))
Func可能的值是:
1、SIG_IGN:忽略此信号
2、SIG_DFL: 按系统默认方式处理
3、信号处理函数名:使用该函数处理
#include <signal.h>#include <stdio.h>#include <stdlib.h>/*自定义信号处理函数*/void my_func(int sign_no){if(sign_no==SIGBUS)printf("I have get SIGBUS\n");}int main(){printf("Waiting for signal SIGBUS \n ");/*注册信号处理函数*/signal(SIGBUS,my_func);pause();//将进程挂起直到捕捉到信号为止exit(0);}
3、共享内存
共享内存是被多个进程共享的一部分物理内存。共享内存是进程间共享数据的一种最快的方法,一个进程向共享内存区域写入了数据,共享这个内存区域的所有进程就可以立刻看到其中的内容。
共享内存实现分为两个步骤:
一、创建共享内存,使用shmget函数。
二、映射共享内存,将这段创建的共享内存映射到具体的进程空间去,使用shmat函数。
共享内存函数由shmget、shmat、shmdt、shmctl四个函数组成。
shmget函数原型
shm_com.h
#define TEXT_SZ 2048struct shared_use_st{ int written_by_you; char some_text[TEXT_SZ];};shm1.c
#include <unistd.h>#include <stdlib.h>#include <stdio.h>#include <string.h>#include <sys/types.h>#include <sys/ipc.h>#include <sys/shm.h>#include "shm_com.h"int main(void){ int running=1;void *shared_memory=(void *)0;struct shared_use_st *shared_stuff;int shmid;/*创建共享内存*/shmid=shmget((key_t)1234,sizeof(struct shared_use_st),0666|IPC_CREAT);if(shmid==-1){ fprintf(stderr,"shmget failed\n");exit(EXIT_FAILURE);}/*映射共享内存*/shared_memory=shmat(shmid,(void *)0,0);if(shared_memory==(void *)-1){ fprintf(stderr,"shmat failed\n");exit(EXIT_FAILURE);}printf("Memory attached at %X\n",(int)shared_memory);/*让结构体指针指向这块共享内存*/shared_stuff=(struct shared_use_st *)shared_memory;/*控制读写顺序*/shared_stuff->written_by_you=0;/*循环的从共享内存中读数据,直到读到“end”为止*/while(running){ if(shared_stuff->written_by_you) { printf("You wrote:%s",shared_stuff->some_text); sleep(1); //读进程睡一秒,同时会导致写进程睡一秒,这样做到读了之后再写 shared_stuff->written_by_you=0; if(strncmp(shared_stuff->some_text,"end",3)==0) { running=0; //结束循环 } }}/*删除共享内存*/if(shmdt(shared_memory)==-1){ fprintf(stderr,"shmdt failed\n"); exit(EXIT_FAILURE);} exit(EXIT_SUCCESS);}
shm2.c
#include <unistd.h>#include <stdlib.h>#include <stdio.h>#include <string.h>#include <sys/types.h>#include <sys/ipc.h>#include <sys/shm.h>#include "shm_com.h"int main(void){ int running=1;void *shared_memory=(void *)0;struct shared_use_st *shared_stuff;char buffer[BUFSIZ];int shmid;/*创建共享内存*/shmid=shmget((key_t)1234,sizeof(struct shared_use_st),0666|IPC_CREAT);if(shmid==-1){ fprintf(stderr,"shmget failed\n");exit(EXIT_FAILURE);}/*映射共享内存*/shared_memory=shmat(shmid,(void *)0,0);if(shared_memory==(void *)-1){ fprintf(stderr,"shmat failed\n");exit(EXIT_FAILURE);}printf("Memory attached at %X\n",(int)shared_memory);/*让结构体指针指向这块共享内存*/shared_stuff=(struct shared_use_st *)shared_memory;/*循环的向共享内存中写数据,直到写入的为“end”为止*/while(running){ while(shared_stuff->written_by_you==1){ sleep(1);//等到读进程读完之后再写printf("waiting for client...\n");}printf("Ener some text:");fgets(buffer,BUFSIZ,stdin);strncpy(shared_stuff->some_text,buffer,TEXT_SZ);shared_stuff->written_by_you=1;if(strncmp(buffer,"end",3)==0){ running=0; //结束循环}}/*删除共享内存*/if(shmdt(shared_memory)==-1){ fprintf(stderr,"shmdt failed\n");exit(EXIT_FAILURE);}exit(EXIT_SUCCESS);}
- LINUX 进程间通信程序设计一
- LINUX 进程间通信程序设计
- Linux程序设计笔记-进程间通信
- LINUX 进程间通信程序设计-2
- 高级Linux程序设计第五章:进程间通信
- Linux程序设计——进程间通信:管道
- linux应用程序设计基础--进程间通信(IPC)
- 高级Linux程序设计第五章:进程间通信
- 《Linux程序设计》--读书笔记---第十三章进程间通信:管道
- 高级Linux程序设计第五章:进程间通信
- Linux程序设计学习笔记----进程间通信——管道
- Linux程序设计学习笔记----System V进程间通信(信号量)
- 《Linux程序设计》——进程间通信:管道
- Linux程序设计——进程间通信机制
- Linux环境进程间通信(一)
- Linux环境进程间通信(一)
- Linux环境进程间通信(一)
- Linux环境进程间通信(一)
- Windows双系统共享应用软件的三种方法介绍
- VIM教程
- Struts2 中继承ActionSupport类,都需要jar包
- Form添加MOAC:多组织访问控制
- IT职业发展路线图
- LINUX 进程间通信程序设计一
- gentoo资料
- STL技术中search()算法
- Nginx 413 修改上传文件大小限制
- 福大数据结构与算法实验题 Who is behind(双端队列)
- 任务调度命令crontab
- VS2008 编译 boost::python boost::serialization 方法
- 使用会员卡消费算法
- get 方式请求乱码以及用Jquery ajax 乱码问题的解决;