Linux环境下多进程并发服务器

一、多进程服务器
在实际项目中,服务器同时可以处理多个客户端的请求,我们称为并发服务器。比如12306服务器,在遇到春节购票高峰的时候,虽然一天需要处理上亿的客户流量,但是我们购票丝毫不觉得卡顿,当然有时候会是网络的问题,这就是并发服务器的强大功能。并发方式还有多线程、多路复用(select、epoll、poll),本文主要记录多进程并发。

二、多进程编程系统调用
1、fork()函数
(1)原型

			头文件#include <unistd>
			pid_t fork(void);
			返回值:成功返回0或>0的数,失败返回-1;

(2)功能
fork()调用之后,当前进程称为父进程,父进程的文本段、数据段、堆栈都会被复制一份,在内存区域重新开辟空间,被复制的进程称为子进程,fork()成功,则返回两个值,第一次返回给父进程,是子进程的PID。第二次返回0给子进程。fork()失败返回<0,失败的原因一般是系统中有太多进程或着超出了系统限制。调用getpid可以获取当前进程ID,getppid()获取父进程ID。

2、vfork()函数
(1)原型
头文件:

#include <sys/types.h>
#include <unistd.h>

pid_t vfork(void);
返回值:
成功:子进程中返回 0,父进程中返回子进程 ID。
失败:返回 -1。

(2)功能:vfork和fork都是创建新进程,它俩有两个区别,执行顺序和对数据段的影响。
执行顺序:fork()调用后的父子进程执行顺序由操作系统调度器决定;而vfork()后的父进程要等待子进程exit(0)退出后才执行。
数据段影响:子进程没有退出之前是在父进程的进程空间运行,这也是父子进进程均会影响数据段的原因。

3、exec*()系列函数
在这里插入图片描述功能:是去执行另外的程序。exec函数不会返回,因为去执行别的程序,如果返回,说明出错。
4、wait()和waitpid()
父进程可以调用wait()或waitpid()查看子进程推出状态。
僵死进程:如果一个已经终止、但其父进程尚未对其调用wait进行善后处理(获取终止子进程的有关信息如CPU时间片、释放它锁占用的资源如文件描述符等的进程被称僵死进程(zombie)。所以最好使用wait()或waitpid()处理僵死进程。

四、实现代码
这里只给出服务器的main实现代码,其他c文件和客户端代码请点击查看

main.c
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<sys/stat.h>
#include<sys/wait.h>
#include<fcntl.h>
#include<errno.h>
#include<stdlib.h>
#include<getopt.h>
#include<string.h>
#include<arpa/inet.h>
#include<ctype.h>
#include"server.h"


int deal_data(char *,char *,char *,char *);
/*
void print_usage(char *program)
{
        printf("%s usages: %s\n",strerror(errno));
        printf("-p(port):serve listen port\n");
        printf("-h(help):help information\n");
        exit(0);
}
*/
int main(int argc,char **argv)
{
        int                  opt;
        int                  serv_port = 0;
        struct sockaddr_in   serv_addr;
        struct sockaddr_in   clien_addr;
        socklen_t            clienaddr_len;
        int                  sockfd;
        int                  clienfd;
        int                  fd;
        int                  rv;
        char                 buf[1024];
        int                  on = 1;
        char                 finish[25]="serve receive finish!";
        pid_t                pid;
        sqlite3               *db;
        char                 *errmsg;
        int                  statu;
        char                 ID[50];
        char                 temp[10];
        char                 time[20];
/*

        struct option long_options[]=
        {
                {"port",1,NULL,'p'},
                {"h",0,NULL,'h'},
                {0,0,0,0}
        };

        while((opt = getopt_long(argc,argv,"p:h",long_options,NULL)) > 0)
        {
                switch(opt)
                {
                        case 'p':
                                serv_port = atoi(optarg);
                                break;
                        
                        case 'h':
                                print_usage(argv[0]);
                                break;
                        default:
                                break;
                }
        }

        if(!serv_port)
        {
                print_usage(argv[0]);
        }

       
*/
	DNSopt(argc,argv,&serv_port);

        if((sockfd = socket(AF_INET,SOCK_STREAM,0)) < 0)
        {
                printf("serve socket failed: %s\n",strerror(errno));
		mylog(__FUNCTION__,__LINE__,ERROR,"serve socket failed:%s\n",strerror(errno));
        }
        memset(&serv_addr,0,sizeof(serv_addr));
        serv_addr.sin_family = AF_INET;
        serv_addr.sin_port = htons(serv_port);
        serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);

        setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));

        if(bind(sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0)
        {
                printf("bind failed: %s\n",strerror(errno));
		mylog(__FUNCTION__,__LINE__,ERROR,"bind failed:%s\n",strerror(errno));
                close(sockfd);
                return -1;
        }

        listen(sockfd,10);

        
        while(1)
        {

                printf("serve wait to connect new client...\n");

                if((clienfd = accept(sockfd,(struct sockaddr *)&clien_addr,&clienaddr_len)) <0 )
                {

                        printf("serve accept failed: %s\n",strerror(errno));
			mylog(__FUNCTION__,__LINE__,ERROR,"server accept faild:%s\n",strerror(errno));
                        return -1;
                }


                printf("Accept new client[%s:%d] scuccessfully.\n",inet_ntoa(clien_addr.sin_addr),ntohs(clien_addr.sin_port));

                pid = fork();
                if(pid < 0)
                {
                        printf("fork() create child process failed: %s\n",strerror(errno));
			mylog(__FUNCTION__,__LINE__,ERROR,"fork() create process failed:%s\n",strerror(errno));
                        close(clienfd);
                        continue;
                }
                if(pid > 0)
                {
                        close(clienfd);
                        continue;
                    
                }
                if(pid == 0)
                {
                        close(sockfd);

                        printf("child process is running...\n");
                        datbas_open(&db);
                
                        while(1) 
                
                        {

                                memset(buf,0,sizeof(buf));


                                if((rv=read(clienfd,buf,sizeof(buf))) < 0)
                                {
                                        printf("read from client failed: %s\n",strerror(errno));
                                        close(clienfd);
                                        close(fd);
                                        datbas_close(db);
                                        exit(0);
                                }

                                else if(rv == 0)
                                {
                                        printf("Disconnect with client..\n");
                                        close(clienfd);
                                        close(fd);
                                        datbas_close(db);
                                        exit(0);
                                }

                                                             
                                if(deal_data(buf,ID,temp,time) < 0)
                                    printf("deal_data failed:%s\n",strerror(errno));

                                if(datbas_insert(db,ID,temp,time) < 0)
                                    printf("datbas_insert failed:%s\n",strerror(errno));
                                         
                                if(write(clienfd,finish,sizeof(finish))<0)
                                        printf("write to client failed:%s\n",strerror(errno));
                       
                        }

                        close(clienfd);
                        datbas_close(db);
               
                }
            
       
        }


        return 0;

}

五、测试结果
运行服务器
在这里插入图片描述
第一个客户端:[127.0.0.1:54154]
在这里插入图片描述第二个客户端:[127.0.0.1:54156]

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值