netty系列3-Java BIO编程

来源:互联网 发布:excel数据抽样 编辑:程序博客网 时间:2024/06/06 20:30

1. BIO特点

网络模型基本的模型是client/server模型,client进程和server进行通信,server端做绑定IP,并绑定端口;client端向服务端监听的地址发起连接请求,通过三次握手建立连接。如果建立成功,双方就可以通过socket进行通信。

Java中的BIO开发流程:
- server:ServerSocket负责绑定ip,启动监听端口
- client:Socket负责发起连接操作
- 连接建立成功之后,双方通过输入和输出流进行通信

2. Java BIO通信模型

2.1 server端主要流程

{    /* 1. 开启监听端口 */    ServerSocket server = new ServerSocket(8080);    while (true) {        /* 2. 监听客户端连接 */        Socket socket = server.accept();        /* 3. 创建线程处理客户端连接 */        new Thread(new TimeServerHandler(socket)).start();    }}

服务端监听客户端连接,每接收到一个连接,就创建一个业务线程来处理具体的请求,然后服务端继续监听客户端连接。

2.2 服务端TimeServerHandler主要逻辑

{    /* 0. socket是来自于服务端接收到的连接 */    /* 1. 构造input和output,分别用于从client读取和发送数据 */    BufferReader in = new BufferReader(new InputStreamReader(socket.getInputStream()));    PrintWriter out = new PrintWriter(socket.getOutputStream(), true);    /* 2. 读取请求内容 */    String body = in.readLine();    /* 3. 发送响应 */    out.println(System.currentTimeMillis());    /* 4. 释放资源 */    out.close();    in.close();    socket.close();}

服务端接收到的连接,业务线程TimeServerHandler主要负责从连接中读取客户端请求,并根据请求发送响应,处理完成请求之后,释放相关的资源。

2.3 client端主要流程:

{    /* 1. 向服务端发起创建连接申请 */    Socket socket = new Socket("127.0.0.1", 8080);    /* 2. 构造inputStream,用于从server端读取数据 */    BufferReader in = new BufferReader(new InputStreamReader(socket.getInputStream()));    /* 3. 构造outputStream,用于向server端发起请求 */    PrintWriter out = new PrintWriter(socket.getOutputStream(), true);    /* 4. 发送请求 */    out.println("QUERY TIME ORDER");    /* 5. 获取相应内容并输出 */    System.out.println("response: " + in.readLine());    /* 6. 释放资源 */    out.close();    in.close();    socket.close();}

客户端主要向服务端发起创建连接申请,并在创建连接之后,发送请求,并接收响应。

3. BIO模型的问题

虽然服务端、客户端编程简单,很容易理解,但是存在一个比较严重的问题是每当有一个新的客户端请求接入时,服务端必须创建一个线程处理新接入的客户端链路,一个线程只能处理一个客户端连接。

在高性能服务器应用领域,往往需要处理成千上万个客户端的并发连接,这种模型显然不能满足高性能、高并发接入的场景。

后面我们会介绍通过线程池或者消息队列实现一个或者多个线程处理N个客户端的伪异步IO模型

4. 源代码

4.1 TimeServer.java

server端监听客户端连接代码:

package com.netease.netty.bio;import java.io.IOException;import java.net.ServerSocket;import java.net.Socket;public class TimeServer {    public static void main(String []args) throws IOException {        int port = 8080;        if (args != null && args.length > 0) {            try {                port = Integer.valueOf(args[0]);            } catch (NumberFormatException e) {                // ...            }        }        ServerSocket server = null;        try {            server = new ServerSocket(port);            System.out.println("timeserver start in port: " + port);            Socket socket = null;            while (true) {                socket = server.accept();                new Thread(new TimeServerHandler(socket)).start();            }         } finally {            if (server != null) {                System.out.println("timeserver close");                server.close();                server = null;            }        }    }}

4.2 TimeServerHandler.java

server端业务代码:

package com.netease.netty.bio;import java.io.BufferedReader;import java.io.InputStreamReader;import java.io.PrintWriter;import java.net.Socket;public class TimeServerHandler implements Runnable {    private Socket socket;    public TimeServerHandler(Socket socket) {        this.socket = socket;    }    @Override    public void run() {        BufferedReader in = null;        PrintWriter out = null;        try {            in = new BufferedReader(new InputStreamReader(this.socket.getInputStream()));            out = new PrintWriter(this.socket.getOutputStream(), true);            String currentTime = null;            String body = null;            while (true) {                body = in.readLine();                if (body == null)                    break;                System.out.println("The time server receive order : " + body);                currentTime = "QUERY TIME ORDER".equalsIgnoreCase(body)                        ? new java.util.Date(System.currentTimeMillis()).toString() : "BAD ORDER!";                out.print(currentTime);            }        } catch (Exception e) {            Utils.releaseAllSource(in, out, this.socket);            in = null;            out = null;            this.socket = null;        }    }}

4.3 TimeClient.java

package com.netease.netty.bio;import java.io.BufferedReader;import java.io.InputStreamReader;import java.io.PrintWriter;import java.net.Socket;public class TimeClient {    public static void main(String []args) {        int port = 8080;        if (args != null && args.length > 0) {            try {                port = Integer.valueOf(args[0]);            } catch (NumberFormatException e) {                /* use default port number. */            }        }        Socket socket = null;        BufferedReader in = null;        PrintWriter out = null;        try {            socket = new Socket("127.0.0.1", port);            in = new BufferedReader(new InputStreamReader(socket.getInputStream()));            out = new PrintWriter(socket.getOutputStream(), true);            out.print("QUERY TIME ORDER");            System.out.println("Send order 2 server succeed");            String resp = in.readLine();            System.out.println("Now is : " + resp);        } catch (Exception e) {            //...        } finally {            Utils.releaseAllSource(in, out, socket);            in = null;            out = null;            socket = null;        }    }}

4.4 Utils.java

工具类,主要释放连接相关的资源:

package com.netease.netty.bio;import java.io.BufferedReader;import java.io.IOException;import java.io.PrintWriter;import java.net.Socket;public class Utils {    public static void releaseAllSource(BufferedReader in, PrintWriter out, Socket socket) {        if (in != null) {            try {                in.close();            } catch (IOException e1) {                e1.printStackTrace();            }        }        if (out != null) {            out.close();        }        if (socket != null) {            try {                socket.close();            } catch (IOException e) {                e.printStackTrace();            }        }    }}

5. ref

  • Netty权威指南
原创粉丝点击