zoukankan      html  css  js  c++  java
  • Server模块使用多线程处理过程

    物联网智能家居环境监测项目多线程说明
    在Server模块的实现过程中,我们使用的是单线程来处理客户端。即开启一次服务器,受理一个客户端,仅接受一个集合。
    在实际项目运行过程中,考虑到实际情况,多采用多线程的形式同时处理多个客户端。例如本项目,可能存在一个中央服务器,而有多个采集子系统在运行,向服务器发送数据。
    但是本项目所搭建的架构,并非特别适合于多线程处理。在模块构建方面只是简单地模拟了一下基于TCP协议的网络传输过程。
    Server模块中的reciver()方法返回值为Collection<Environment>集合,本意是模块对象调用一次该方法,接受一个客户端,则返回一个集合。也就是单线程处理过程。

    先说一下多线程处理的思路:
    其实很简单,只需要让服务器循环调用ss.accpet()方法,近乎时刻处于侦听状态。那么问题来了,之前服务器调用ss.accpet()方法会得到一个代表客户端的Socket对象,我们后续所有的工作都是基于这个Socket对象来实现的。现在如何让服务器接收到Socket之后立刻放下手头的工作回到侦听状态?

    实现原理其实也很简单,这里使用到多线程的思想:
    在服务器接收到一个客户端的连接请求后,立刻开启一条线程,把Socket对象交由这条线程去处理。

    基本代码如下:
    //创建服务器套接字
    int port = 8989;
    ServerSocket ss = new ServerSocket(port);
    //可以使用无限循环让服务器始终处于开启状态
    //也可以设置一个标志位来手动控制服务器的关闭
    while(true){
    //有客户端发来请求
    Socket socket = ss.accpet();
    //创建一条线程处理这个客户端
    new ClientThread(socket).start();
    }
    这里new线程并启动只是一个时间点上所做的事情,执行完毕之后当前while循环代码全部执行完毕,会进入到下一次循环中,也就是再一次调用accept()进入侦听状态等待下一个客户端的连接。近乎做到了时刻处于侦听状态的效果。当然在单核CPU计算机中不存在绝对的同步,只是CPU运行、分配时间片和切换速度很快,我们肉眼无法察觉。在java代码中创建一条线程并调用start()方法耗时是非常非常短的。所以在这里可以近乎看做服务器永远处在accept()方法的侦听过程中。

    这里一定要注意的是,服务器只开启一次,循环体内的写的代码试是用来多次调用accept()方法接受客户端的请求。之前有同学把创建服务器的步骤也写到了循环里,其实违背了多线程的初衷,也没有真正起到同步运行的目的。

    ClientThread就是我们自己定义的一个线程类,现在我们把每次拿到的Socket交给它,它就可以帮助我们去实现之前我们写在reciver()方法里的功能。例如:获取套接字输入流、获取客户端传输过来的数据清单(即采集模块采集到的Collection集合)。但是这样定义的话,我们就必须在线程中调用DBStore模块的入库方法,在线程中执行入库操作。因为线程中接收到的数据清单想要再交给Server模块去处理不太容易。但是并非不可,只是需要做很麻烦的处理,得不偿失,我们没有必要去纠结这个问题。

    现在回到前文所述的问题,为什么说本模块的编写方式不适合多线程处理?
    试想,现在有10个客户端同时连接服务器,开始传输数据。根据上文所述,我们需将DBStore模块入库的操作放在线程里执行,那Server模块中的reciver()方法返回什么?该方法声明是存在返回值的,必须要返回一个值回去。所以在这个地方有一点的歧义。我们如果想要单纯测试一下多线程的编写方法,可以把Server接口中的返回值声明为void。

    但是这样做又存在一个新的问题,我们在项目中如何实现模拟多个客户端同时连接同时发送数据?
    当然了大家可能会想到直接把客户端的测试类执行三次,但是我们现在已经引入了备份模块,每次解析完原始数据,再去解析都会跳过已经读取过的字符。如果想模拟这个过程的同学,可以把采集模块代码复制三分,分别去采集三个不同的原始文件。

    给大家一份线程代码的简单实现自己参考一下:
    class ClientThread extends Thread {

    // 客户端套接字
    //Server模块在创建线程时通过构造器传入
    private Socket client;
    public ClientThread(Socket socket) {
    this.client = socket;
    }

    @Override
    public void run() {
    // 客户端套接字的输入流
    InputStream is;
    try {
    is = client.getInputStream();
    // 使用对象输入流进行包装
    ObjectInputStream ois = new ObjectInputStream(is);

    Collection<Environment> coll = (Collection<Environment>) ois.readObject();
    System.out.println("接收完毕!总数据量:" + coll.size());
    DBStore dbStore = new DBStoreImpl();
    dbStore.saveDb(coll);
    } catch (Exception e) {
    e.printStackTrace();
    }
    }
    }













  • 相关阅读:
    广义线性模型 GLM
    最大熵模型 Maximum Entropy Model
    Ensemble Learning 之 Bagging 与 Random Forest
    Ensemble Learning 之 Gradient Boosting 与 GBDT
    Ensemble Learning 之 Adaboost
    集成学习概述
    决策树之 CART
    用于分类的决策树(Decision Tree)-ID3 C4.5
    朴素贝叶斯(Naive Bayes)
    动态规划 Dynamic Programming
  • 原文地址:https://www.cnblogs.com/DennySmith/p/12189265.html
Copyright © 2011-2022 走看看