多进程的网络服务的一般模型

来源:互联网 发布:杨辉三角c语言程序六行 编辑:程序博客网 时间:2024/04/30 21:32

前述:多进程网络服务模式其实是基于Linux系统提供的父子进程的关系为多用户提供并发服务,是比较受大众喜爱的并发服务技术,其基本的服务理念是来一个客户,就启动一个服务进程!

多进程网络服务的实现原理:

第一步:>主服务在端进行绑定监听,同时设置被绑定的地址与端口是可重用的(因为可能会有多个进程要在同一个端口进行监听),启动监听;

第二步:>若当前有新连接到来,就启动一个子进程与其交互,服务结束后子进程自动退出

多进程网络服务的流程图如下示:

这里写图片描述

多进程网络服务的优点: 方法通用

多进程网络服务的缺点:
1> 每次启动并关闭子进程会带来很大的开销,在大用户量并发的前提下,会产生不小的负担;

2> 父子进程间的数据共享,同步等实现上有一定的困难;

无论如何,该模式在实际的商用环境中是一种可选的模式!!!!

以下是一个该模式的简单实现:

该示例是服务器处理来自客户端的请求:

服务器端的代码如下:

#include "../unp.h"//子进程处理通信过程void handler(int sock){    int sockconn = sock;    //得到客户端的套接字    char sendbuf[100];    Oper op;    int result;    while(1)    {        int res = recv(sockconn, (char *)&op, sizeof(op), 0);    //接收客户的消息        if(res == -1){            perror("recv");        }        //对客户端的服务请求进行处理        if(op.oper == ADD){   //得到两数的和            result = op.op1 + op.op2;        }else if(op.oper == SUB){  //得到两数的差            result = op.op1 - op.op2;        }else if(op.oper == MUL){   //得到两个数的乘积            result = op.op1 * op.op2;        }else if(op.oper == DIV){   //两个数的除            result = op.op1 / op.op2;        }else if(op.oper == QUIT){   //客户端发出退出服务请求            struct sockaddr_in addrcli;            socklen_t addrlen = sizeof(struct sockaddr);   //客户端的地址结构大小            getpeername(sockconn, (struct sockaddr*)&addrcli, &addrlen);   //得到对端即客户端的端口号(本例中是由系统自动分配的)            printf("client[%d] quit.\n", addrcli.sin_port);            break;        }        send(sockconn, (char *)&result, sizeof(int), 0);  //将服务后得到的结果返回给客户端    }}int main(int ac, char *av[]){    int sockser = socket(AF_INET, SOCK_STREAM, 0);   //得到服务器端的套接字    if(sockser == -1){        perror("socket");    }    struct sockaddr_in addrser, addrcli;   //服务器或客户端的地址结构    addrser.sin_family = AF_INET;    //服务器端所用的协议家族    addrser.sin_port = htons(SERVER_PORT);    //设置服务器的端口号    addrser.sin_addr.s_addr = inet_addr(SERVER_IP);  //设置服务器端的IP地址    socklen_t addrlen = sizeof(struct sockaddr);   //得到服务器的地址结构的大小    int res = bind(sockser, (struct sockaddr*)&addrser, addrlen);   //绑定服务器的套接字和服务器的地址结构    if(res == -1){        perror("bind");    }    listen(sockser, QUEUE_SIZE);   //监听    int sockconn;    while(1){        sockconn = accept(sockser, (struct sockaddr*)&addrcli, &addrlen);   //服务器接受客户端的连接        if(sockconn == -1){            perror("accept");        }        printf("client[%d] connect server ok.\n", addrcli.sin_port);        pid_t pid = fork();   //创建进程用于服务        if(pid == 0){            handler(sockconn);  //子进程处理客户端的请求函数            exit(0);        }else if(pid > 0){            close(sockconn);   //父进程关闭已连接套接字            continue;        }else{            printf("fork error.\n");        }    }    close(sockser);   //关闭服务器端的套接字    return 0;}

