Java网络通信基础系列-BIO模型

  关于Java网络通讯方面的内容,下载地址:https://github.com/mldn/echo,我也做的Fork,地址:https://github.com/bijian1013/echo

  Java基础知识:BIO、NIO、AIO三者的技术实现,以及彼此之间的区别

  Netty:TCP 程序实现为主,代码的核心:Echo程序模型,通过网络实现一个基础的Echo。

一.BIO模型:同步阻塞IO处理

  在程序的开发之中Java里面最小的处理单元就是线程,也就是说每一个线程可以进行IO的处理,在处理之中,该线程无法进行任何的其他操作。

  多线程是不可能无限制进行创造的,所以需要去考虑堆线程进行有效的个数控制。

  如果产生的线程过多,那么直接的问题在于,处理性能降低 ,响应的速度变慢。 需要去区分操作系统的内核线程以及用户线程的区别,所以最好与内核线程有直接联系,需要使用到固定线程池。

  【BIO】现在烧水,意味着你现在需要一直盯着水壶去看,一直看它已经烧为止,在这之中你什么都干不了。

 

二.实例

1.项目结构

  echo-util:公共的工具工程

  echo-base:基于java开发的bio、nio、aio实例

  echo-netty:基于netty开发的网络通信实例

  echo-http:基于netty开发的http服务实例

2.实例代码

  echo-util工程中的代码:

HostInfo.java

package com.bijian.info;

public interface HostInfo {
    public static final String HOST_NAME = "localhost" ;
    public static final int PORT = 9999 ;
    public static final String SEPARATOR = "%$%" ;
}

InputUtil.java

package com.bijian.util;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class InputUtil {
    private static final BufferedReader KEYBOARD_INPUT = new BufferedReader(new InputStreamReader(System.in));

    private InputUtil() {
    }

    /**
     * 实现键盘数据的输入操作 ,可以返回的数据类型为String
     *
     * @param prompt 提示信息
     * @return 输入的数据返回
     */
    public static String getString(String prompt) {
        boolean flag = true; // 数据接收标记
        String str = null;
        while (flag) {
            System.out.print(prompt);
            try {
                str = KEYBOARD_INPUT.readLine(); // 读取一行数据
                if (str == null || "".equals(str)) {
                    System.out.println("数据输入错误 ,该内容不允许为空:");
                } else {
                    flag = false;
                }
            } catch (IOException e) {
                System.out.println("数据输入错误 ,该内容不允许为空:");
            }
        }
        return str;
    }
}

  BIO实例代码:

BIOEchoServer.java

package com.bijian.bio.server;


import com.bijian.info.HostInfo;

import java.io.IOException;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class BIOEchoServer {
    public static void main(String[] args) throws Exception{
        ServerSocket serverSocket = new ServerSocket(HostInfo.PORT) ;// 设置监听端口
        System.out.println("服务器端已经启动,监听的端口为:" + HostInfo.PORT);
        boolean flag = true ;
        ExecutorService executorService = Executors.newFixedThreadPool(10) ;
        while(flag) {
            Socket client = serverSocket.accept() ;
            executorService.submit(new EchoClientHandler(client)) ;
        }
        executorService.shutdown() ;
        serverSocket.close() ;
    }

    private static class EchoClientHandler implements Runnable {
        private Socket client ; // 每一个客户端都需要启动一个任务(task)来执行。
        private Scanner scanner ;
        private PrintStream out ;
        private boolean flag = true ;   // 循环标记
        public EchoClientHandler(Socket client) {
            this.client = client ; // 保存每一个客户端操作
            try {
                this.scanner = new Scanner(this.client.getInputStream()) ;
                this.scanner.useDelimiter("\n") ; // 设置换行符
                this.out = new PrintStream(this.client.getOutputStream()) ;
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        @Override
        public void run() {
            while(this.flag) {
                if (this.scanner.hasNext()) {   // 现在有数据进行输入
                    String val = this.scanner.next().trim() ; // 去掉多余的空格内容
                    System.err.println("{服务器端}" + val);
                    if("byebye".equalsIgnoreCase(val)) {
                        this.out.println("ByeByeByte...");
                        this.flag = false ;
                    } else {
                        out.println("【ECHO】" + val);
                    }
                }
            }
            this.scanner.close();
            this.out.close();
            try {
                this.client.close();
            } catch (IOException e) {
            }
        }
    }
}

BIOEchoClient.java

package com.bijian.bio.client;

import com.bijian.info.HostInfo;
import com.bijian.util.InputUtil;

import java.io.PrintStream;
import java.net.Socket;
import java.util.Scanner;

public class BIOEchoClient {
    public static void main(String[] args) throws Exception {
        Socket client = new Socket(HostInfo.HOST_NAME,HostInfo.PORT) ;  // 定义连接的主机信息
        Scanner scan = new Scanner(client.getInputStream()) ;   // 获取服务器端的响应数据
        scan.useDelimiter("\n") ;
        PrintStream out = new PrintStream(client.getOutputStream()) ; // 向服务器端发送信息内容
        boolean flag = true ; // 交互的标记
        while(flag) {
            String inputData = InputUtil.getString("请输入要发送的内容:").trim() ;
            out.println(inputData); // 把数据发送到服务器端上
            if(scan.hasNext()) {
                String str = scan.next().trim() ;
                System.out.println(str);
            }
            if ("byebye".equalsIgnoreCase(inputData)) {
                flag = false ;
            }
        }
        client.close();
    }
}

  先运行BIOEchoServer.java,再运行BIOEchoClient.java,效果如下:

 

PS:其它知识

  Java基本功:合理的类设计+多线程(JUC)+反射机制+网络通讯+数据结构+JVM

  Shiro、SpringDataJPA、MyBatis、OAuth软件设计方法、Linux使用需要熟练(如果你可以独立的实现一套分布式的认证于授权管理,那么就证明你的水平不低了。

  架构师经常需要精通几门语言。 

  docker+k8s+devops。

 

特别说明:这是开课吧的公开课

posted on 2019-06-15 11:37  bijian1013  阅读(574)  评论(0)    收藏  举报

导航