#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <ctype.h>
#include <strings.h>
#include <sys/wait.h>
#include <signal.h>
void func(int sig)
{
while( (waitpid(-1, NULL, WNOHANG )) > 0)
printf("有一个客户端退出\n");
}
int main()
{
// 创建套接字
int sfd = socket(AF_INET, SOCK_STREAM, 0);
// 绑定
struct sockaddr_in server;
bzero(&server, sizeof(server));
server.sin_family = AF_INET;
server.sin_port = htons(8888);
server.sin_addr.s_addr = htonl(INADDR_ANY);
bind(sfd,(struct sockaddr*)&server, sizeof(server));
// 监听上限
listen(sfd, 128);
// 获得连接
struct sockaddr_in client;
socklen_t len = sizeof(client);
int flag = 0; // 标志位,为了避免循环注册信号捕捉
// 先屏蔽信号SIGCHLD
sigset_t set, oldset; // 定义自定义信号集
sigemptyset(&set); // 清空自定义信号集
sigemptyset(&oldset);
sigaddset(&set, SIGCHLD); // 自定义信号集set中屏蔽SIGCHID
sigprocmask(SIG_BLOCK, &set, &oldset); //将自定义信号集set映射到阻塞信号集,并保留原始信号集
while(1)
{
int cfd = accept(sfd, (struct sockaddr*)&client, &len);
if(cfd > 0) // 代表得到新连接,创建子进程
{
pid_t pid = fork(); // 创建子进程,fork后会出现两个进程,一个子进程一个父进程,fork前的代码是父进程执行,fork后的代码子父进程都执行,执行顺序是谁先占CPU谁执行。
if(pid == 0) // 子进程负责通信,即执行的是子进程
{
close(sfd); // 用于通信,sfd 没有用,关闭
char buf[BUFSIZ];
bzero(buf, sizeof(buf));
while(1)
{
int ret = read(cfd, buf, sizeof(buf));
if(ret < 0)
{
perror("read err");
return -1;
}
else if(ret == 0)
{
printf("客户端关闭\n");
return 0;
}
else
{ // 正常读写
write(cfd, buf, ret); // 回写服务器
write(STDOUT_FILENO, buf, ret); // 输出到屏幕
}
}
}
else if(pid > 0) // 若执行的是父进程,父进程回收资源:捕捉SIGCHID
{
close(cfd); // 父进程不负责连接,关闭cfd
if(flag == 0)
{
// 注册捕捉
struct sigaction act;
act.sa_flags = 0;
act.sa_handler = func;
sigemptyset(&act.sa_mask);
sigaction(SIGCHLD, &act, NULL);
// 解除阻塞,即恢复旧的信号集
sigprocmask(SIG_SETMASK, &oldset, NULL);
// 改变标志位,保证下次循环,不注册
flag = 1;
}
}
}
}
return 0;
}
多进程版 高并发服务器
最新推荐文章于 2023-11-09 20:05:21 发布