自学Linux系统软件编程七天
进程间的通信
- 进程间的通信:管道:进程间通信最简单的形式 ;信号:提供一种内核层与用户层之间的通知机制 ;消息队列 ; 共享内存 ;信号灯 ;套接字
- 管道:
1. 无名管道
只能用于具有亲缘关系的进程间通信
2. 有名管道
可以任意两个进程之间通信
3. 有名管道必须读写两端同时加入,才能继续向下执行,否则会阻塞等待
1. 管道特点:
读:
如果管道中有写端,有数据则直接读出,没有数据会阻塞等待直到有数据写入,读出数据才能执行向下执行 ;如果管道中没有写端,有数据则直接读出,没有数据不会阻塞等待,直接返回
写:
如果管道中有读端,管道中数据没有写满数据,则直接写入,如果管道中写满数据,需要等到有数据读出才能继续写入;如果管道中没有读端,向管道中写入数据会产生管道破裂 2. 函数接口:man 2 pipe int pipe(int pipefd[2]); 功能: 创建操作管道的两个文件描述符 参数: pipefd: 存放文件描述符的数组 pipefd[0]:读文件描述符 pipefd[1]:写文件描述符 返回值: 成功返回0 失败返回-1 man 3 mkfifo int mkfifo(const char *pathname, mode_t mode); 功能: 创建管道文件 参数: pathname:管道文件名 mode:权限 返回值: 成功返回0 失败返回-1
- 信号
1. 类型kill -l 1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP 6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1 11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM 16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP 21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ 26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR 31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3 38) SIGRTMIN+4 39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8 43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13 48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-1 53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7 58) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2 63) SIGRTMAX-1 64) SIGRTMAX 2:SIGINT 中断 ctrl + c 3:SIGQUIT 退出 ctrl + \ 11:SIGSEGV 段错误 13:SIGPIPE 管道破裂 14:SIGALRM 定时 17:SIGCHLD 有子进程结束了 18:SIGCONT 让进程暂停 19:SIGSTOP 让进程停止 20:SIGTSTP 让进程挂起 ctrl + z 29:SIGIO 异步IO信号
2. 对信号的处理方式:
1. 忽略:信号来了,不处理该信号
2. 缺省:信号来了,按照默认的方式处理信号
3. 捕捉:信号来了,按照指定的方式处理信号
注意:
9号、19号信号,不能被忽略和捕捉 -
函数接口
man 2 signal typedef void (*sighandler_t)(int); sighandler_t signal(int signum, sighandler_t handler); 功能: 修改信号的处理方式 参数: signum:信号的编号 handler:信号处理的方式 SIG_IGN 忽略 SIG_DFL 缺省 返回值: 成功返回之前信号处理函数 失败返回SIG_ERR man 2 alarm unsigned int alarm(unsigned int seconds); 功能: 定时seconds秒后给当前进程发送SIGALRM信号 参数: seconds:秒数 返回值: 成功返回之前定时剩余的秒数 如果之前没有定时返回0 man 2 kill int kill(pid_t pid, int sig); 功能: 向pid对应的进程发送sig信号 参数: pid:目标进程的PID sig:信号的编号 返回值: 成功返回0 失败返回-1
QUESTION
练习:实现一收一发消息:我的思路是利用 mkfifo
函数创建有名管道,为进程间通信搭建通道。我创建l两个管道,一个用于发送消息,一个用于接收消息。然后使用 open
函数分别以只读、只写的模式打开管道。send.c
程序主要负责先发送消息,然后接收消息;recv.c
程序主要负责先接收消息,然后发送回复消息。
//send.c
#include <stdio.h>
#include "public.h"
int main(int argc, const char **argv)
{
int fatob = 0;
int fbtoa = 0;
char tmpbuff[4096] = {0};
mkfifo("/tmp/ATOB", 0777);
mkfifo("/tmp/BTOA", 0777);
fatob = open("/tmp/ATOB", O_WRONLY);
if (-1 == fatob)
{
ERR_MSG("fail to open");
return -1;
}
fbtoa = open("/tmp/BTOA", O_RDONLY);
if (-1 == fbtoa)
{
ERR_MSG("fail to open");
return -1;
}
printf("管道打开成功!\n");
while (1)
{
gets(tmpbuff);
write(fatob, tmpbuff, strlen(tmpbuff));
memset(tmpbuff, 0, sizeof(tmpbuff));
read(fbtoa, tmpbuff, sizeof(tmpbuff));
printf("RECV:%s\n", tmpbuff);
}
close(fatob);
close(fbtoa);
return 0;
}
//recv.c
#include <stdio.h>
#include "public.h"
int main(int argc, const char **argv)
{
int fatob = 0;
int fbtoa = 0;
char tmpbuff[4096] = {0};
mkfifo("/tmp/ATOB", 0777);
mkfifo("/tmp/BTOA", 0777);
fatob = open("/tmp/ATOB", O_RDONLY);
if (-1 == fatob)
{
ERR_MSG("fail to open");
return -1;
}
fbtoa = open("/tmp/BTOA", O_WRONLY);
if (-1 == fbtoa)
{
ERR_MSG("fail to open");
return -1;
}
printf("管道打开成功!\n");
while (1)
{
memset(tmpbuff, 0, sizeof(tmpbuff));
read(fatob, tmpbuff, sizeof(tmpbuff));
printf("RECV:%s\n", tmpbuff);
gets(tmpbuff);
write(fbtoa, tmpbuff, strlen(tmpbuff));
}
close(fatob);
close(fbtoa);
return 0;
}
写完上述代码后,我发现,当我在其中一端运行过后,想使用ctrl+c退出,但是之后另一端出现了一直在打印RECV,为了解决这个问题,我对代码进行优化处理,利用线程让两个程序能同时运行,并加入了在两端都输入.quit即可退出程序运行的代码,
//send.c
#include <stdio.h>
#include "public.h"
int fatob = 0;
int fbtoa = 0;
void *sendfun(void *arg)
{
char tmpbuff[4096] = {0};
while (1)
{
gets(tmpbuff);
if (0 == strcmp(tmpbuff, ".quit"))
{
break;
}
write(fatob, tmpbuff, strlen(tmpbuff));
}
close(fatob);
return NULL;
}
void *recvfun(void *arg)
{
char tmpbuff[4096] = {0};
ssize_t nret = 0;
while (1)
{
memset(tmpbuff, 0, sizeof(tmpbuff));
nret = read(fbtoa, tmpbuff, sizeof(tmpbuff));
if (0 == nret)
{
break;
}
printf("RECV:%s\n", tmpbuff);
}
return NULL;
}
int main(int argc, const char **argv)
{
pthread_t tid_send;
pthread_t tid_recv;
char tmpbuff[4096] = {0};
mkfifo("/tmp/ATOB", 0777);
mkfifo("/tmp/BTOA", 0777);
fatob = open("/tmp/ATOB", O_WRONLY);
if (-1 == fatob)
{
ERR_MSG("fail to open");
return -1;
}
fbtoa = open("/tmp/BTOA", O_RDONLY);
if (-1 == fbtoa)
{
ERR_MSG("fail to open");
return -1;
}
printf("管道打开成功!\n");
pthread_create(&tid_send, NULL, sendfun, NULL);
pthread_create(&tid_recv, NULL, recvfun, NULL);
pthread_join(tid_send, NULL);
pthread_join(tid_recv, NULL);
#if 0
while (1)
{
gets(tmpbuff);
write(fatob, tmpbuff, strlen(tmpbuff));
memset(tmpbuff, 0, sizeof(tmpbuff));
read(fbtoa, tmpbuff, sizeof(tmpbuff));
printf("RECV:%s\n", tmpbuff);
}
#endif
close(fbtoa);
return 0;
}
//recv.c
#include <stdio.h>
#include "public.h"
int fatob = 0;
int fbtoa = 0;
void *sendfun(void *arg)
{
char tmpbuff[4096] = {0};
while (1)
{
gets(tmpbuff);
if (0 == strcmp(tmpbuff, ".quit"))
{
break;
}
write(fbtoa, tmpbuff, strlen(tmpbuff));
}
close(fbtoa);
return NULL;
}
void *recvfun(void *arg)
{
char tmpbuff[4096] = {0};
ssize_t nret = 0;
while (1)
{
memset(tmpbuff, 0, sizeof(tmpbuff));
nret = read(fatob, tmpbuff, sizeof(tmpbuff));
if (0 == nret)
{
break;
}
printf("RECV:%s\n", tmpbuff);
}
return NULL;
}
int main(int argc, const char **argv)
{
pthread_t tid_send;
pthread_t tid_recv;
char tmpbuff[4096] = {0};
mkfifo("/tmp/ATOB", 0777);
mkfifo("/tmp/BTOA", 0777);
fatob = open("/tmp/ATOB", O_RDONLY);
if (-1 == fatob)
{
ERR_MSG("fail to open");
return -1;
}
fbtoa = open("/tmp/BTOA", O_WRONLY);
if (-1 == fbtoa)
{
ERR_MSG("fail to open");
return -1;
}
printf("管道打开成功!\n");
pthread_create(&tid_send, NULL, sendfun, NULL);
pthread_create(&tid_recv, NULL, recvfun, NULL);
pthread_join(tid_send, NULL);
pthread_join(tid_recv, NULL);
#if 0
while (1)
{
gets(tmpbuff);
write(fatob, tmpbuff, strlen(tmpbuff));
memset(tmpbuff, 0, sizeof(tmpbuff));
read(fbtoa, tmpbuff, sizeof(tmpbuff));
printf("RECV:%s\n", tmpbuff);
}
#endif
close(fatob);
return 0;
}