客户端的代码如下:

#include "unp.h"void Input(Oper *op);void help();int main(int ac, char *av[]){    int sockcli = socket(AF_INET, SOCK_STREAM, 0);  //得到客户端的套接字    if(sockcli == -1){        perror("socket");    }    struct sockaddr_in addrser;   //服务器的地址结构    addrser.sin_family = AF_INET;   //设置服务器的协议家族    addrser.sin_port = htons(SERVER_PORT);   //设置服务器的端口号    addrser.sin_addr.s_addr = inet_addr(SERVER_IP);   //设置服务器的IP地址    socklen_t addrlen = sizeof(struct sockaddr);   //得到服务器的地址结构大小    int res = connect(sockcli, (struct sockaddr*)&addrser, addrlen);   //连接服务器    if(res == -1){        perror("connect");    }else{        printf("client connect server ok.\n");    }    char cmd[20];   //用于存储客户所请求的服务名称    Oper op;        //客户的请求的结构体(包括客户请求的服务类型,输入的数据)    int result;     //由服务器发回的请求的服务结果    //客户发送请求并接收请求结果    while(1){        printf("please input cmd:>");        scanf("%s", cmd);        if(strcmp(cmd, "add") == 0){            op.oper = ADD;            Input(&op);        }else if(strcmp(cmd, "sub") == 0){            op.oper = SUB;            Input(&op);        }else if(strcmp(cmd, "mul") == 0){            op.oper = MUL;            Input(&op);        }else if(strcmp(cmd, "div") == 0){            op.oper = DIV;            while(1){                Input(&op);                if(op.op2 == 0){   //除数为0时重新输入                    perror("op2 == 0 error");                    printf("please input again.\n");                    continue;                }                break;            }        }else if(strcmp(cmd, "help") == 0){            help();            continue;        }else if(strcmp(cmd, "quit") == 0){            op.oper = QUIT;        }else{            printf("your input is invalid.\n");        }        int res = send(sockcli, (char *)&op, sizeof(op), 0);  //发送客户的请求给服务器        if(res == -1){            perror("send");        }        if(op.oper == QUIT){            break;        }        recv(sockcli, &result, sizeof(int), 0);   //接收服务器发送回来的结果        printf("result = %d\n", result);    }    close(sockcli);   //关闭客户端的套接字    return 0;}void Input(Oper *op)   //得到进行操作的两个数{    printf("please input op1 add op2.\n");    scanf("%d, %d", &op->op1, &op->op2);}void help()   //提示信息{    printf("#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*\n");    printf("^^^^^^^^^version^^^^^^^^^ :         ^^^^^v1.0^^^^^^^^^^\n");    printf("^^^^^^^^^author^^^^^^^^^^ :         ^^^^^haha^^^^^^^^^^\n");    printf("~*~*~*~*~cmd~*~*~*~*~*~*~           ~*~*~describe~*~*~\n");    printf("~*~*~*~*~add~*~*~*~*~*~*~           ~*~*~op1 + op2~*~*\n");    printf("~*~*~*~*~sub~*~*~*~*~*~*~           ~*~*~op1 - op2~*~*\n");    printf("~*~*~*~*~mul~*~*~*~*~*~*~           ~*~*~op1 * op2~*~*\n");    printf("~*~*~*~*~div~*~*~*~*~*~*~           ~*~*~op1 / op2~*~*\n");    printf("#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*\n");}

头文件

#include <iostream>#include <unistd.h>#include <signal.h>#include <stdio.h>#include <arpa/inet.h>#include <netinet/in.h>#include <string.h>#include <stdlib.h>#include <sys/socket.h>#define SERVER_IP    "127.0.0.1"#define SERVER_PORT  7070#define QUEUE_SIZE   5typedef enum{ADD, SUB, MUL, DIV, QUIT}OPER_STATE;typedef struct Oper{    OPER_STATE oper;    int op1;    int op2;}Oper;
1 0
原创粉丝点击