一、Xmind整理:
管道的原理:
有名管道的特點:?
信號的原理:
二、課上練習:
練習1:pipe
功能:創(chuàng)建一個無名管道,同時打開無名管道的讀寫端
原型:
#include <unistd.h>
int pipe(int pipefd[2]); int* pfd; int pfd[]
參數(shù):
int pipefd[2]:函數(shù)運行完畢后,該參數(shù)指向的數(shù)組中會存儲兩個文件描述符;
pipefd[0]: 讀端文件描述符;
pipefd[1]: 寫端文件描述符;
返回值:
成功,返回0;
失敗,返回-1,更新errno;
小練:?
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <head.h>
int main(int argc, const char *argv[])
{
//管道的創(chuàng)建必須放在fork函數(shù)前
//若放在fork函數(shù)后,會導致父子進程各自創(chuàng)建一根管道
//此時會導致父子進程各自操作各自的管道,無法進行通信
int pfd[2] = {0};
if(pipe(pfd) < 0)
{
perror("pfd");
return -1;
}
printf("pipe success pfd[0]=%d pfd[1]=%d\n",pfd[0],pfd[1]);
pid_t cpid = fork();
if(cpid > 0) //父進程中為真
{
//父進程發(fā)送數(shù)據(jù)給子進程
char buf[128]="";
while(1)
{
fgets(buf,sizeof(buf),stdin);
buf[strlen(buf)-1] = 0; //從終端獲取數(shù)據(jù),最后會拿到\n字符,將\n字符修改成0
//將數(shù)據(jù)寫入到管道文件中
if(write(pfd[1],buf,sizeof(buf)) < 0)
{
perror("write");
return -1;
}
printf("寫入成功\n");
}
}
else if(0 == cpid) //子進程中為真
{
//子進程讀取父進程發(fā)送過來的數(shù)據(jù)
char buf[128] = "";
ssize_t res = 0;
while(1)
{
bzero(buf,sizeof(buf));
printf("__%d__\n",__LINE__);
//當管道中沒有數(shù)據(jù)的時候,read函數(shù)阻塞
res = read(pfd[0],buf,sizeof(buf));
printf("res=%ld : %s\n",res,buf);
}
}
else
{
perror("fork");
return -1;
}
return 0;
}
練習2:mkfifo
功能:創(chuàng)建一根有名管道
原型:
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);
參數(shù):
char *pathname:指定要創(chuàng)建的有名管道的路徑以及名字;
mode_t mode:有名管道的權(quán)限:0664 0777,真實的權(quán)限 (mode & ~umask)
the permissions of the created file are (mode & ~umask)
返回值:
成功,返回0;
失敗,返回-1,更新errno;
errno == 17,文件已經(jīng)存在的錯誤,這是一個允許存在的錯誤,忽略該錯誤
練習3:操作有名管道
功能:操作有名管道與用文件IO操作普通文件一致
原型:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *pathname, int flags);
參數(shù):
int flags:
O_RDONLY 只讀
O_WRONLY 只寫
O_RDWR 讀寫
---上述三種必須,且只能包含一種---
O_NONBLOCK 非阻塞
1.int flags == O_RDONLY
? ? open函數(shù)阻塞,此時需要另外一個進程或線程以寫的方式打開同一根管道,open函數(shù)解除阻塞
2.int flags == O_WRONLY
? ?open函數(shù)阻塞,此時需要另外一個進程或線程以讀的方式打開同一根管道,open函數(shù)解除阻塞
3.int flags == O_RDWR
? ?open函數(shù)不阻塞,此時管道的讀寫端均被打開
? ?當管道的讀寫端均被打開的時候,此時open函數(shù)不阻塞
4.int flags == O_RDONLY | O_NONBLOCK
? ?open函數(shù)不阻塞,open函數(shù)運行成功,此時管道只有讀端
5.int flags == O_WRONLY | O_NONBLOCK
? ?open函數(shù)不阻塞,open函數(shù)運行失敗,此時管道的讀寫端均打開失敗?
示例:?
讀端:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
int main(int argc, const char *argv[])
{
umask(0);
if(mkfifo("./fifo", 0777) < 0)
{
//printf("errno = %d\n", errno);
if(errno != 17) //17 == EEXIST
{
perror("mkfifo");
return -1;
}
}
printf("create FIFO success\n");
//open函數(shù)阻塞
int fd = open("./fifo", O_RDONLY);
if(fd < 0)
{
perror("open");
return -1;
}
printf("open FIFO rdonly success fd=%d\n", fd);
char buf[128] = "";
ssize_t res = 0;
while(1)
{
bzero(buf, sizeof(buf));
res = read(fd, buf, sizeof(buf));
if(res < 0)
{
perror("read");
return -1;
}
else if(0 == res)
{
printf("對端關(guān)閉\n");
break;
}
printf("%ld :%s\n", res, buf);
}
close(fd);
return 0;
}
寫端:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
int main(int argc, const char *argv[])
{
umask(0);
if(mkfifo("./fifo", 0777) < 0)
{
//printf("errno = %d\n", errno);
if(errno != 17) //17 == EEXIST
{
perror("mkfifo");
return -1;
}
}
printf("create FIFO success\n");
//open函數(shù)阻塞
int fd = open("./fifo", O_WRONLY);
if(fd < 0)
{
perror("open");
return -1;
}
printf("open FIFO wronly success fd=%d\n", fd);
char buf[128] = "";
while(1)
{
printf("請輸入>>>");
fgets(buf, sizeof(buf), stdin);
buf[strlen(buf)-1] = 0;
if(write(fd, buf, sizeof(buf)) < 0)
{
perror("write");
return -1;
}
printf("寫入成功\n");
}
close(fd);
return 0;
}
小練:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <head.h>
int main(int argc, const char *argv[])
{
//創(chuàng)建有名管道
if(mkfifo("./fifo",0664) < 0)
{
//printf("%d\n",errno);
if(errno != 17) //17:文件已經(jīng)存在錯誤,這是一個允許存在的錯誤,忽略該錯誤
{
perror("mkfifo");
return -1;
}
}
printf("mkfifo success\n");
/*
int fd = open("./fifo",O_RDWR);
if(fd < 0)
{
perror("open");
return -1;
}
printf("open success fd = %d\n",fd);
*/
int fd_r = open("./fifo",O_RDONLY|O_NONBLOCK);
if(fd_r < 0)
{
perror("open");
return -1;
}
printf("open success fd_r = %d\n",fd_r);
int fd_w = open("./fifo",O_WRONLY|O_NONBLOCK);
if(fd_w < 0)
{
perror("open");
return -1;
}
printf("open success fd_w = %d\n",fd_w);
return 0;
}
練習4:常見的信號
練習5:signal
功能:捕獲信號,為信號注冊新的處理函數(shù)
原型:
#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler); //void (*handler)(int);
參數(shù):
int signum:指定要捕獲的信號對應的編號??梢蕴罹幪枺部梢蕴顚暮?。2) SIGINT
sighandler_t handler:函數(shù)指針,回調(diào)函數(shù);
1) SIG_IGN:忽略信號; 9) 19)號信號無法忽略;
2) SIG_DFL:執(zhí)行默認操作;
3) 傳入一個函數(shù)的首地址,代表捕獲信號,且該函數(shù)的返回值必須是void類型,參數(shù)列表必須是int類型,例如:
void handler(int sig){
}
typedef void (*sighandler_t)(int); typedef void (*)(int) sighandler_t;
typedef 舊的類型名 新的類型名;
typedef int uint32_t; int a ----> uint32_t a;
typedef int* pint; int* pa ---> pint pa;
typedef void (*)(int) sighandler_t; void (*ptr)(int) ----> sighandler_t ptr;
返回值:
成功,返回該信號的上一個信號處理函數(shù)的首地址; 默認處理函數(shù)的首地址獲取不到,返回NULL;
失敗,返回SIG_ERR ((__sighandler_t)-1),更新errno;
注意:當在某個信號A的信號處理函數(shù)中時,再次觸發(fā)信號A,此時信號A的處理函數(shù)不會再次被載入運行,即第二次觸發(fā)的信號A被屏蔽。但是此時若觸發(fā)了信號B,信號B的處理函數(shù)是可以正常被載入的,即沒有屏蔽信號B。
小練:?
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>
#include <head.h>
void handler(int sig)
{
printf("this is sig=%d\n",sig);
return;
}
int main(int argc, const char *argv[])
{
//捕獲2號SIGINT信號
if(signal(2,handler) == SIG_ERR)
{
perror("signal");
return -1;
}
printf("捕獲2號信號成功\n");
//捕獲3號SIGINT信號
if(signal(3,handler) == SIG_ERR)
{
perror("signal");
return -1;
}
printf("捕獲3號信號成功\n");
//捕獲20號SIGINT信號
if(signal(20,handler) == SIG_ERR)
{
perror("signal");
return -1;
}
printf("捕獲20號信號成功\n");
while(1)
{
printf("this is main func\n");
sleep(1);
}
return 0;
}
三、課后作業(yè):
1.要求實現(xiàn)AB進程對話
? ?A進程先發(fā)送一句話給B進程,B進程接收后打印
? ?B進程再回復一句話給A進程,A進程接收后打印
? ?重復1.2步驟,當收到quit后,要結(jié)束AB進程
? ?提示:兩根管道
A進程:?
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <head.h>
int main(int argc, const char *argv[])
{
//創(chuàng)建有名管道
if(mkfifo("./fifo",0664) < 0)
{
//printf("%d\n",errno);
if(errno != 17) //17:文件已經(jīng)存在錯誤,這是一個允許存在的錯誤,忽略該錯誤
{
perror("mkfifo");
return -1;
}
}
printf("mkfifo success\n");
if(mkfifo("./fifo1",0664) < 0)
{
//printf("%d\n",errno);
if(errno != 17) //17:文件已經(jīng)存在錯誤,這是一個允許存在的錯誤,忽略該錯誤
{
perror("mkfifo");
return -1;
}
}
printf("mkfifo1 success\n");
int fd_r= open("./fifo",O_RDONLY);
if(fd_r < 0)
{
perror("open");
return -1;
}
printf("open success fd_r = %d\n",fd_r);
int fd_w = open("./fifo1",O_WRONLY);
if(fd_w < 0)
{
perror("open");
return -1;
}
printf("open success fd_w= %d\n",fd_w);
//從管道中讀取數(shù)據(jù),打印到終端上
char buf[128]="";
ssize_t res = 0;
while(1)
{
bzero(buf,sizeof(buf));
//當管道的讀寫端均存在,若管道中沒有數(shù)據(jù),則read函數(shù)阻塞
res = read(fd_r,buf,sizeof(buf));
if(strcmp(buf,"quit") == 0)
{
write(fd_w,buf,sizeof(buf));
break;
}
if(res < 0)
{
perror("read");
return -1;
}
if(0 == res)
{
printf("寫端關(guān)閉\n");
break;
}
printf("res =%ld\n輸出:%s\n",res,buf);
bzero(buf, sizeof(buf));
printf("請輸入:");
fgets(buf, sizeof(buf),stdin);
buf[strlen(buf)-1] = '\0';
if(write(fd_w,buf,sizeof(buf))< 0)
{
perror("write");
return -1;
}
printf("寫入數(shù)據(jù)成功 res =%ld\n",res);
}
close(fd_r);
close(fd_w);
return 0;
}
B進程:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <head.h>
int main(int argc, const char *argv[])
{
//創(chuàng)建有名管道
if(mkfifo("./fifo",0664) < 0)
{
//printf("%d\n",errno);
if(errno != 17) //17:文件已經(jīng)存在錯誤,這是一個允許存在的錯誤,忽略該錯誤
{
perror("mkfifo");
return -1;
}
}
printf("mkfifo success\n");
if(mkfifo("./fifo1",0664) < 0)
{
//printf("%d\n",errno);
if(errno != 17) //17:文件已經(jīng)存在錯誤,這是一個允許存在的錯誤,忽略該錯誤
{
perror("mkfifo");
return -1;
}
}
printf("mkfifo1 success\n");
int fd_w = open("./fifo",O_WRONLY);
if(fd_w < 0)
{
perror("open");
return -1;
}
printf("open success fd_w= %d\n",fd_w);
int fd_r= open("./fifo1",O_RDONLY);
if(fd_r < 0)
{
perror("open");
return -1;
}
printf("open success fd_r = %d\n",fd_r);
//從終端獲取數(shù)據(jù),寫到管道中
char buf[128]="";
ssize_t res = 0;
while(1)
{
bzero(buf, sizeof(buf));
printf("請輸入:");
fgets(buf,sizeof(buf),stdin);
buf[strlen(buf)-1] = '\0';
if(strcmp(buf,"quit") == 0)
{
write(fd_w,buf,sizeof(buf));
break;
}
if(write(fd_w,buf,sizeof(buf)) < 0)
{
perror("write");
return -1;
}
printf("寫入數(shù)據(jù)成功 res =%ld\n",res);
bzero(buf,sizeof(buf));
//當管道的讀寫端均存在,若管道中沒有數(shù)據(jù),則read函數(shù)阻塞
res = read(fd_r,buf,sizeof(buf));
if(res < 0)
{
perror("read");
return -1;
}
if(0 == res)
{
printf("寫端關(guān)閉\n");
break;
}
printf("res =%ld\n輸出:%s\n",res,buf);
}
close(fd_w);
close(fd_r);
return 0;
}
文章來源:http://www.zghlxwxcb.cn/news/detail-629907.html
2.在第1題的基礎(chǔ)上實現(xiàn),A能隨時發(fā)信息給B,B能隨時接收A發(fā)送的數(shù)據(jù),反之亦然。
A進程:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <sys/wait.h>
#include <signal.h>
int main(int argc, const char *argv[])
{
if(mkfifo("./fifo", 0775) < 0) //當前進程寫該管道
{
if(17 != errno) //#define EEXIST 17
{
perror("mkfifo");
return -1;
}
}
printf("fifo create success\n");
if(mkfifo("./fifo1", 0775) < 0) //當前進程讀該管道
{
if(17 != errno) //#define EEXIST 17
{
perror("mkfifo");
return -1;
}
}
printf("fifo1 create success\n");
//創(chuàng)建一個子進程
pid_t cpid = fork();
if(cpid > 0)
{
//讀 fifo1
int fd_r = open("./fifo1", O_RDONLY); //阻塞
if(fd_r < 0)
{
perror("open");
return -1;
}
printf("open fifo rdonly success __%d__\n", __LINE__);
ssize_t res = 0;
char buf[128] = "";
while(1)
{
bzero(buf, sizeof(buf));
//讀寫段均存在,且管道中沒有數(shù)據(jù),該函數(shù)阻塞
res = read(fd_r, buf, sizeof(buf));
if(res < 0)
{
perror("read");
return -1;
}
else if(0 == res)
{
printf("對端進程退出\n");
break;
}
printf("res=%ld : buf=%s\n", res, buf);
if(!strcmp(buf, "quit"))
break;
}
close(fd_r);
kill(cpid, 9);
wait(NULL);
}
else if(0 == cpid)
{
//寫 fifo
int fd_w = open("./fifo", O_WRONLY); //阻塞
if(fd_w < 0)
{
perror("open");
return -1;
}
printf("open fifo wronly success __%d__\n", __LINE__);
char buf[128] = "";
while(1)
{
bzero(buf, sizeof(buf));
// printf("請輸入>>>");
fgets(buf, sizeof(buf), stdin);
buf[strlen(buf)-1] = 0;
if(write(fd_w, buf, sizeof(buf)) < 0)
{
perror("write");
return -1;
}
// printf("寫入成功\n");
if(!strcmp(buf, "quit"))
break;
}
close(fd_w);
kill(getppid() , 9);
}
else
{
perror("fork");
return -1;
}
return 0;
}
B進程:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <sys/wait.h>
#include <signal.h>
int main(int argc, const char *argv[])
{
if(mkfifo("./fifo", 0775) < 0) //當前進程寫該管道
{
if(17 != errno) //#define EEXIST 17
{
perror("mkfifo");
return -1;
}
}
printf("fifo create success\n");
if(mkfifo("./fifo1", 0775) < 0) //當前進程讀該管道
{
if(17 != errno) //#define EEXIST 17
{
perror("mkfifo");
return -1;
}
}
printf("fifo1 create success\n");
//創(chuàng)建一個子進程
pid_t cpid = fork();
if(cpid > 0)
{
//讀 fifo
int fd_r = open("./fifo", O_RDONLY); //阻塞
if(fd_r < 0)
{
perror("open");
return -1;
}
printf("open fifo rdonly success __%d__\n", __LINE__);
ssize_t res = 0;
char buf[128] = "";
while(1)
{
bzero(buf, sizeof(buf));
//讀寫段均存在,且管道中沒有數(shù)據(jù),該函數(shù)阻塞
res = read(fd_r, buf, sizeof(buf));
if(res < 0)
{
perror("read");
return -1;
}
else if(0 == res)
{
printf("對端進程退出\n");
break;
}
printf("res=%ld : buf=%s\n", res, buf);
if(!strcmp(buf, "quit"))
break;
}
close(fd_r);
kill(cpid, 9);
wait(NULL);
}
else if(0 == cpid)
{
//寫 fifo1
int fd_w = open("./fifo1", O_WRONLY); //阻塞
if(fd_w < 0)
{
perror("open");
return -1;
}
printf("open fifo wronly success __%d__\n", __LINE__);
char buf[128] = "";
while(1)
{
bzero(buf, sizeof(buf));
//printf("請輸入>>>");
fgets(buf, sizeof(buf), stdin);
buf[strlen(buf)-1] = 0;
if(write(fd_w, buf, sizeof(buf)) < 0)
{
perror("write");
return -1;
}
// printf("寫入成功\n");
if(!strcmp(buf, "quit"))
break;
}
close(fd_w);
kill(getppid() , 9);
}
else
{
perror("fork");
return -1;
}
return 0;
}
文章來源地址http://www.zghlxwxcb.cn/news/detail-629907.html
到了這里,關(guān)于IO進程線程day8(2023.8.6)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!