bio定义

BIO (Blocking I/O): 同步阻塞I/O模式,数据的读取写入必须阻塞在一个线程内等待其完成。在活动连接数不是特别高(小于单机1000)的情况下,这种模型是比较不错的,可以让每一个连接专注于自己的 I/O 并且编程模型简单,也不用过多考虑系统的过载、限流等问题。线程池本身就是一个天然的漏斗,可以缓冲一些系统处理不了的连接或请求。但是,当面对十万甚至百万级连接的时候,传统的 BIO 模型是无能为力的。因此,我们需要一种更高效的 I/O 处理模型来应对更高的并发量。

bio实现文件读写

/**
    * BIO模式
    * FileReader逐个字符读取文件,FileReader extends InputStreamReader
    * 读取文件中内容到字符数组中
    * 如何确定字符数组长度:
    * FileReader不能自定义编码读取
    * 此方法也可以用于读取二进制文件,只不过读取出来有很多乱码
    * @param fileName
    * @return
    * @throws IOException
    */
public static char[] readByOneCharWithDefaultEncoding(String fileName) throws IOException{
    File file = new File(fileName);
    FileReader fileReader = new FileReader(file); // 不能自定义编码,内部默认采用系统的编码
    System.out.println("当前采用编码: " + fileReader.getEncoding()); 
    char[] charcters = new char[1024];
    int result = fileReader.read();  // 逐个字符读取,不能按行读取
    int i = 0;
    while(result != -1 && i < 1024){
        char temp = (char)result;
        charcters[i] = temp;
        i++;
        result = fileReader.read();
    }
    fileReader.close();
    return charcters;
}

bio服务器

//BIO服务端源码
public final class ServerNormal {
	//默认的端口号
	private static int DEFAULT_PORT = 12345;
	//单例的ServerSocket
	private static ServerSocket server;
	//根据传入参数设置监听端口,如果没有参数调用以下方法并使用默认值
	public static void start() throws IOException{
		//使用默认值
		start(DEFAULT_PORT);
	}
	//这个方法不会被大量并发访问,不太需要考虑效率,直接进行方法同步就行了
	public synchronized static void start(int port) throws IOException{
		if(server != null) return;
		try{
			//通过构造函数创建ServerSocket
			//如果端口合法且空闲,服务端就监听成功
			server = new ServerSocket(port);
			System.out.println("服务器已启动,端口号:" + port);
			//通过无线循环监听客户端连接
			//如果没有客户端接入,将阻塞在accept操作上。
			while(true){
				Socket socket = server.accept();
				//当有新的客户端接入时,会执行下面的代码
				//然后创建一个新的线程处理这条Socket链路
				new Thread(new ServerHandler(socket)).start();
			}
		}finally{
			//一些必要的清理工作
			if(server != null){
				System.out.println("服务器已关闭。");
				server.close();
				server = null;
			}
		}
	}
}

bio的服务处理handler

/**
 * 客户端线程
 */
public class ServerHandler implements Runnable{
	private Socket socket;
	public ServerHandler(Socket socket) {
		this.socket = socket;
	}
	@Override
	public void run() {
		BufferedReader in = null;
		PrintWriter out = null;
		try{
			in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
			out = new PrintWriter(socket.getOutputStream(),true);
			String expression;
			String result;
			while(true){
				//通过BufferedReader读取一行
				//如果已经读到输入流尾部,返回null,退出循环
				//如果得到非空值,就尝试计算结果并返回
				if((expression = in.readLine())==null) break;
				System.out.println("服务器收到消息:" + expression);
				try{
					result = Calculator.cal(expression).toString();
				}catch(Exception e){
					result = "计算错误:" + e.getMessage();
				}
				out.println(result);
			}
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			//一些必要的清理工作
			if(in != null){
				try {
					in.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
				in = null;
			}
			if(out != null){
				out.close();
				out = null;
			}
			if(socket != null){
				try {
					socket.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
				socket = null;
			}
		}
	}
}

bio客户端

/**
 * 阻塞式I/O创建的客户端
 */
public class Client {
	//默认的端口号
	private static int DEFAULT_SERVER_PORT = 12345;
	private static String DEFAULT_SERVER_IP = "127.0.0.1";
	public static void send(String expression){
		send(DEFAULT_SERVER_PORT,expression);
	}
	public static void send(int port,String expression){
		System.out.println("算术表达式为:" + expression);
		Socket socket = null;
		BufferedReader in = null;
		PrintWriter out = null;
		try{
			socket = new Socket(DEFAULT_SERVER_IP,port);
			in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
			out = new PrintWriter(socket.getOutputStream(),true);
			out.println(expression);
			System.out.println("___结果为:" + in.readLine());
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			//一下必要的清理工作
			if(in != null){
				try {
					in.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
				in = null;
			}
			if(out != null){
				out.close();
				out = null;
			}
			if(socket != null){
				try {
					socket.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
				socket = null;
			}
		}
	}
}