实现思路
// 1. Socket() 创建监听套接字 -- lfd
// 2. Bind() 绑定服务器地址结构 。 strcut sockaddr_in srv_addr;
// 3. Listen() 128
// 4. 启动循环
while(1) {
// 5. cfd = Accept(lfd, 客户端地址结构,大小);
// 6. pid = fork() 创建子进程
if pid == 0 {
// 子进程
} else if (pid > 0) {
// 父进程
}
}
// 7. 子进程
close(lfd); // 子进程关闭,不使用的 lfd
read(cfd);
小 —— 大 toupper();
write(cfd);
// 8. 父进程
close(cfd); // 父进程关闭,不使用的 通信套接字 cfd
// 回收子进程。回收 pcb
// 信号捕捉 —— SIGCHLD
sigaction() --- struct sigaction {sa_handler, sa_mask, sa_flags}
while(waitpid(0, NULL, WNOHANG) > 0)
代码实现
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <errno.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <ctype.h>
#include <signal.h>
#include <sys/wait.h>
#include "wrap.h"
#define SRV_PORT 8888
void sys_err(const char *str)
{
perror(str);
exit(1);
}
void catch_child(int signum)
{
while (waitpid(-1, NULL, WNOHANG) > 0);
return ;
}
int main(int argc, char *argv[])
{
int lfd = 0, cfd = 0;
int ret, i;
pid_t pid;
struct sockaddr_in srv_addr, clt_addr;
socklen_t clt_addr_len;
char buf[BUFSIZ];
char clt_IP[512];
//memset(&srv_addr, 0, sizeof(srv_addr));
bzero(&srv_addr, sizeof(srv_addr));
srv_addr.sin_family = AF_INET;
srv_addr.sin_port = htons(SRV_PORT);
srv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
lfd = Socket(AF_INET, SOCK_STREAM, 0);
Bind(lfd, (struct sockaddr *)&srv_addr, sizeof(srv_addr));
Listen(lfd, 128);
clt_addr_len = sizeof(clt_addr);
while (1) {
cfd = Accept(lfd, (struct sockaddr *)&clt_addr, &clt_addr_len);
printf("IP:%s, port:%d\n",
inet_ntop(AF_INET, &clt_addr.sin_addr.s_addr, clt_IP, sizeof(clt_IP)),
ntohs(clt_addr.sin_port));
// 创建子进程
pid = fork();
if (pid < 0) {
sys_err("fock err:");
} else if (pid == 0) { // 子进程
close(lfd);
break;
} else if (pid > 0) {
close(cfd); // 父进程,关闭通信socket
// 定义初始化 信号状态结构体
struct sigaction act;
act.sa_handler = catch_child; // 设置回调函数
sigemptyset(&act.sa_mask); // 清空 回调函数调用期间生效的 信号屏蔽字
act.sa_flags = 0;
// 注册信号捕捉函数
ret = sigaction(SIGCHLD, &act, NULL);
if (ret != 0)
sys_err("sigaction err:");
continue;
}
}
// 子进程业务逻辑
if (pid == 0) {
for (;;) {
ret = Read(cfd, buf, sizeof(buf));
if (ret == 0) {
printf("客户端关闭, 退出...\n");
close(cfd);
exit(1);
}
for (i = 0; i < ret; i++) {
buf[i] = toupper(buf[i]);
}
Write(cfd, buf, ret);
Write(STDOUT_FILENO, buf, ret); // 打印到服务器屏幕
}
}
return 0;
}