IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 系统运维 -> Linux C 进程间的通信——无名管道、有名管道、信号 -> 正文阅读

[系统运维]Linux C 进程间的通信——无名管道、有名管道、信号

一、无名管道

? ? ? ? 无名管道是早期的进程通信,主要用于父子进程或带有血缘关系的进程(进程组)间的通信,比较简单,主要用到的函数有一个:

#include <unistd.h>
int pipe(int pipefd[2]);    // 创建无名管道
// pipefd是存放文件描述符的数组
// pipefd[0]代表读
// pipefd[1]代表写

? ? ? ? ? 以下是测试代码,没有加入线程,只实现了单向通信,父进程往管道里写数据,子进程读取父进程写入的数据

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>

int main(int argc,char *argv[])
{
    //创建无名管道
	int pipefd[2];
	if(pipe(pipefd)){					
		perror("pipe error");
		exit(-1);
	}
	printf("[0] %d \n",pipefd[0]);    //pipefd[0]:读
	printf("[1] %d \n",pipefd[1]);    //pipefd[1]: 写
	
	//创建进程
	pid_t pid = fork();
	if(pid < 0){
		perror("fork error");
		exit(1);
	}else if(pid == 0){
		//子进程读取父进程写入的数据
		close(pipefd[1]);	//子进程只读取数据,所以把写关闭
		char buf[50];
		while(1){
			bzero(buf,sizeof(buf));//清空数组
			read(pipefd[0],buf,sizeof(buf));//读取数据
			printf("父进程:%s\n",buf);

		}
	}else{
		//父进程写入数据
		close(pipefd[0]);//父进程只写数据,所以把读关闭
		char buf[50];	
		while(1){
			bzero(buf,sizeof(buf));//清空数组 
            gets(buf);

			write(pipefd[1],buf,strlen(buf));//父进程写数据到pipefd[1]里
			
		}
	}
	
	return 0;
}

? ? ? ? 运行结果:

iot@ubuntu:~/shared/process/day3/temp$ ./a.out 
[0] 3 
[1] 4 
ni gan ma
父进程: ni gan ma
ai u 
父进程: ai u
buyaozaidale
父进程: buyaozaidale
^C
iot@ubuntu:~/shared/process/day3/temp$ 

二、有名管道

? ? ? ? 有名管道也属于早期进程通信的一种,可以用于任意进程间的通信,比无名管道灵活,主要用到的函数有:

#include <sys/types.h>
#include <sys/stat.h>

/**
  ***********************************
  *@brief  创建有名管道
  *@param  pathname:带文件名的路径 
           mode:文件的八进制权限
  *@retval int 
			成功返回0
			失败返回-1,并返回错误码EOF
  ***********************************
  */
int mkfifo(const char *pathname, mode_t mode);

? ? ? ? 测试代码如下,单向通信,进程1往管道里写数据,进程2从管道里读取数据,这两个进程可以是任意进程。

进程1:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

int main(int argc,char *argv[])
{
	if(argc != 2){
		printf("User :%s <name>\n",argv[0]);
		exit(1);
	}
	

	if(mkfifo(argv[1],0666)){	//创建管道文件,文件名需要从外部传进来
		perror("mkfifo error");
		exit(-1);
	}
	
	
	//往管道文件里写数据,文件IO
	int fd = open("./ikun",O_RDWR);    //以读写方式打开文件,打开管道
	if(fd < 0){
		perror("open error");
		exit(1);
	}

	char buf[50]; //数据缓冲区大小
	while(1){
		bzero(buf,sizeof(buf));  //初始化空间清零
		gets(buf);	        //从键盘获取数据,把数据写入buf
		write(fd,buf,sizeof(buf));  //把buf里的数据写给fd
			
	}
	close(fd);    
	
	return 0;
}

进程2:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

int main(int argc,char *argv[])
{
	if(argc != 2){
		printf("User :%s <name>\n",argv[0]);
		exit(1);
	}
	
	mkfifo(argv[1],0664);
	//往管道文件里写数据
	int fd = open(argv[1],O_RDWR);//以读写方式打开文件,打开管道
	if(fd < 0){
		perror("open error");
		exit(1);
	}

	char buf[50];
	while(1){
		bzero(buf,sizeof(buf));
		read(fd,buf,sizeof(buf));//从fd中读取buf里的数据
		printf("%s\n",buf);//把buf里的数据打印出屏幕
		
	}
	close(fd);
	
	return 0;
}

