Skip to content

Commit 32b555e

Browse files
committedDec 21, 2024
fgets
1 parent 3a70677 commit 32b555e

File tree

3 files changed

+178
-0
lines changed

3 files changed

+178
-0
lines changed
 

‎c/fgets/Makefile

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
.PHONY: udpSendTest
2+
3+
CCFLAGS := -g3 -O0 -W -Wall -std=gnu11 -pipe -Wno-int-to-pointer-cast -Wno-pointer-to-int-cast -Wno-unused-variable -Wno-unused-but-set-variable -Wno-unused-parameter
4+
LDFLAGS := -lpthread
5+
6+
udpSend: main.c
7+
@echo "test udp send program ..."
8+
gcc $(CCFLAGS) $^ $(LDFLAGS)

‎c/fgets/main.c

+152
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
#include <stdlib.h>
2+
#include <stdio.h>
3+
#include <string.h>
4+
#include <pthread.h>
5+
#include <signal.h>
6+
#include <unistd.h>
7+
#include <errno.h>
8+
#include <sys/types.h>
9+
#include <sys/wait.h>
10+
#include <sys/socket.h>
11+
#include <sys/time.h>
12+
#include <sys/prctl.h>
13+
#include <sys/epoll.h>
14+
#include <netinet/icmp6.h> // struct nd_neighbor_solicit/advert, which contains icmp6_hdr and ND_NEIGHBOR_ADVERT
15+
#include <netinet/in.h> // IPPROTO_IPV6, IPPROTO_ICMPV6, INET6_ADDRSTRLEN
16+
#include <netinet/ip.h> // IP_MAXPACKET (65535)
17+
#include <arpa/inet.h> // inet_pton() and inet_ntop()
18+
#include <poll.h>
19+
#include <fcntl.h>
20+
21+
22+
23+
24+
const char* cnGetSysErrnoDesc()
25+
{
26+
static __thread char s_acErrorDesc[512];
27+
s_acErrorDesc[0] = '\0';
28+
strerror_r(errno,s_acErrorDesc,sizeof(s_acErrorDesc));
29+
return s_acErrorDesc;
30+
}
31+
32+
33+
int main(int argc, char* argv[])
34+
{
35+
int nonblockingFlag = 0;
36+
37+
if(argc > 1)
38+
{
39+
nonblockingFlag = 1;
40+
}
41+
42+
int pipefds[2];
43+
int rc;
44+
rc = pipe(pipefds);
45+
if(rc < 0)
46+
{
47+
perror("Create pipe in failure");
48+
return -1;
49+
}
50+
51+
pid_t child = fork();
52+
53+
if(child == 0)
54+
{
55+
printf("Child process must exit when parent process exited\n");
56+
prctl(PR_SET_PDEATHSIG, SIGTERM);
57+
58+
printf("Child process set self to be the leader of process group\n");
59+
setpgid(0, 0);
60+
int blackhole = open("/dev/null", O_RDWR | O_CLOEXEC);
61+
if(blackhole < 0)
62+
{
63+
return -1;
64+
}
65+
66+
dup2(blackhole, STDIN_FILENO);
67+
68+
printf("Redirect the standard out and standard err\n");
69+
dup2(pipefds[1], STDOUT_FILENO);
70+
dup2(pipefds[1], STDERR_FILENO);
71+
72+
printf("Sleep a while to watch the blocking status of fgets API\n");
73+
sleep(10);
74+
75+
printf("fflush the output streams if any\n");
76+
77+
fflush(stdout);
78+
fflush(stderr);
79+
80+
/*immediately exit*/
81+
_exit(0);
82+
}
83+
84+
printf("Parent process continues to run ...\n");
85+
close(pipefds[1]);
86+
87+
if(nonblockingFlag)
88+
{
89+
printf("Set nonblocking flag\n");
90+
int oldFlags = fcntl(pipefds[0], F_GETFL);
91+
fcntl(pipefds[0], F_SETFL, oldFlags | O_NONBLOCK);
92+
}
93+
else
94+
{
95+
printf("Using blocked fd APIs\n");
96+
}
97+
98+
FILE* fp = fdopen(pipefds[0], "r");
99+
100+
if(fp == NULL)
101+
{
102+
perror("fdopen pipe fd in failure");
103+
return -1;
104+
}
105+
106+
int status;
107+
pid_t chckpid;
108+
char szLineBuf[512];
109+
char* szLine;
110+
111+
do
112+
{
113+
szLine = fgets(szLineBuf, sizeof(szLineBuf), fp);
114+
if(szLine == NULL)
115+
{
116+
continue;
117+
}
118+
119+
printf("Child process output: %s\n", szLine);
120+
status = 0;
121+
chckpid = waitpid(child, &status, WNOHANG | WEXITED);
122+
}while(chckpid == 0 /*running*/);
123+
124+
printf("Detect child process has exited ...\n");
125+
126+
do
127+
{
128+
szLine = fgets(szLineBuf, sizeof(szLineBuf), fp);
129+
if(szLine == NULL)
130+
{
131+
perror("Read child process's lefted output");
132+
break;
133+
}
134+
135+
printf("Child process lefted output: %s\n", szLine);
136+
}while(szLine != NULL);
137+
138+
if(WIFEXITED(status))
139+
{
140+
printf("Normally exited\n");
141+
}
142+
143+
if(WIFSIGNALED(status))
144+
{
145+
printf("exited by signal: %d\n", WTERMSIG(status));
146+
}
147+
148+
fclose(fp);
149+
printf("Will exit !!!\n");
150+
return 0;
151+
}
152+

‎kb/fgets.md

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
虽然笔者认可`不重复发明轮子`的理论,但是,在遇到具体问题的时间,如果你不知道一个具体的`API`,还是会陷入重复制造的麻烦当中。
2+
3+
笔者遇到的问题,是父进程从父子进程之间的`pipe`,按行工作协议读取子进程的行输出。
4+
5+
因为不知道`fdopen`函数的存在,原来曾蹩脚地写过解析行的小函数,正确性还没有办法一下子保证正确 :(
6+
7+
在用`fdopen`将文件句柄转换为文件流后,您立马可以直接使用工业级的`fgets stream API`
8+
9+
10+
11+
# 注意事项
12+
+ `fdopen`后句柄所有权将发生转移,后期必须使用`fclose`进行关闭文件流对象
13+
+ `fcntl`设置**pipe**文件句柄的`O_NONBLOCK`选项,对于`fgets`存在影响,建议在非阻塞场景,必须设置
14+
+ + `waitpid(childpid, &status, WNOHANG | WEXITED) == 0`检测子进程是否已退出
15+
16+
17+
# 遗留问题
18+
+ 文件流操作在`f* API`体系中单独设置阻塞非阻塞状态?

0 commit comments

Comments
 (0)
Please sign in to comment.