进程间的通信:
IPC(InterProcess Communication )进程间的通信,通过内核提供的缓冲区进行
常见的通信方式:
单工(广播),半双工(对讲机),全双工(打电话)
管道:半双工
pipe通信
成功返回0,失败返回-1. fd[0]代表读端,fd[1]代表写端
读函数read
ssize_t read(int fd,void *buf,size_t nbyte)
read函数是负责从 fd中读取内容到buf中.成功时,read返回实际所读的字节数,如果返回的值是0,表示已经读到文件的结束了.
小于0表示出现了错误.如果错误为 EINTR说明读是由中断引起的, 如果是ECONNREST表示网络连接出了问题.
写函数write
ssize_t write(int fd,const void *buf,size_t nbytes)
write函数将buf中的nbytes字节内容写 入文件描述符fd.成功时返回写的字节数.失败时返回-1. 并设置errno变量. 在网络程序中,当我们向套接字文件描述符写时有俩种可能.
1)write 的返回值大于0,表示写了部分或者是全部的数据.
2)返回的值小于0,此时出现了错误.我们要根据错误类型来处理. 如果错误为EINTR表示在写的时候出现了中断错误.
如果为EPIPE表示网络连接出现了问题(对方已经关闭了连接).
3)nbytes 可以大于实际能写入的大小,比如,缓冲区只能写入100,但却写入1000,前100个字节能写入成功。可利用这个特性加上移动指针反复写入
SIGPIPT是13号信号。
计算管道的大小:512*8
FIFO通信
写:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
int main(int argc,char * argv[])
{
if(argc != 2){
printf("./a.out fifoname\n");
return -1;
}
// 当前目录有一个 myfifo 文件
//打开fifo文件
printf("begin open ....\n");
int fd = open(argv[1],O_WRONLY);
printf("end open ....\n");
//写
char buf[256];
int num = 1;
while(1){
memset(buf,0x00,sizeof(buf));
sprintf(buf,"xiaoming%04d",num++);
write(fd,buf,strlen(buf));
sleep(1);
//循环写
}
//关闭描述符
close(fd);
return 0;
}
读:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
int main(int argc,char *argv[])
{
if(argc != 2){
printf("./a.out fifoname\n");
return -1;
}
printf("begin oepn read...\n");
int fd = open(argv[1],O_RDONLY);
printf("end oepn read...\n");
char buf[256];
int ret;
while(1){
//循环读
memset(buf,0x00,sizeof(buf));
ret = read(fd,buf,sizeof(buf));
if(ret > 0){
printf("read:%s\n",buf);
}
}
close(fd);
return 0;
}
mmap共享映射区
创建映射区:
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
释放映射区:
mmap九问:
mmap实现父子进程通信:
用命令拷贝一个文件的头文件到另一个文件
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <sys/wait.h>
int main()
{
// 先创建映射区
int fd = open("mem.txt",O_RDWR);
//int *mem = mmap(NULL,4,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
int *mem = mmap(NULL,4,PROT_READ|PROT_WRITE,MAP_PRIVATE,fd,0);
if(mem == MAP_FAILED){
perror("mmap err");
return -1;
}
// fork子进程
pid_t pid = fork();
// 父进程和子进程交替修改数据
if(pid == 0 ){
//son
*mem = 100;
printf("child,*mem = %d\n",*mem);
sleep(3);
printf("child,*mem = %d\n",*mem);
}
else if(pid > 0){
//parent
sleep(1);
printf("parent,*mem=%d\n",*mem);
*mem = 1001;
printf("parent,*mem=%d\n",*mem);
wait(NULL);
}
munmap(mem,4);
close(fd);
return 0;
}
匿名映射:
函数说明:ftruncate()会将参数fd 指定的文件大小改为参数length 指定的大小。参数fd 为已打开的文件描述词,而且必须是以写入模式打开的文件。如果原来的文件大小比参数length 大,则超过的部分会被删去。
mmap实现无血缘关系的进程通信:
如果进程要通信,flags必须设为MAP_SHARED
写:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <sys/wait.h>
typedef struct _Student{
int sid;
char sname[20];
}Student;
int main(int argc,char *argv[])
{
if(argc != 2){
printf("./a.out filename\n");
return -1;
}
// 1. open file
int fd = open(argv[1],O_RDWR|O_CREAT|O_TRUNC,0666);
int length = sizeof(Student);
ftruncate(fd,length);
// 2. mmap
Student * stu = mmap(NULL,length,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
if(stu == MAP_FAILED){
perror("mmap err");
return -1;
}
int num = 1;
// 3. 修改内存数据
while(1){
stu->sid = num;
sprintf(stu->sname,"xiaoming-%03d",num++);
sleep(1);//相当于没隔1s修改一次映射区的内容
}
// 4. 释放映射区和关闭文件描述符
munmap(stu,length);
close(fd);
return 0;
}
~
读:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <sys/wait.h>
typedef struct _Student{
int sid;
char sname[20];
}Student;
int main(int argc,char *argv[])
{
//open file
int fd = open(argv[1],O_RDWR);
//mmap
int length = sizeof(Student);
Student *stu = mmap(NULL,length,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
if(stu == MAP_FAILED){
perror("mmap err");
return -1;
}
//read data
while(1){
printf("sid=%d,sname=%s\n",stu->sid,stu->sname);
sleep(1);
}
//close and munmap
munmap(stu,length);
close(fd);
return 0;
}
~