? ? ? ? 进程1创建一个名为ikun的有名管道,运行进程1就可以在当前目录下生成管道文件ikun,我们用 ls -l 查看一下,ikun的文件类型为p,说明我们创建成功。注:管道文件由内核区域映射,文件大小永远为0。

iot@ubuntu:~/shared/process/day3/temp$ ./mkfifo1 ikun
^C
iot@ubuntu:~/shared/process/day3/temp$ ls -l
total 48
-rwxrwxr-x 1 iot iot 8600 Sep 11 04:32 a.out
prw-rw-r-- 1 iot iot    0 Sep 11 04:44 ikun
-rwxrwxr-x 1 iot iot 8560 Sep 11 04:36 mkfifo1
-rw-rw-r-- 1 iot iot  724 Sep 11 04:36 mkfifo1.c
-rwxrwxr-x 1 iot iot 8600 Sep 11 04:33 mkfifo2
-rw-rw-r-- 1 iot iot  632 Sep 11 04:09 mkfifo2.c

????????进程2用到了main函数传参,所以先运行进程1,将管道文件创建出来,再运行进程2,将管道文件名传进去。另开一个终端,运行进程2,在进程1输入的数据将会在进程2打印出来,即实现了进程间的单向通信。

?

三、信号

? ? ? ? 信号也属于早期进程间的通信,信号是软件层面上对中断机制的一种模拟,是一种异步的通信,信号可以直接进行用户空间进程和内核进程之间的交互。在linux中用命令 kill -l 查看所有的信号

? ? ? ? ?与信号通信相关的函数有以下:

1. kill
#include <sys/types.h>
#include <signal.h>

/**
  ***********************************
  *@brief  发送信号
  *@param  pid:进程号 
           sig:信号
  *@retval int 
			成功返回0
			失败返回-1,并返回错误码EOF
  ***********************************
  */
int kill(pid_t pid, int sig);


2. signal
/**
  ***********************************
  *@brief  信号注册
  *@param  signum:信号 
           handler:事件,捕捉到信号signum后要执行的操作(函数)
  *@retval sighandler_t
			成功返回sighandler_t
			失败返回SIG_ERR,并返回错误码
  ***********************************
  */
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);

????????测试代码如下:

kill_1:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <signal.h>

int main(int argc,char *argv[])
{
    if(argc != 3){
	printf("User %s<PID><SIG>",argv[0]);
	    exit(-1);
    }
    //int a = atoi(argv[1]);//将pid号从字符窜转化为整形
    // int b = atoi(argv[2]);//将sig号从字符串转化为整形
    // printf("a=%d b=%d\n",a,b);//将两个以转换的整形打印出来

    kill(atoi(argv[1]),atoi(argv[2]));
    return 0;
}

kill_2:

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>

void show(int sig)
{
    printf("你干嘛~\n");
}

int main(void)
{
   // signal(2,SIG_IGN);//将信号2忽略
   //signal(2,SIG_DFL);//收到信号2默认执行
    signal(2,show);
    while(1){
	    sleep(1);
	    printf("%d\n",getpid());    //获取当前进程的pid号
    }
    return 0;
}

? ? ? ? 先运行kill_2,每隔1s打印一次当前的进程号,另开一个终端,运行kill_1,每执行一次 ./kill_2 10834 2 就会向进程10834发送一个信号2,kill_2收到信号2后,打印一次你干嘛~

?

? ? ? ? 至此,早期的进程通信结束,下期将更新在 system V 之后的进程间的通信——共享内存、消息队列、信号灯(信号量)。

? ? ? ? 以上测试代码仅实现单向通信,要实现双向通信的话加个线程即可。

?

  系统运维 最新文章
配置小型公司网络WLAN基本业务(AC通过三层
如何在交付运维过程中建立风险底线意识,提
快速传输大文件,怎么通过网络传大文件给对
从游戏服务端角度分析移动同步(状态同步)
MySQL使用MyCat实现分库分表
如何用DWDM射频光纤技术实现200公里外的站点
国内顺畅下载k8s.gcr.io的镜像
自动化测试appium
ctfshow ssrf
Linux操作系统学习之实用指令(Centos7/8均
上一篇文章      下一篇文章      查看所有文章
加:2022-09-13 11:56:34  更:2022-09-13 11:58:51 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年6日历 -2024/6/27 1:11:06-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码