Home Article Practice 05_管道

05_管道

2024-04-25 14:22  views:222  source:拼搏百天我要上蓝翔    

知识点1【文件描述符复制】让新的文件描述符 指向 旧的文件描述符。(新旧文件描述符指向同一个文件)使用的函数d
up、dup21、dup函数(复制文件描述符)1 #include <unistd。h>2 int dup(i
nt oldfd);dup函数的功能:从系统中寻找最小可用的文件描述符 作为oldfd的副本。新文件描述符 通
过dup的返回值返回。案例1:dup的基本案例2、dup2函数(复制文件描述符)1 #include <uni
std。h>2 int dup2(int oldfd, int newfd);dup2的功能:将newfd作为
oldfd的副本。如果newfd事先存在 dup2会先close(newfd),然后将newfd作为oldfd
的副本。知识点2【无名管道】1、无名管道的概述管道(pipe)又称无名管道。 无名管道是一种特殊类型的文件,在
应用层体现为两个打开的文件描述符。管道的特点:1、半双工,数据在同一时刻只能在一个方向上流动。2、数据只能从管
道的一端写入,从另一端读出。3、写入管道中的数据遵循先入先出的规则。4、管道所传送的数据是无格式的,这要求管道
的读出方与写入方必须事先约定好数据的格式, 如多少字节算一个消息等。5、管道不是普通的文件,不属于某个文件系统
,其只存在于内存中。6、管道在内存中对应一个缓冲区。不同的系统其大小不一定相同。7、从管道读数据是一次性操作,
数据一旦被读走,它就从管道中被抛弃,释放空间以便写更多的数据。8、管道没有名字,只能在具有血缘关系的进程之间使
用2、无名管道的创建1 #include <unistd。h>2 int pipe(int filedes[2
]);功能:经由参数filedes返回两个文件描述符参数:filedes为int型数组的首地址,其存放了管道的
文件描述符fd[0]、fd[1]。filedes[0]为读而打开,filedes[1]为写而打开管道,file
des[0]的输出是filedes[1]的输入。返回值:成功:返回 0失败:返回-1注意:在使用无名管道的时候
必须事先确定,谁发,谁收的问题。案例1:父进程发 子进程收1 #include <stdio。h>2 #in
clude <unistd。h>3 #include <string。h>4 #include <sys/wa
it。h>5 int main(int argc, char const *argv[])6 {7 //创建一
个无名管道8 int fd[2];9 pipe(fd);1011 //创建一个子进程12 //父进程发 子进程
收13 pid_t pid = fork();14 if (pid == 0) //子进程15 {16 //子
进程的写端无意义(可以事先关闭)17 close(fd[1]);1819 //子进程接收父进程消息20 pri
ntf("子进程%d正在等待父进程的消息\n", getpid());21 unsigned char buf
[128] = "";22 read(fd[0], buf, sizeof(buf));23 printf("
子进程%d读到的消息为:%s\n", getpid(), buf);2425 //子进程读完数据 应该关闭读端
26 close(fd[0]);2728 //显示退出29 _exit(‐1);30 }31 else if
(pid > 0) //父进程32 {33 //父进程的读端无意义(可以事先关闭)34 close(fd[0]
);3536 //写端写入数据37 printf("父进程:%d将3秒后写入数据hello pipe\n",
getpid());38 sleep(3);39 write(fd[1], "hello pipe", str
len("hello pipe"));40 printf("父进程:%d完成写入\n", getpid());
4142 //通信完成 应该关闭写端43 close(fd[1]);4445 //等待子进程退出46 wait
(NULL);47 }48 return 0;49 }503、无名管道读写的特点1、默认用read函数从管道中
读数据是阻塞的。2、调用write函数向管道里写数据,当缓冲区已满时write也会阻塞。3、通信过程中,读端口
全部关闭后,写进程向管道内写数据时,写进程会(收到SIGPIPE信号)退出。案例1:调用write函数向管道里
写数据,当缓冲区已满时write也会阻塞1 #include <stdio。h>2 #include <uni
std。h>3 #include <string。h>4 #include <sys/wait。h>5 int
main(int argc, char const *argv[])6 {7 //创建一个无名管道8 int
fd[2];9 pipe(fd);1011 //创建一个子进程12 //父进程发 子进程收13 pid_t
pid = fork();14 if (pid == 0) //子进程15 {16 getchar();171
8 //显示退出19 _exit(‐1);20 }21 else if (pid > 0) //父进程22 {
23 int i = 0;24 for (i = 0; i < 1000; i++)25 {26 char b
uf[128] = "";27 write(fd[1], buf, 128);28 printf("i=%d\
n", i + 1);29 }3031 //等待子进程退出32 wait(NULL);33 }34 retur
n 0;35 }案例2:通信过程中,读端口全部关闭后,写进程向管道内写数据时,写进程会(收到SIGPIPE信号
)退出1 #include <stdio。h>2 #include <unistd。h>3 #include
<string。h>4 #include <sys/wait。h>5 int main(int argc, c
har const *argv[])6 {7 //创建一个无名管道8 int fd[2];9 pipe(fd)
;1011 //创建一个子进程12 //父进程发 子进程收13 pid_t pid = fork();14 i
f (pid == 0) //子进程15 {16 //子进程的写端无意义(可以事先关闭)17 close(fd
[1]);1819 int i = 0;20 while (1)21 {22 //子进程接收父进程消息23 p
rintf("子进程%d正在等待父进程的消息\n", getpid());24 unsigned char b
uf[128] = "";25 read(fd[0], buf, sizeof(buf));26 printf
("子进程%d读到的消息为:%s\n", getpid(), buf);27 if (++i == 3)28
break;29 }3031 //子进程读完数据 应该关闭读端32 close(fd[0]);3334 //显
示退出35 _exit(‐1);36 }37 else if (pid > 0) //父进程38 {39 //
父进程的读端无意义(可以事先关闭)40 close(fd[0]);4142 while (1)43 {44 /
/写端写入数据45 printf("父进程:%d将1秒后写入数据hello pipe\n", getpid()
);46 sleep(1);47 write(fd[1], "hello pipe", strlen("hel
lo pipe"));48 printf("父进程:%d完成写入\n", getpid());49 }5051
//通信完成 应该关闭写端52 close(fd[1]);5354 //等待子进程退出55 wait(NUL
L);56 }57 return 0;58 }594、无名管道综合案例1 #include <stdio。h>
2 #include <unistd。h>3 #include <string。h>4 #include <s
ys/wait。h>5 int main(int argc, char const *argv[])6 {7
//创建无名管道8 int fd[2];9 pipe(fd);1011 //创建两个子进程12 int i =
0;13 for (i = 0; i < 2; i++)14 {15 pid_t pid = fork();
16 if (pid == 0)17 break;18 }1920 if (i == 0) //子进程121
{22 //ps ‐A 写端23 //读端无意义 可以事先关闭24 close(fd[0]);25 //1要作
为fd[1]的副本26 dup2(fd[1], 1);27 //执行ps ‐A28 execlp("ps",
"ps", "‐A", NULL);29 _exit(‐1);30 }31 else if (i == 1)
//子进程232 {33 //grep bash 读端34 //写端无意义 可以事先关闭35 close(fd
[1]);36 //0作为fd[0]的副本37 dup2(fd[0], 0);38 //执行grep bash
39 execlp("grep", "grep", "bash", NULL);40 _exit(‐1);41
}42 else if (i == 2) //父进程43 {44 //关闭管道读写端45 close(fd[
0]);46 close(fd[1]);47 while (1)48 {49 pid_t pid = wait
pid(‐1, NULL, WNOHANG);50 if (pid > 0)51 {52 printf("子进
程%d退出了\n", pid);53 }54 else if (pid == 0)55 {56 continu
e;57 }58 else if (pid < 0)59 {60 break;61 }62 }63 }6465
return 0;66 }知识点3【有名管道、命名管道】(重要)主要用于没有血缘关系的进程间通信。1、有名管
道的概述FIFO其特点是:1、半双工,数据在同一时刻只能在一个方向上流动。2、写入FIFO中的数据遵循先入先出
的规则。3、FIFO所传送的数据是无格式的,这要求FIFO的读出方与写入方必须事先约定好数据的格式,如多少字节
算一个消息等。4、FIFO在文件系统中作为一个特殊的文件而存在,但FIFO中的内容却存放在内存中。5、管道在内
存中对应一个缓冲区。不同的系统其大小不一定相同。6、从FIFO读数据是一次性操作,数据一旦被读,它就从FIFO
中被抛弃,释放空间以便写更多的数据。7、当使用FIFO的进程退出后,FIFO文件将继续保存在文件系统中以便以后
使用。 8、FIFO有名字,不相关的进程可以通过打开命名管道进行通信(重要、重要、重要)2、有名管道的API1
、创建有名管道FIFO文件的创建1 #include <sys/types。h>2 #include <sys
/stat。h>3 int mkfifo( const char *pathname, mode_t mode
);参数:pathname:FIFO的路径名+文件名。mode:mode_t类型的权限描述符。返回值:成功:返
回 0失败:如果文件已经存在,则会出错且返回-1read。c1 #include <stdio。h>2 #in
clude <sys/types。h>3 #include <sys/stat。h>4 #include <s
tring。h>5 #include <fcntl。h>6 #include <unistd。h>7 int
main(int argc, char const *argv[])8 {9 //创建有名管道(保存两个进程
识别相同目录)10 mkfifo("my_fifo", 0666);1112 //open以读的方式的打开 有
名管道(阻塞 到 对方 以写的方式打开)13 int fd = open("my_fifo", O_RDONL
Y);14 if (fd < 0)15 {16 perror("open");17 return 0;18 }
19 printf("写端open成功了\n");2021 //循环的读取数据22 while (1)23 {
24 //接收数据25 char buf[128] = "";26 read(fd, buf, sizeof(
buf));27 printf("收到数据位:%s\n", buf);2829 //退出循环30 if (st
rcmp(buf, "bye") == 0)31 break;32 }3334 close(fd);35 re
turn 0;36 }37write。c1 #include <stdio。h>2 #include <sys
/types。h>3 #include <sys/stat。h>4 #include <fcntl。h>5 #
include <string。h>6 #include <unistd。h>7 int main(int a
rgc, char const *argv[])8 {9 //创建有名管道(保存两个进程 识别相同目录)10
mkfifo("my_fifo", 0666);1112 //open以写的方式的打开 有名管道(阻塞 到 对
方 以读的方式打开)13 int fd = open("my_fifo", O_WRONLY);14 if (
fd < 0)15 {16 perror("open");17 return 0;18 }19 printf(
"写端open成功了\n");2021 //循环写入数据22 while (1)23 {24 //获取键盘输入
25 char buf[128] = "";26 printf("请输入需要发送的数据:");27 fgets
(buf, sizeof(buf), stdin);28 buf[strlen(buf) ‐ 1] = 0;2
930 //发送数据31 write(fd, buf, strlen(buf));3233 //退出循环34
if (strcmp(buf, "bye") == 0)35 break;36 }3738 close(fd)
;39 return 0;40 }案例1:将收发合并成有一个代码1 #include <stdio。h>2 #
include <sys/types。h>3 #include <sys/stat。h>4 #include
<fcntl。h>5 #include <string。h>6 #include <unistd。h>7 in
t main(int argc, char const *argv[])8 {9 //创建有名管道(保存两个进
程 识别相同目录)10 mkfifo("my_fifo", 0666);1112 #ifdef WRITE13
int fd = open("my_fifo", O_WRONLY);14 #endif15 #ifdef
READ16 int fd = open("my_fifo", O_RDONLY);17 #endif18 i
f (fd < 0)19 {20 perror("open");21 return 0;22 }23 prin
tf("写端open成功了\n");2425 #ifdef WRITE26 //循环写入数据27 while
(1)28 {29 //获取键盘输入30 char buf[128] = "";31 printf("请输入需
要发送的数据:");32 fgets(buf, sizeof(buf), stdin);33 buf[strl
en(buf) ‐ 1] = 0;3435 //发送数据36 write(fd, buf, strlen(bu
f));3738 //退出循环39 if (strcmp(buf, "bye") == 0)40 break;
41 }42 #endif4344 #ifdef READ45 //循环的读取数据46 while (1)47
{48 //接收数据49 char buf[128] = "";50 read(fd, buf, sizeo
f(buf));51 printf("收到数据位:%s\n", buf);5253 //退出循环54 if (
strcmp(buf, "bye") == 0)55 break;56 }57 #endif58 close(
fd);59 return 0;60 }3、有名管道读写的特点阻塞方式打开管道:1、open以只读方式打开FI
FO时,要阻塞到某个进程为写而打开此FIFO2、open以只写方式打开FIFO时,要阻塞到某个进程为读而打开此
FIFO。3、open以只读、只写方式打开FIFO时会阻塞,调用read函数从FIFO里读数据时read也会阻
塞。4、通信过程中若写进程先退出了,则调用read函数从FIFO里读数据时不阻塞;若写进程又重新运行,则调用r
ead函数从FIFO里读数据时又恢复阻塞。5、通信过程中,读进程退出后,写进程向命名管道内写数据时,写进程也会
(收到SIGPIPE信号)退出。6、调用write函数向FIFO里写数据,当缓冲区已满时write也会阻塞。以
非阻塞方式打开管道:1、先以只读方式打开:如果没有进程已经为写而打开一个FIFO, 只读open成功,并且op
en不阻塞。 2、先以只写方式打开:如果没有进程已经为读而打开一个FIFO,只写open将出错返回-1。3、r
ead、write读写命名管道中读数据时不阻塞。4、通信过程中,读进程退出后,写进程向命名管道内写数据时,写进
程也会(收到SIGPIPE信号)退出。注意: open函数以可读可写方式打开FIFO文件时的特点:1、open
不阻塞。2、调用read函数从FIFO里读数据时read会阻塞。3、调用write函数向FIFO里写数据,当缓
冲区已满时write也会阻塞4、单机QQ聊天程序题目:实现单机QQ聊天 提示: 父进程创建子进程,实现多任务。
父进程负责发信息(向FIFO里写数据),子进程负责接收信息( 从FIFO里读数据)。 打开命名管道的用阻塞的
方法打开。07_bob。c1 #include <stdio。h>2 #include <sys/types。
h>3 #include <sys/stat。h>4 #include <fcntl。h>5 #include
<string。h>6 #include <unistd。h>7 #include <sys/wait。h>
8 int main(int argc, char const *argv[])9 {10 //创建两个有名管
道11 mkfifo("bob_to_lucy", 0666);12 mkfifo("lucy_to_bob"
, 0666);1314 int i = 0;15 for (; i < 2; i++)16 {17 pid_
t pid = fork();18 if (pid == 0)19 break;20 }2122 if (i
== 0) //子进程1 负责fa消息 (bob 发给 lucy)23 {24 int fd = open("
bob_to_lucy", O_WRONLY);25 if (fd < 0)26 {27 perror("op
en");28 _exit(‐1);29 }3031 //获取键盘输入32 while (1)33 {34 /
/获取键盘输入35 char buf[128] = "";36 printf("\rbob:");37 fge
ts(buf, sizeof(buf), stdin);38 buf[strlen(buf) ‐ 1] = 0
;3940 //发送数据41 write(fd, buf, strlen(buf));4243 //退出循环4
4 if (strcmp(buf, "bye") == 0)45 break;46 }4748 //退出进程4
9 close(fd);50 _exit(‐1);51 }52 else if (i == 1) //子进程2
负责shou消息 (lucy 发给 bob)53 {54 int fd = open("lucy_to_bo
b", O_RDONLY);55 if (fd < 0)56 {57 perror("open");58 _e
xit(‐1);59 }60 //循环的读取数据61 while (1)62 {63 //接收数据64 cha
r buf[128] = "";65 read(fd, buf, sizeof(buf));66 printf
("\rlucy:%s\n\rbob:", buf);6768 //退出循环69 if (strcmp(buf
, "bye") == 0)70 break;71 }72 close(fd);73 _exit(‐1);74
}75 else if (i == 2) //父进程 负责 回收资源76 {77 while (1)78 {
79 pid_t pid = waitpid(‐1, NULL, WNOHANG);80 if (pid >
0)81 {82 printf("子进程%d退出了\n", pid);83 }84 else if (pid
== 0)85 {86 continue;87 }88 else if (pid < 0)89 {90 bre
ak;91 }92 }93 }94 return 0;95 }9607_lucy。c1 #include <s
tdio。h>2 #include <sys/types。h>3 #include <sys/stat。h>4
#include <fcntl。h>5 #include <string。h>6 #include <uni
std。h>7 #include <sys/wait。h>8 int main(int argc, char
const *argv[])9 {10 //创建两个有名管道11 mkfifo("bob_to_lucy",
0666);12 mkfifo("lucy_to_bob", 0666);1314 int i = 0;15
for (; i < 2; i++)16 {17 pid_t pid = fork();18 if (pid
== 0)19 break;20 }2122 if (i == 0) //子进程1 负责fa消息 (lucy
发给 bob)23 {24 int fd = open("lucy_to_bob", O_WRONLY);25
if (fd < 0)26 {27 perror("open");28 _exit(‐1);29 }3031
//获取键盘输入32 while (1)33 {34 //获取键盘输入35 char buf[128] =
"";36 printf("\rlucy:");37 fgets(buf, sizeof(buf), stdi
n);38 buf[strlen(buf) ‐ 1] = 0;3940 //发送数据41 write(fd,
buf, strlen(buf));4243 //退出循环44 if (strcmp(buf, "bye")
== 0)45 break;46 }4748 //退出进程49 close(fd);50 _exit(‐1);
51 }52 else if (i == 1) //子进程2 负责shou消息 (bob 发给 lucy)53
{54 int fd = open("bob_to_lucy", O_RDONLY);55 if (fd <
0)56 {57 perror("open");58 _exit(‐1);59 }60 //循环的读取数据6
1 while (1)62 {63 //接收数据64 char buf[128] = "";65 read(f
d, buf, sizeof(buf));66 printf("\rbob:%s\n\rlucy:", buf
);6768 //退出循环69 if (strcmp(buf, "bye") == 0)70 break;71
}72 close(fd);73 _exit(‐1);74 }75 else if (i == 2) //父
进程 负责 回收资源76 {77 while (1)78 {79 pid_t pid = waitpid(‐1
, NULL, WNOHANG);80 if (pid > 0)81 {82 printf("子进程%d退出了
\n", pid);83 }84 else if (pid == 0)85 {86 continue;87 }
88 else if (pid < 0)89 {90 break;91 }92 }93 }94 return
0;95 }合并一个:1 #include <stdio。h>2 #include <sys/types。h>
3 #include <sys/stat。h>4 #include <fcntl。h>5 #include <
string。h>6 #include <unistd。h>7 #include <sys/wait。h>8
int main(int argc, char const *argv[])9 {10 //创建两个有名管道1
1 mkfifo("bob_to_lucy", 0666);12 mkfifo("lucy_to_bob",
0666);1314 int i = 0;15 for (; i < 2; i++)16 {17 pid_t
pid = fork();18 if (pid == 0)19 break;20 }2122 if (i ==
0) //子进程1 负责fa消息23 {24 #ifdef BOB25 int fd = open("bob
_to_lucy", O_WRONLY);26 #endif // DEBUG27 #ifdef LUCY28
int fd = open("lucy_to_bob", O_WRONLY);29 #endif // DE
BUG30 if (fd < 0)31 {32 perror("open");33 _exit(‐1);34
}3536 //获取键盘输入37 while (1)38 {39 //获取键盘输入40 char buf[12
8] = "";41 #ifdef BOB42 printf("\rbob:");43 #endif // D
EBUG44 #ifdef LUCY45 printf("\rlucy:");46 #endif // DEB
UG47 fflush(stdout);48 fgets(buf, sizeof(buf), stdin);4
9 buf[strlen(buf) ‐ 1] = 0;5051 //发送数据52 write(fd, buf,
strlen(buf));5354 //退出循环55 if (strcmp(buf, "bye") == 0
)56 break;57 }5859 //退出进程60 close(fd);61 _exit(‐1);62 }
63 else if (i == 1) //子进程2 负责shou消息64 {65 #ifdef BOB66
int fd = open("lucy_to_bob", O_RDONLY);67 #endif // DEB
UG68 #ifdef LUCY69 int fd = open("bob_to_lucy", O_RDONL
Y);70 #endif // DEBUG71 if (fd < 0)72 {73 perror("open"
);74 _exit(‐1);75 }76 //循环的读取数据77 while (1)78 {79 //接收数
据80 char buf[128] = "";81 read(fd, buf, sizeof(buf));82
#ifdef BOB83 printf("\rlucy:%s\n\rbob:", buf);84 #endi
f // DEBUG85 #ifdef LUCY86 printf("\rbob:%s\n\rlucy:",
buf);87 #endif // DEBUG88 fflush(stdout);89 //退出循环90 if
(strcmp(buf, "bye") == 0)91 break;92 }93 close(fd);94
_exit(‐1);95 }96 else if (i == 2) //父进程 负责 回收资源97 {98 w
hile (1)99 {100 pid_t pid = waitpid(‐1, NULL, WNOHANG);
101 if (pid > 0)102 {103 printf("子进程%d退出了\n", pid);104
}105 else if (pid == 0)106 {107 continue;108 }109 else
if (pid < 0)110 {111 break;112 }113 }114 }115116 return
0;117 }



Disclaimer: The above articles are added by users themselves and are only for typing and communication purposes. They do not represent the views of this website, and this website does not assume any legal responsibility. This statement is hereby made! If there is any infringement of your rights, please contact us promptly to delete it.

字符:    改为:
去打字就可以设置个性皮肤啦!(O ^ ~ ^ O)