#include <stdio.h>
#include <unistd.h>
int gval = 10;
int main()
{
pid_t pid;
int lval = 20;
gval++, lval += 5;
pid = fork();
//子进程
if (pid == 0)
{
gval += 2, lval += 2;
}
else
{
gval -= 2, lval -= 2;
}
//子进程
if (pid == 0)
{
printf("子进程[%d,%d]\n", gval, lval);
}
else
{
sleep(30);
printf("父进程[%d,%d]\n", gval, lval);
}
printf("猜猜我是啥[%d,%d]\n", gval, lval);
}
fork函数子进程返回0, 父进程返回子进程的 pid
#include <sys/wait.h>
pid_t wait(int * statloc);
成功时返回终止的子进程ID, 失败时返回 -1
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
int main()
{
pid_t pid;
int status;
pid = fork();
//子进程
if (pid == 0)
{
sleep(10);
return 44;
}
else
{
wait(&status);
//正常退出
if(WIFEXITED(status)){
printf("获取子进程返回值%d\n", WEXITSTATUS(status));
}
}
printf("猜猜我是啥\n");
}
output:
取子进程返回值44
猜猜我是啥
当你运行此段代码时候, 发现最少等待10s钟才能程序结束, 原因是wait是阻塞的, 父进程将等待子进程执行完毕, 获取其返回值。
#include <sys/wait.h>
pid_t waitpid(pid_t pid, int * statloc, int options)
成功时返回终止的子进程ID(或0), 失败时返回 -1
具体参数:
参数 | 含义 |
---|---|
pid | 等待终止的子进程id, -1表示等待任意进程 |
statloc | 具体返回值指针 |
options | 具体参数常量 |
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
int main()
{
pid_t pid;
int status;
pid = fork();
//子进程
if (pid == 0)
{
return 44;
}
else
{
while (!waitpid(-1, &status, WNOHANG))
{
sleep(3);
printf("非阻塞等待\n");
}
//正常退出
if (WIFEXITED(status))
{
printf("获取子进程返回值%d\n", WEXITSTATUS(status));
}
}
printf("猜猜我是啥\n");
}
output:
非阻塞等待
获取子进程返回值44
猜猜我是啥
在这个示例里面, 我们使用了 waitpid 非阻塞等待子进程函数, 如果去掉我们的 while 等待, 一般是不会获取到子进程任何值就将结束了。
#include <stdio.h>
#include <signal.h>
#include <sys/wait.h>
#include <unistd.h>
void keycontrol(int sig)
{
if (sig == SIGINT)
{
puts("CTRL+C pressed.");
}
}
void child(int sig)
{
int status;
waitpid(-1, &status, WNOHANG);
if (WIFEXITED(status))
{
printf("%d\n", WEXITSTATUS(status));
}
}
int main()
{
int i;
pid_t pid;
signal(SIGINT, keycontrol);
signal(SIGCHLD, child);
//假装在运行
for (i = 0; i < 2; i++)
{
pid = fork();
if (pid == 0)
{
puts("我是子进程");
return 88;
} else {
puts("wait...");
sleep(10);
}
}
return 0;
}
output:
wait...
我是子进程
88
wait...
我是子进程
88
当你运行此代码时候发现, 我们的父进程并没有 sleep(10) 等待后返回, 而是早早的执行结束了。 发生信号时, 为了调用信号处理器, 将唤醒由于调用 sleep 函数而进入阻塞状态的进程, 所以 sleep 在信号发生时是失效的。
信号现在推荐使用 sigaction
echo_server.c
#include <stdio.h>
#include <signal.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#define BUF_SIZE 1024
void read_childproc(int sig)
{
pid_t pid;
int status;
pid = waitpid(-1, &status, WNOHANG);
printf("removed proc id: %d\n", pid);
}
int main()
{
//注册子进程信号
struct sigaction act;
act.sa_sigaction = read_childproc;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
sigaction(SIGCHLD, &act, 0);
int serv_sock = socket(PF_INET, SOCK_STREAM, 0);
//初始化地址
struct sockaddr_in serv_addr;
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(9200);
if (bind(serv_sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) == -1)
{
printf("绑定地址失败 \n");
exit(1);
}
if (listen(serv_sock, 5) == 1)
{
printf("绑定端口失败 \n");
exit(1);
}
////////接收请求///////////
struct sockaddr_in clnt_adr;
int clnt_sock, adr_sz, str_len;
pid_t pid;
char buf[BUF_SIZE];
while (1)
{
adr_sz = sizeof(clnt_adr);
clnt_sock = accept(serv_sock, (struct sockaddr *)&clnt_adr, &adr_sz);
if (clnt_sock == -1)
{
continue;
}
else
{
puts("new client connected...");
}
pid = fork();
if (pid == -1)
{
puts("-1 -1 -1");
close(clnt_sock);
continue;
}
//子进程处理
if (pid == 0)
{
//关闭复制到的父文件号
close(serv_sock);
while ((str_len = read(clnt_sock, buf, BUF_SIZE)) != 0)
write(clnt_sock, buf, str_len);
close(clnt_sock);
puts("子进程受理");
//正常退出子进程
return 0;
}
else
{
puts("父进程不处理 clnt_sock");
close(clnt_sock);
}
}
close(serv_sock);
return 0;
}
echo_client.c
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#define BUF_SIZE 5
int main(int argc, char *argv[])
{
char message[BUF_SIZE];
int str_len, recv_len, recv_cnt, i;
struct sockaddr_in serv_addr, clnt_addr;
int serv_sock = socket(PF_INET, SOCK_STREAM, 0);
if (serv_sock == -1)
{
printf("socket() error");
exit(1);
}
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
serv_addr.sin_port = htons(9200);
if (connect(serv_sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) == -1)
{
printf("connect() error");
exit(1);
}
while (1)
{
fputs("请输入您的信息,按Q键退出\n", stdout);
fgets(message, 1024, stdin);
//因为fgets会保留输入中换行符,故判断加\n
if (!strcmp(message, "q\n") || !strcmp(message, "Q\n"))
{
break;
}
write(serv_sock, message, strlen(message));
str_len = read(serv_sock, message, BUF_SIZE);
printf("Message from server: %s\n", message);
}
close(serv_sock);
return 0;
}