多进程并发服务器(低端)

(1)  分析:      

        多进程的并发服务器中,父进程一旦监听到客户端连接,就会创建相应的子进程来处理。如果用waipid(),父进程因为accept阻塞无法跳转。因此,防止僵尸进程,只能依靠信号,要进行信号改造,一有子进程退出就会产生DIGCHLD信号,改造DIGCHLD信号,使得父进程一收到信号就跳过来回收。

        如果成功读到cnt,不应该用break,应该用close(client_fd)。因为整个大的while(1)已经属于子进程的内容 。子进程资源是完全copy了父进程一份,如果client退出的话就直接break,acceptclient_fd,就会出错。所以用return 0,直接退出子进程。

(2)代码

server.c

#include<stdio.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<wait.h>
#include<netinet/in.h>
#include<unistd.h>
#include<stdlib.h>
#include<pthread.h>
#include <arpa/inet.h>
#include<signal.h>

int signal_quit_hander(int signo)
{
        switch(signo)
        {
                case SIGCHLD:
                        printf("child process quit\n");
           /*捕捉到SIGCHLD信号,父进程不阻塞但等待子进程退出,并回收释放资源*/
                        while(waitpid(-1,NULL,WNOHANG) > 0);   
                break;
        }
}

int signal_setup()
{
        struct sigaction act,oact;
        act.sa_handler = (void *)signal_quit_hander;  //新的信号处理方式
        sigemptyset(&act.sa_mask);
        act.sa_flags = 0;
        act.sa_flags |= SA_RESTART;
        if(sigaction(SIGCHLD,&act,&oact) < 0)
        {
                return -1;
        }
        return 0;
}
int main()
{
        int fd;
        pid_t pid;
        int sockfd,client_fd;
        int cnt;
        struct sockaddr_in saddr,caddr;
        socklen_t slen,clen;
        char rdBuff[128] = {0};

        sockfd = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
        if(sockfd < 0)
        {
                perror("socket failed\n");
                exit(1);
        }
printf("sockfd:%d\n",sockfd);

        saddr.sin_family = AF_INET;
        saddr.sin_port = htons(8090);
        saddr.sin_addr.s_addr = htons(INADDR_ANY);
        slen = sizeof(saddr);
        clen = sizeof(caddr);
        bind(sockfd,(struct sockaddr *)&saddr,slen);
        signal_setup();
        listen(sockfd,100);

        while(1)
        {
                printf("listen ...\n");
                client_fd = accept(sockfd,(struct sockaddr *)&caddr,&clen);
                printf("connect successfully\n");
                printf("client_fd:%d\n",client_fd);
                printf("cip:%s\n",inet_ntoa(caddr.sin_addr));
                pid = fork();
                if(pid < 0)
                {
                        perror("fork failed\n");
                        exit(1);
                }
                else if(pid == 0)
                {
                        close(sockfd);
                        while(1)
                        {
                                cnt = read(client_fd,rdBuff,128);
                                if(cnt < 0)
                                {
                                        perror("read failed\n");
                                        exit(2);
                                }
                                else if(cnt == 0)
                                {
                                        printf("client offline...\n");
                                        close(client_fd);
                                        //break;
                                        return 0;
                                }
                                else
                                {
                                        printf("rd = %s\n",rdBuff);
                                        write(client_fd,"ok read data end",18);
                                }
                        }
                }
                else
                {
                        close(client_fd);
                }
        }
                close(sockfd);
                return 0;
}
~  

client.c

#include<stdio.h>
#include<sys/ipc.h>
#include<sys/types.h>
#include<sys/msg.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<fcntl.h>
#include<sys/stat.h>

int main()
{
        int client_fd;
        int i = 10;
        int ret;
        int sockfd,file_fd;
        struct sockaddr_in saddr = {0};
        socklen_t slen;
        char rdBuff[128] = {0};
        sockfd = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
        if(sockfd < 0)
        {
                perror("socket failed\n");
                exit(1);
        }
        printf("sockfd:%d\n",sockfd);

        saddr.sin_family = AF_INET;
        saddr.sin_port = htons(8090);
        saddr.sin_addr.s_addr = inet_addr("192.168.56.133");
        slen = sizeof(saddr);
        do{
                ret = connect(sockfd,(struct sockaddr *)&saddr,slen);
        }while(ret != 0);
        printf("connect successfully\n");
        sleep(2);
        while(i--)
        {
                write(sockfd,"hello",8);
                read(sockfd,rdBuff,128);
                printf("data = %s,pid = %lu\n",rdBuff,(unsigned long)getpid());
                usleep(500000);
        }
        close(sockfd);
        return 0;
}

1.c

#include<stdio.h>
#include<sys/ipc.h>
#include<sys/types.h>
#include<sys/msg.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<fcntl.h>
#include<sys/stat.h>

int main()
{
        int client_fd;
        int i = 10;
        int ret;
        int sockfd,file_fd;
        struct sockaddr_in saddr = {0};
        socklen_t slen;
        char rdBuff[128] = {0};
        sockfd = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
        if(sockfd < 0)
        {
                perror("socket failed\n");
                exit(1);
        }

printf("sockfd:%d\n",sockfd);

        saddr.sin_family = AF_INET;
        saddr.sin_port = htons(8090);
        saddr.sin_addr.s_addr = htons(INADDR_ANY);
        slen = sizeof(saddr);
        clen = sizeof(caddr);
        bind(sockfd,(struct sockaddr *)&saddr,slen);
        signal_setup();
        listen(sockfd,100);

        while(1)
        {
                printf("listen ...\n");
                client_fd = accept(sockfd,(struct sockaddr *)&caddr,&clen);
                printf("connect successfully\n");
                printf("client_fd:%d\n",client_fd);
                printf("cip:%s\n",inet_ntoa(caddr.sin_addr));
                pid = fork();
                if(pid < 0)
                {
                        perror("fork failed\n");
                        exit(1);
                }
                else if(pid == 0)

(3)结果:

先运行server.c,再运行1.c,紧接着运行client.c

 

(4)注意:

SIGCHLD信号产生的条件

1.子进程终止时会向父进程发送SIGCHLD信号,告知父进程回收自己,但该信号的默认处理动作为忽略,因此父进程仍然不会去回收子进程,需要捕捉处理实现子进程的回收;

2.子进程接收到SIGSTOP(19)信号停止时;

3.子进程处在停止态,接受到SIGCONT后唤醒时。

综上:子进程结束、接收到SIGSTOP停止(挂起)和接收到SIGCONT唤醒时都会向父进程发送SIGCHLD信号。父进程可以捕捉该信号,来实现对子进程的回收,或者了解子进程所处的状态。

(2)借助SIGCHLD信号回收子进程

子进程结束运行,其父进程会收到SIGCHLD信号。该信号的默认处理动作是忽略。

(5)参考:

(57条消息) SIGCHLD信号_luciusvorenus的博客-CSDN博客

(57条消息) linux中sigaction函数详解_魏波.的博客-CSDN博客

(57条消息) wait()和waitpid()解析_waitpid(null)是等待一个子进程完成吗_Randy__Lambert的博客-CSDN博客

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值