这个代码是有问题的!待修改,但需要发链接修改所以还是发表了
读者朋友们有建议的请积极评论呀!
这个代码的问题就出在,一旦关闭某个客户端,然后对应的服务器的一个子线程就跟着exit了,然后信号处理函数sigaction工作后,代码又循环到while (1 ) { accept那个地方,然后接收不到新的客户端就return -1 了 然后服务器端线程就退出了(被主线程回收了),再也接收不了新的客户端了!(状态是establish 但是IP地址端口都没了)
//多进程 的 高并发服务器。修改:利用sigchld信号,回收子进程
//头文件wait.h --waitpid(参1,参2,参3),参1是pid 参2是状态参数可以写null 参3默认0?我写WNOHANG是不等待/不阻塞
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include<netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <ctype.h>
#include <sys/wait.h>
#include <signal.h>
//信号 callback function
//while (1)的设计目的是保证所有子进程都能回收
void quitfun(int signum){
pid_t wpid;
while (1) {
wpid = waitpid(-1,NULL,WNOHANG);
if(wpid>0){
printf("wait child exit, pid号码是 %d\n",wpid);
}
else if (wpid ==0 ||wpid == -1){
break;
}
}
}
int main() {
int sfd = socket(AF_INET, SOCK_STREAM, 0);
if (sfd <0){
printf("socket fun error\n");
return -1;
}
//定义一个地址结gou体
struct sockaddr_in myad;
//清空 memory
bzero(&myad, sizeof(myad));
myad.sin_family =AF_INET;
myad.sin_port =htons(8888);
myad.sin_addr.s_addr = htonl (INADDR_ANY);
int ret = bind(sfd, (struct sockaddr *)&myad, sizeof(myad));
if (ret<0) {
printf("bind error/n");
return -1;
}
//将socket从主动变为被动(服务器必备),这样可以监听来自客户的请求
listen( sfd,128);
//定义一个地址结gou体接受客户端地址结构体
struct sockaddr_in dst;
bzero(&myad, sizeof(myad));
dst.sin_family =AF_INET;
dst.sin_port =htons(8888);
socklen_t dstleng = sizeof(dst);
//先阻塞sigchld信号,不是让它发不出来,而是如果发了,先等待,一会儿处理
sigset_t set2;
sigemptyset(&set2);
sigaddset(&set2, SIGCHLD);
sigprocmask(SIG_BLOCK, &set2, NULL);
pid_t clientpid;
int newfd;//这是收发描述符
while (1) {
//jieshou client connect
newfd = accept (sfd, (struct sockaddr* )&dst, &dstleng);
if (newfd <0) {
printf("服务端,accept error、\n");
return -1;
}
char addstring[128];
memset(addstring, 0x00,128);
printf("服务器端,还没有fork,客户端地址是:\n");
printf("IP:%s,PORT: %d\n", inet_ntop(AF_INET, &dst.sin_addr.s_addr,addstring,sizeof(addstring)),ntohs(dst.sin_port));
//fork child tackle message, father listen
clientpid = fork();
if (clientpid<0) {
printf("fork error\n");
close (sfd);
return -1;
}
else if (clientpid>0){
//father process ,close message 文件描述符
close (newfd);
//注册信号处理结构体
struct sigaction act;
act.sa_flags=0;
sigemptyset(&act.sa_mask);
act.sa_handler=quitfun;
sigaction(SIGCHLD,&act,NULL);
//解除对SIGCHLD的阻塞???(我的疑问,这个不应该写在sigaction函数前面?可能是我没学懂)
sigprocmask( SIG_UNBLOCK,&set2,NULL);
}
else if (clientpid ==0){
//子进程,打印端口,发现一个子进程1个端口,当然ip共享
printf("child process,IP:%s,PORT: %d\n", inet_ntop(AF_INET, &dst.sin_addr.s_addr,addstring,sizeof(addstring)),ntohs(dst.sin_port));
//把客户端发送过来的数据读出来
int i =0;
int n =0;
char buf[1024];
while (1){
memset(buf,0x00,sizeof(buf));
n = read (newfd,buf,sizeof(buf));
if (n<=0){
printf("这里是服务器,有客户端已关闭,或读到的为0\n");
break;
}
for (i=0;i<n;i++){
buf[i] =toupper(buf[i]);
}
//把数据传回客户端,变成大写了已经
write (newfd, buf, n);
}
close(newfd);
exit(0); //子进程退出,避免再次fork子进程
}
}
return 0;
}