`

java BIO

阅读更多

一、传统的BIO编程

先用BIO实现一个简单功能:

server端:监听,打印客户端发送过来的内容,并将原内容回复给客户端。

客户端:向服务端发送内容,并打印服务端返回的内容。

服务端代码:

 

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
 
public class BioServer {
    private ServerSocket server;
 
    public BioServer(int port) throws IOException {
        server = new ServerSocket(port);
    }
 
    public void listen() throws IOException {
        System.out.println("server started.........................");
        Socket socket = null;
        try {
            while (true) {
                socket = server.accept();
                BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                PrintWriter out = new PrintWriter(new BufferedWriter(
                        new OutputStreamWriter(socket.getOutputStream())), true);
                while (true) {
                    String text = in.readLine();
                    System.out.println("text from client: " + text);
                    out.println(text);
                    if ("exit".equals(text)) {
                        //out.println("exit");
                        socket.close();
                        break;
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            server.close();
        }
    }
 
    public static void main(String[] args) throws IOException {
        BioServer server = new BioServer(9000);
        server.listen();
    }
}

 客户端代码:

 

 

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
 
public class BioClient {
    private Socket socket;
 
    public BioClient(String host, int port) throws UnknownHostException, IOException {
        socket = new Socket(host, port);
 
    }
 
    public void send() throws IOException {
        try {
            PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true);
            out.println("呵呵呵");
            out.println("hello server");
            out.println("哈哈哈");
            out.println("exit");
            out.flush();
            InputStream inputStream=socket.getInputStream();
            BufferedReader in = new BufferedReader(
                        new InputStreamReader(inputStream));
            while (true) {
                String text = in.readLine();
                System.out.println(text);
                if ("exit".equals(text)||"busy".equals(text)) {
                    break;
                }
            }
        } finally {
            socket.close();
        }
    }
 
    public static void main(String[] args) throws UnknownHostException, IOException {
        for (int i = 0; i < 10; i++) {
            new Thread(new Runnable() {
 
                @Override
                public void run() {
                    BioClient client;
                    try {
                        client = new BioClient("127.0.0.1", 9000);
                        client.send();
                    } catch (UnknownHostException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
 
            }).start();
        }
 
    }
}

 这种写法是一个服务线程为多个客户端服务。服务端执行了socket = server.accept()后服务端才能与客户端建立连接,否则客户端一直阻塞等待连接建立,server端没有阻塞在server.accept方法时客户端如果请求连接就会报connection refused异常。当服务端接受了一个客户端的连接就执行22-34行之间的代码开始为客户端服务,服务完成后再继续调用socket = server.accept()并接待下一个客户端。缺点很明显,只要服务端还没有处理完上一个客户端的请求,别的客户端的请求就必须要先阻塞在那里等待。就好像是有一个售票口只有一个售票员,而在外面有一堆等着买票的人一样,只有一个人买到票并离开了,售票员才能为下一个人服务。

 

升级一下程序,使每个客户端都有一个服务线程为其服务:

服务端代码:

 

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
 
public class BioServer {
    private ServerSocket server;
 
    public BioServer(int port) throws IOException {
        server = new ServerSocket(port);
    }
 
    public void listen() throws IOException {
        System.out.println("server started.........................");
        Socket socket = null;
        try {
            while (true) {
                socket = server.accept();
                new Thread(new BioServerThread(socket)).start();
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            server.close();
        }
    }
     
    public static void main(String[] args) throws IOException {
        BioServer server = new BioServer(9000);
        server.listen();
    }
}

 

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
 
public class BioServerThread implements Runnable {
    private Socket socket;
 
    public BioServerThread(Socket socket) throws IOException {
        this.socket = socket;
    }
 
    @Override
    public void run() {
        try {
            BufferedReader in = new BufferedReader(
              new InputStreamReader(socket.getInputStream()));
            PrintWriter out = new PrintWriter(new BufferedWriter(
                    new OutputStreamWriter(socket.getOutputStream())), true);
            while (true) {
                String text = in.readLine();
                System.out.println(Thread.currentThread().getName() + " text from client: " + text);
                out.println(text);
                if ("exit".equals(text)) {
                    //out.println("exit");
                    socket.close();
                    break;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

 这样一来每一个请求服务端都会单独打开一个线程,但是如果客户端同时请求太多,则会同时打开很多线程,可能会达到系统处理能力的上限从而导致系统崩溃。想象一下为每一个买票的人配一个售票员的场景吧/(ㄒoㄒ)/~~。

 

可以通过线程池的方式来解决为每个客户端分配一个线程的问题,通过调节线程池的大小使得性能和响应之间达到一个比较好的平衡。

重写服务端代码:

import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
 
import snailxr.bio.thread.BioServerThread;
 
public class BioServer {
    private ServerSocket server;
    public BioServer(int port) throws IOException {
        server = new ServerSocket(port);
    }
 
    public void listen() throws IOException {
        BlockingQueue<Runnable> block = new ArrayBlockingQueue<Runnable>(100);
        /**
         * 
         * 1)当池子大小小于corePoolSize就新建线程,并处理请求
         * 2)当池子大小等于corePoolSize,把请求放入workQueue中,池子里的空闲线程就去从workQueue中取任务并处理
         * 3)当workQueue放不下新入的任务时,新建线程入池,并处理请求,
         * 如果池子大小撑到了maximumPoolSize就用RejectedExecutionHandler来做拒绝处理
         */
        ThreadPoolExecutor pool = new ThreadPoolExecutor(1, // corePoolSize
                                                            // 池中保存的线程数,包括空闲线程
                2,// maximumPoolSize池中允许的最大线程数
                30, // 当线程数大于核心时,此为终止前 多余的空闲线程等待新任务的最长时间,单位由下个参数设置。
                TimeUnit.MINUTES, // 时间的单位
                block, new RejectedExecutionHandler() {
 
                    @Override
                    public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
                        System.out.println(r.getClass().getName());
                        System.out.println("无法继续提供服务....................");
 
                        try {
 
                            BioServerThread bioServer = (BioServerThread) r;
                            Socket socket = bioServer.getSocket();
                            PrintWriter out = new PrintWriter(new BufferedWriter(
                                    new OutputStreamWriter(socket.getOutputStream())), true);
                            InputStream in=socket.getInputStream();
                            out.println("busy");
                            while(true){
                                if(in.read()<0){
                                    socket.close();//让客户端先关闭
                                    break;
                                }
                            }
                        } catch (IOException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                    }
                });// 任务队列
        System.out.println("server started.........................");
        Socket socket = null;
        try {
            while (true) {
                socket = server.accept();
                BioServerThread thread = new BioServerThread(socket);
                pool.execute(thread);
                System.out.println(pool.getActiveCount());
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            server.close();
            pool.shutdown();
        }
    }
 
    public static void main(String[] args) throws IOException {
        BioServer server = new BioServer(9000);
        server.listen();
    }
}

 通过上面的程序我们可以看到bio的api比较简单,适用于连接数量比较少的架构。即使是使用了多线程去处理建立连接后的操作,但是由于bio程序在read和write时都会阻塞线程,直到有数据可读或可写,对线程资源造成了极大的浪费,所以如果并发要求比较高的话,bio可能不是很好的选择。

 

 

分享到:
评论

相关推荐

    Java BIO Socke示例

    Java BIO (Blocking Input/Output) 是Java标准库中提供的一种基础网络编程模型,它主要用于创建基于TCP/IP的Socket通信服务。在这个"Java BIO Socke示例"中,我们将探讨如何使用Java BIO API来实现简单的Socket通信...

    java BIO NIO AIO

    Java BIO NIO AIO Java BIO、NIO、AIO是 Java 中的三种 I/O 模式,每种模式都有其特点和应用场景。下面对每种模式进行详细解释。 Java BIO Java BIO( Blocking I/O)是一种同步阻塞式的 I/O 模式,即服务器实现...

    WuziGame-JAVA BIO的联机五子棋游戏(客户端+服务器)

    【WuziGame - JAVA BIO的联机五子棋游戏】是一个使用Java编程语言开发的多人在线游戏项目,其中包含了客户端和服务器两部分。在这个游戏中,玩家可以通过网络连接与他人进行实时对战,享受五子棋的乐趣。项目采用BIO...

    基于java的BIO、NIO、AIO通讯模型代码实现

    Java作为一门广泛使用的开发语言,提供了多种I/O(Input/Output)通信模型,包括传统的阻塞I/O(BIO)、非阻塞I/O(NIO)以及异步I/O(AIO)。这些通信模型在不同的场景下有着各自的优势,理解和掌握它们对于优化...

    JAVA BIO AIO NIO测试代码

    对java io总结时编写的测试代码,包括BIO,NIO,AIO的实现,Java io操作是编程人员经常使用到的,以前只是使用没有对这三种IO做系统的了解,本文将对这三种IO作详细的介绍并附有测试完整代码

    Java BIO、NIO、AIO、Netty知识详解(值得珍藏)

    Java中的I/O(输入/输出)机制是程序与...在Java中,这五种模型分别对应BIO、NIO、AIO、传统的异步I/O(如Java的Future)以及基于回调的异步I/O。这些模型的选择取决于应用场景的需求,如连接数、操作类型和性能要求。

    Java使用BIO和NIO进行文件操作对比代码示例

    "Java使用BIO和NIO进行文件操作对比代码示例" Java BIO和NIO是两种不同的输入/输出(IO)模型,在文件操作中发挥着重要作用。BIO(Blocking I/O)是一种同步阻塞IO模式,而NIO(Non-Blocking I/O)是一种同步非阻塞...

    biojava-master

    《生物信息学与BioJava应用详解》 在生物信息学领域,BioJava是一个重要的开源工具,主要用于处理和分析生物学数据。这个名为“biojava-master”的压缩包包含了BioJava的源码以及相关的说明教程,为研究者和开发者...

    BioJava(Java Library)指南

    BioJava是基于Java编程语言的一个开源生物信息学库,它为生物信息学家提供了一系列工具,用于处理和分析生物学数据。这个库涵盖了多个生物信息学领域,包括序列比对、基因组分析、蛋白质结构和功能预测等。下面我们...

    biojava tutorial

    ### BioJava教程详解 #### 一、BioJava简介与应用场景 **BioJava**是一个开源的Java类库集合,旨在为生物序列数据分析的应用程序提供一个框架。它包含了丰富的接口和工具,用于处理生物学序列数据,例如DNA、RNA和...

    biojava-jar

    biojava,bioinformatics tools

    关于bioJava(1)

    **生物信息学与bioJava简介** 在IT领域中,生物信息学是一门结合生物学、计算机科学和统计学的交叉学科,主要关注生命科学数据的处理和分析。在生物信息学中,开发各种软件工具和库是至关重要的,以便对基因序列、...

    关于bioJava(2)

    关于“关于bioJava(2)”的这篇博客,作者可能主要讨论了开源生物信息学工具bioJava的第二部分内容。bioJava是一个用Java语言编写的库,主要用于处理生物学数据,如DNA序列、蛋白质序列等。它为生物信息学家提供了...

    Java IO应届生培训讲义

    Java IO应届生培训讲义是一份面向刚毕业的大学生进行Java IO相关知识的培训资料,它涵盖了Java IO的基础知识、不同的IO模型以及Java中的BIO、NIO和AIO高级IO类库。下面详细解释这些知识点: 1. 用户空间和内核空间 ...

    biojava使用指南及部分程序开发

    BioJava是一个开源项目,它提供了一系列用于处理生物信息学数据的Java类库。BioJava的目标是让程序员能够更容易地分析生物序列数据,如DNA、RNA和蛋白质序列,并执行与序列分析相关的其他任务,如模式搜索、结构预测...

    biojava.jar

    这是biojava的jar包,另外回上传源代码的,由于文件太大所以不能一块上传

    BioJava 生物信息学

    BioJava 的设计涵盖了生物信息学的很多方面的编程

    一站式学习Java网络编程 全面理解BIO:NIO:AIO1

    全面理解 Java 网络编程 - BIO、NIO、AIO 本课程旨在帮助学生全面理解 Java 网络编程中的 BIO、NIO、AIO 三剑客,掌握 RPC 编程的基础知识,并结合实战项目巩固所学。 一、网络编程三剑客 - BIO、NIO、AIO BIO...

    biojava.jar使用说明书

    biojava.jar使用说明书,英文版本。请大家看好再下!

    java socket Bio Nio example

    在Java中,Socket主要分为两种模式:BIO(Blocking I/O)和NIO(Non-blocking I/O)。这两个模式分别有不同的应用场景和优缺点。 **一、Java Socket BIO** BIO,即阻塞I/O模型,是Java最初提供的网络通信方式。在...

Global site tag (gtag.js) - Google Analytics