进程间通信(IPC)

进程间通信(IPC)

前言

管道

匿名管道 pipe:适用于亲缘关系进程间的、一对一的通信
具名管道 fifo :适用于任何进程间的一对一、多对一的通信
套接字 socket:适用于跨网络的进程间通信
信号:异步通信方式
system-V IPC对象
共享内存:效率最高的通信方式
消息队列:相当于带标签的增强版管道
信号量组:也称为信号灯,用来协调进程间或线程间的执行进度
POSIX信号量
POSIX匿名信号量:适用于多线程,参数简单,接口明晰
POSIX具名信号量:适用于多进程,参数简单,接口明晰

父子进程使用匿名管道通信
#include <unistd.h>
//读fd[0],一个专用于写fd[1]
int pipe( int fd[2] ); //匿名管道

示例代码如下:

#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
int main(void)
{
    // 创建匿名管道
	int fd[2];
	pipe(fd);
    // 子进程
	if(fork() == 0)
	{
        // 向父进程打招呼
		char *msg = "hello parent!";
		write(fd[1], msg, strlen(msg));
		exit(0);
       // 关掉不必要的读端   
               close(fd[0]);
	}
    // 父进程
	else
	{
	    char buf[50];
            bzero(buf, 50);
        // 静静地等待子进程的消息  阻塞
		read(fd[0], buf, 50);
		printf("来自子进程: %s\n", buf);
		exit(0);
      // 关掉不必要的写端
                close(fd[1]);
	}
}

1普通文件,默认是非阻塞的,且不可修改。
2管道文件,默认是阻塞的,可修改。

 // 1,将管道设置为非阻塞
    long flag = fcntl(fd[0], F_GETFL);
    flag |= O_NONBLOCK; //某位设置为O_NONBLOCK
    fcntl(fd[0], F_SETFL, flag);
// 2,将管道重新设置为阻塞
flag = fcntl(fd[0], F_GETFL);
flag &= ~O_NONBLOCK;  //还原flag的值,某位清零
fcntl(fd[0], F_SETFL, flag);

具名管道FIFO更接近普通文件,有文件名、可以open打开、支持read()/write()等读写操作。
与PIPE一样不支持定位操作lseek()
与PIPE一样秉持相同的管道读写特性
使用专门的接口来创建:mkfifo()(匿名管道是pipe())
在文件系统中有对应节点,支持使用 open() 打开管道(匿名管道不具备)
支持多路同时写入(匿名管道不具备)

#include <sys/types.h>
#include <sys/stat.h>
//mode是文件权限模式,例如0666
int mkfifo(const char *pathname, mode_t mode);
示例代码:
// 进程A,创建管道并向管道写入字符串"data from FIFO."
int main()
{
    // 创建具名管道
    mkfifo("/tmp/fifo", 0666);
    // 向管道写入数据
    int fd = open("/tmp/fifo", O_RDWR);
    char *msg = "data from FIFO";
    write(fd, msg, strlen(msg));
    close(fd);
    return 0;
}
// 进程B,从管道读出数据
int main()
{
    // 从管道读出数据
    int fd = open("/tmp/fifo", O_RDWR);
    char buf[50];
    bzero(buf, 50);
    read(fd, buf, 50);
    printf("%s\n", buf);
    close(fd);
    return 0;
}
编程实现下述命令的执行效果,查看系统进程列表中的指定进程信息:
gec@ubuntu:~$ ps ajx | grep 'xxx' --color
253
gec@ubuntu:~$ 
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
int main(int argc, char **argv)
{
    int fd[2];
    pipe(fd);
    if(argc != 2)
    {
        printf("用法: %s 要搜索的进程名\n", argv[0]);
        exit(0);
    }
    if(fork() == 0) //创建进程
    {
        //fd[1]:写:设置为标准输出
        dup2(fd[1], STDOUT_FILENO);
	// 子进程执行 "ps ajx"
        execlp("ps", "ps", "ajx", NULL);
    }
    else
    {
        close(fd[1]);  //fd[0]:读:设置为标准输入
        dup2(fd[0], STDIN_FILENO);
	// 父进程执行 "grep"   argv[1]: |
        execlp("grep", "grep", argv[1], "--color", NULL);
    }
    exit(0);
}

精灵进程、有名管道FIFO

【2】编程实现两个程序:一个服务器server,一个客户机client。要求:
服务器创建并监视有名管道FIFO,一旦发现有数据则将其保存到一个指定的地方。
客户机每隔一段时间产生一个子进程。
客户机的这些子进程将当前系统时间和自身的PID写入有名管道FIFO就退出。

解答:
// 服务端程序示例代码:

int main(int argc, char **argv)
{
	mkfifo("/tmp/fifo", 0666);
	int fifofd = open("/tmp/fifo", O_RDWR);
	int logfd  = open("/tmp/log.txt", O_WRONLY|O_CREAT|O_APPEND, 0777);
	char buf[1024];
	while(1)
	{
		bzero(buf, 1024);
		read(fifofd, buf, 1024);
		write(logfd, buf, strlen(buf));
	}
	return 0;
}

//客户端代码:

int main(int argc, char **argv)
{
	mkfifo("/tmp/fifo", 0777);
	int fd = open("/tmp/fifo", O_WRONLY);
	char buf[1024];
	time_t t;
	while(1)
	{
		bzero(buf, 1024);
		time(&t);
		snprintf(buf, 1024, "[%-6d] %s",
			getpid(), ctime(&t));
		write(fd, buf, strlen(buf));
		sleep(1);
	}
	return 0;
}

【3】根据管道的读写特性,编写一个程序,测试你系统管道文件的缓冲区大小。

int main()
{
    // 管道默认为阻塞
    int fd[2];
    pipe(fd);
    // 将管道写端设置为非阻塞
    long flag = fcntl(fd[1], F_GETFL);
    flag |= O_NONBLOCK;
    fcntl(fd[1], F_SETFL, flag);
    // 持续不断写入数据,直到报错为止
    int total = 0;
    while(1)
    {
        if(write(fd[1], "x", 1) < 0)
        {
            perror("写入失败");
            break;
        }
        total++;
    }
    printf("缓冲区大小:%d个字节\n", total);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Qt历险记

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值