【第22期】观点:IT 行业加班,到底有没有价值?

线程池网络服务模型

原创 2016年06月01日 00:14:01

前述: 线程池网络服务是针对多线程网络服务模式的不足而提出的改进模式;其基本理念是先创建一批资源,当有用户到来时,直接分配已经创建的资源;线程池的主要目的是减少系统在频繁创建资源时的开销。

线程池网络服务的实现原理:

  1>  主服务线程创建的即定数量的服务线程,同时在指定端口进行侦听;

  2>  若当前有新连接到来,则从线程池中找出空闲的服务线程,为其服务,服务完毕,线程不进行释放,重新放回线程池;

  3>   若当前线程池已经满了,则将当前的连接加入等待队列或者为其创建新的线程为其服务(依实现而定);

线程池网络服务的流程图如下:

这里写图片描述

线程池服务的优点: 性能高效

线程池的核心设计思想是: 系统在初始化时就创建一定数量的服务线程,并使它们处于空闲装态,若当前有新用户到来,则系统先查找有无空闲线程,若有则立即为其分配服务线程,若没有,则将新用户加入待服务的队列并在其他线程服务完成后,重新为其分配服务线程。

新用户若在等待服务队列里耗时过长,会影响用户体验,针对此问题,有以下的改进方案:

1> 动态创建新的服务线程,服务结束后,该线程加入到线程池,此种改进方法的好处是用户体验得到提升,但是潜在问题是线程的规模在长时间,大并发用户的状态下,会变得很大,最后会因资源消耗过大,系统退出;

2> 增加一个线程资源回收机制,当线程池的规模达到一定程度或满足某种即定规则时,会主动杀死一些线程,以达到在用户体验于系统运行稳定性之间的折中;

线程池的设计方案:

   1> 系统在初始化时,开辟THREAD_MAX个线程,组成服务线程池。

   2> 每个线程均有两种状态,空闲、工作状态,每个线程均有一块属于自己得公共数据区域,这块数据区域存放两个变量,一个是用来标记自身状态,0:空闲 1:工作,另一个变量对应客户端套接字号,如果线程处于空闲状态,则套接字号为初始值。

   3> 当有新用户到来时,系统通过查找公共数据区域,判断当前系统是否有空闲线程,若有则直接为其分配服务线程。

   4> 若当前没有空闲线程,系统将不做任何处理,提示当前系统忙,关闭新客户套接字

以下是线程池的一个示例:

//客户端代码
#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 "../unp.h"
#define THREAD_MAX 3

typedef struct thread_arg{
    bool flag;
    int sockconn;
}thread_arg;

typedef struct thread_arg threadpool[THREAD_MAX];
threadpool pool;


void* handler(void *arg)
{
    int index = *(int *)arg;
    printf("[%d] thread startup.\n", index);

    struct thread_arg *pthread = &pool[index];

    int sockconn = pthread->sockconn;

    char sendbuf[100];
    Oper op;
    int result;
    while(1)
    {
        if(pthread->flag){
            printf("[%d] thread start work.\n", index);
        int res = recv(pool[index].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(pool[index].sockconn, (struct sockaddr*)&addrcli, &addrlen);
            printf("client[%d] quit.\n", addrcli.sin_port);
            pthread->flag = 0;
            close(sockconn);
            continue;
        }

        send(pool[index].sockconn, (char *)&result, sizeof(int), 0);
        }else{
            printf("[%d] thread is idel.\n", index);
            sleep(1);
        }
    }
}

int main(int ac, char *av[])
{
    int sockser = socket(AF_INET, SOCK_STREAM, 0);
    if(sockser == -1){
        perror("socket");
    }
    int yes = 1;
    if(setsockopt(sockser, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1){
        perror("setsockopt");
    }

    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);

    socklen_t addrlen = sizeof(struct sockaddr);
    int res = bind(sockser, (struct sockaddr*)&addrser, addrlen);
    if(res == -1){
        perror("bind");
    }
    listen(sockser, QUEUE_SIZE);


    pthread_t tid[THREAD_MAX];
    for(int i = 0; i < THREAD_MAX; ++i){
        pool[i].flag = 0;
        pool[i].sockconn = 0;
    }
    for(int i = 0; i < THREAD_MAX; ++i){
        pthread_create(&tid[i], NULL, handler, &i);
        sleep(1);
    }

    int sockconn;
    int j = -1;
    while(1){
        sockconn = accept(sockser, (struct sockaddr*)&addrcli, &addrlen);
        if(sockconn == -1){
            perror("accept");
        }
        printf("client[%d] connect server ok.\n", addrcli.sin_port);
        for(int i = 0; i < THREAD_MAX; ++i){
            if(pool[i].flag == 0){
                pool[i].sockconn = sockconn;
                pool[i].flag = 1;
                break;
            }
            ++j;
            if(j >= THREAD_MAX){
                pthread_create(&tid[j], NULL, handler, &j);
                pool[j].sockconn = sockconn;
                pool[j].flag = 1;
                sleep(1);
                break;
            }
        }
    }
    close(sockser);
    return 0;
}
//头文件
#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;
版权声明:本文为博主原创文章,未经博主允许不得转载。 举报

相关文章推荐

网络编程-线程池模型的使用

线程池服务模型是single thread 与 request per thread两种模型的折中方案,其在实现时通常需要借助任务队列,主线程往任务队列尾添加任务,线程池中的服务线程不断从任务队列头取...

浅析I/O模型

也许很多朋友在学习NIO的时候 都会感觉有点吃力,对里面的很多概念都感觉不是那么明朗。在进入Java NIO编程之前,我们今天先来讨论一些比较基础的知识:I/O模型。下面本文先从同步和异步的概念 说起,然后接着阐述了阻塞和非阻塞的区别,接着介绍了阻塞IO和非阻塞IO的区别,然后介绍了同步IO和异步IO的区别,接下来介绍了5种IO模型,最后 介绍了两种和高性能IO设计相关的设计模式(Reactor和Proactor)。 <p style="text

线程池网络服务

1、线程池网络服务:针对多线程网络服务模式的一些不足之处而提出的改进模式。池是一个很重要的概念,其基本理念是:先创建一批资源,当有用户到来时,直接分配以创建好的资源,它的主要目的是减少系统在频繁创建资...

使用 Apache MINA 开发高性能网络应用程序

在分布式服务框架中,一个最基础的问题就是远程服务是怎么通讯的,在Java领域中有很多可实现远程通讯的技术,例如:RMI、MINA、ESB、Burlap、Hessian、SOAP、EJB和JMS等,这些名词之间到底是些什么关系呢,它们背后到底是基于什么原理实现的呢,了解这些是实现分布式服务框架的基础知识,而如果在性能上有高的要求的话,那深入了解这些技术背后的机制就是必须的了,在这篇blog中我们将来一探究竟,抛砖引玉,欢迎大家提供更多的实现远程通讯的技术和原理的介绍。 基本原理 要实现网络机器间的通讯,首先得来看看计算机系统网络通信的基本原理,在底层层面去看,网络通信需要做的就是将流从一
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

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