进程间的通信(Linux)

目录

1、管道

(1)无名管道

  1)无名管道的创建 --pipe()

  2)无名管道的读写特性

(2)、有名管道

2、信号

(1)常用信号

(2)信号相关指令

(3)信号相关接口函数 -- kill

(4)定时器

(5)捕获信号 -- signal


 

进程间通信机制: 

unix继承:管道、信号

system V IPC对象:共享内存、消息队列、信号灯集

                                套接字

 

1、管道

管道分为无名管道和有名管道 -- 区别在于创建的管道能否在文件系统中可见

(1)无名管道

特点:

1、在创建之后在文件系统中不可见

2、以半双工的方式进行通信

3、拥有固定的读端和写端

4、只能用于具有亲缘关系的进程间通信

  1)无名管道的创建 --pipe()

       #include <unistd.h>

       int pipe(int pipefd[2]);
参数:
    pipefd:存放无名管道读端和写端的数组首地址
        pipefd[0] -- 读端
        pipefd[1] -- 写端
返回值:
    成功返回0,失败返回-1

 练习:在一个进程中创建一个子进程,子进程从键盘获取数据,父进程打印输出

 代码示例:

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

int main(int argc, char *argv[])
{
    int fd[2] = {0};//定义无名管道读写端的数组
    int ret = pipe(fd);//创建无名管道
    if(ret < 0)
        {
        perror("pipe");
        exit(-1);
    }
    
    pid_t pid = fork();
    if(pid < 0)
    {
        perror("fork");
        exit(-1);
    }
    if(pid == 0)//子进程
    {
        while(1)
        {
            char buf[64] = {0};
            fgets(buf,64,stdin);
            buf[strlen(buf)-1] = '\0';
            write(fd[1],buf,strlen(buf));
        }
        exit(0);
    }
    else//父进程
    {
        while(1)
        {
            char buf1[64] = {0};
            memset(buf1,0,64);
            read(fd[0],buf1,64);
            printf("%s\n",buf1);
        }
    }
    wait(NULL);
    exit(0);

    return 0;
} 

运行结果: 

  2)无名管道的读写特性

读特性:

        写端存在:如果管道有数据,返回读到的字节数

                          如果管道无数据,阻塞

        写端不存在:如果管道有数据,返回读到的字节数

                             如果管道无数据,返回0

写特性:

        读端存在:如果管道有空间,返回写入的字节数

                          如果管道无空间,阻塞,直到有空间为止

        读端不存在:

                          无论管道是否有空间,管道破裂(向进程发送管道破裂信号,结束进程)

 

练习:1、计算无名管道空间大小

           2、验证管道破裂

代码示例:

1、

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

int main(int argc, char *argv[])
{
    int fd[2];
    int ret = pipe(fd);
    if(ret < 0)
    {
        perror("pipe");
        exit(-1);
    }
    int size = 0,m = 0;
    while(1)
    {
        char buf[1024] = {0};
        size_t m = write(fd[1],buf,1024);//往管道里写数据,返回字节数
        size = size + m;
        printf("%d\n",size);
    }


    return 0;
} 

2、

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

int main(int argc, char *argv[])
{ 
    int pfd[2] = {0};
    int ret = pipe(pfd);   //创建无名管道
    if(ret < 0)
    {
        perror("pipe");
        exit(-1);
    }

    close(pfd[0]);         //关闭无名管道的读端
    pid_t pid = fork();     //创建子进程

    if(pid == 0)
    {
        write(pfd[1], "hello", 5);
        
        sleep(5);
    }
	else
	{
		int status;
		wait(&status);
		
		printf("%d %d %d\n", WIFEXITED(status),WIFSIGNALED(status),WTERMSIG(status));
		
		exit(0);
	}

    return 0;
} 

运行结果: 

 

 

(2)、有名管道

有名管道创建之后会在文件系统中以管道文件的形式存在

有名管道可以用于任意两个进程之间的通信,没有固定的读端和写端

 (1)有名管道的创建 -- mkfifo

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

       int mkfifo(const char *pathname, mode_t mode);

参数:
    pathname:创建管道文件的文件名
    mode:创建管道文件的权限
返回值:
    成功返回0,失败返回-1

练习:创建一个有名管道,一个进程向管道中输入数据,另一个进程输出数据

1、创建有名管道

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{ 
    int ret = mkfifo("fifo", 0664);
    if(ret < 0)
    {
        perror("mkfifo");
        exit(-1);
    }


    return 0;
} 

 2、创建进程

进程1:

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

int main(int argc, char *argv[])
{ 
    int fd = open("fifo", O_RDONLY);
    if(fd < 0)
    {
        perror("open");
        exit(-1);
    }
    
    printf("open fifo ok!\n");

    char buf[64] = {0};
    while(1)
    {
        memset(buf, 0, 64);
        read(fd, buf, 64);
        printf("%s\n", buf);
    }

    close(fd);
    return 0;
} 

进程2:

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

int main(int argc, char *argv[])
{ 
    int fd = open("fifo", O_WRONLY);
    if(fd < 0)
    {
        perror("open");
        exit(-1);
    }
    
    printf("open fifo ok!\n");

    char buf[64] = {0};
    while(1)
    {
        fgets(buf, 64, stdin);
        buf[strlen(buf)-1] = '\0';

        write(fd, buf, strlen(buf));
    }

    close(fd);
    return 0;
} 

2、信号

信号:是中断在软件层次上的一种模拟

信号的处理方式:

默认处理

忽略

捕获信号

 

(1)常用信号

(2)信号相关指令

kill -l :查看当前系统中的所有信号

kill -信号编号 进程号:向指定进程发送对应编号的信号

例:

kill -9 1234:向进程1234发送信号9

kill -9 -1234:向进程组1234发送信号9

kill -9 -1 :向除了init进程以外的其他所有进程发送信号9

(3)信号相关接口函数 -- kill

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

       int kill(pid_t pid, int sig);

参数:
    pid:指定进程号
    sig:指定信号
返回值:
    成功返回0,失败返回-1;
    
-------------------------------------------------

       #include <signal.h>

       int raise(int sig);

参数:
    sig:指定信号
    
返回值:
    成功返回0,失败返回非零值
    

(4)定时器

定时时间到时,当前进程会接受到编号为14的信号 -- SIGARLM

一个进程中最多只能存在一个定时器

定时器相关函数 -- alarm

       #include <unistd.h>

       unsigned int alarm(unsigned int seconds);

参数:
    seconds:定时秒数
返回值:
    成功返回0或者上个定时器定时剩余的时间
    
-------------------------------------------------
    
       #include <unistd.h>

       int pause(void);
功能:阻塞在当前位置,等待定时结束

(5)捕获信号 -- signal

       #include <signal.h>

       typedef void (*sighandler_t)(int);

       sighandler_t signal(int signum, sighandler_t handler);

参数:
    signum:指定信号
    handler:信号处理函数
			SIG_IGN:选择以忽略方式处理指定信号
            SIG_DFL:选择以默认方式处理指定信号

练习:创建一个子进程,子进程结束时,父进程提示子进程退出信息

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
void func(int num);
int main(int argc, char *argv[])
{ 
    pid_t pid = fork();
    
    if(pid == 0)
    {
        printf("aaaaaaaa\n");
        exit(0);
    }
    else
    {
        signal(17, func);
        while(1)
        {
            printf("bbbbbbbbbbb\n");
            sleep(1);
        }

    }


    return 0;
} 

void func(int num)
{
    printf("child leave!\n");
    raise(9);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值