多进程服务器(有问题的代码)

发布时间:2024年01月10日

这个代码是有问题的!待修改,但需要发链接修改所以还是发表了

读者朋友们有建议的请积极评论呀!

这个代码的问题就出在,一旦关闭某个客户端,然后对应的服务器的一个子线程就跟着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;
}

文章来源:https://blog.csdn.net/warmingsummer/article/details/135509531
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。