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

原创 2016年05月31日 22:25:11

前述:多进程网络服务模式其实是基于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   5

typedef enum{ADD, SUB, MUL, DIV, QUIT}OPER_STATE;

typedef struct Oper{
    OPER_STATE oper;
    int op1;
    int op2;
}Oper;
版权声明:本文为博主原创文章,未经博主允许不得转载。

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

前述: 多线程网络服务类似于多进程网络服务模式, 不同之处是多线程是为新到连接启动一个服务线程,而多进程模式是为新到连接启动一个服务进程。多线程网络服务模式的实现原理: 1> 在主服务线程里进行阻塞...
  • github_33736971
  • github_33736971
  • 2016年05月31日 23:34
  • 254

并发模型编程中多进程与多进程的选择

在进行并发程序的实现时我们经常面临一个问题,到底是该选择多线程并发模型还是多线程并发模型呢?要在这两者间进行一个选择,首先需要明白两者的优缺点: 多线程的优点 方便高效的内存共享 ...
  • lisongjia123
  • lisongjia123
  • 2016年04月17日 18:56
  • 907

多进程网络服务

1、高性能网络服务程序  Linux的一个应用优势是可用于设计各种高性能网络服务程序,高性能的一个特点就是实现并发访问处理,及同时为多个在线用户提供服务;多进程网络服务、多线程网络服务、线程池网络服务...
  • qaz5210987
  • qaz5210987
  • 2018年02月10日 13:20
  • 1

Linux服务器多进程模型

Linux多进程服务器真的很给力,赞一个! Linux多进程一般是master负责侦听,worker接受和伺服client。 一个使用了以下技术的多进程模型: 1. sigset...
  • huangjm_13
  • huangjm_13
  • 2014年11月26日 09:45
  • 1393

基于UDP的C/S网络编程模型(使用sendto和recvfrom函数)

服务端: #include #include #include #include #include #include //#define CONFIG_TCP_CONNECT #d...
  • zh1074
  • zh1074
  • 2017年09月11日 15:13
  • 116

Ngnix的基本学习-多进程和Apache的比较

Ngnix的学习总结Ngnix一直以来都是I/O密集性服务的不二选择,今天就把这两天整理学习关于Ngnix的基本知识整理下,如果有错误,请大家指出,谢谢批评。基本的架构设计 接口设计 所有的模块都遵...
  • qq_25797077
  • qq_25797077
  • 2016年08月13日 17:57
  • 1171

Nginx 多进程模型是如何实现高并发的?

进程数与并发数不存在很直接的关系。这取决取server采用的工作方式。 如果一个server采用一个进程负责一个request的方式,那么进程数就是并发数。那么显而易见的,就是会有很多进程在等待中。...
  • hellochenlu
  • hellochenlu
  • 2017年01月16日 22:50
  • 132

很好的设计-服务端网络请求处理模型

几个月前学习了公司内部的网络编程框架,结果zuij
  • whuqin
  • whuqin
  • 2014年06月27日 16:10
  • 1223

关于数据加密模型

首先介绍数据加密算法(Data Encryption Algorithm,DEA),它属于对称密钥密码体制.   DES是一种分组密钥,加密前先对整个明文分组,每个分组64位长的二进制。然...
  • ciaos
  • ciaos
  • 2012年12月04日 16:23
  • 798

两种网络结构模型(二、三)

C/S网络结构模型 C/S(客户机/服务器)结构模型的网络逻辑结构如图5.2所示,在局域网应用最广。在这种网络管理模式中,网络中的各计算机地位不再平等,而是由一台或者多台计算机担当整个网络的管理角色,...
  • xiulan2004
  • xiulan2004
  • 2010年10月20日 18:03
  • 230
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:多进程的网络服务的一般模型
举报原因:
原因补充:

(最多只允许输入30个字)