博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Netty杂记1—BIO网络编程
阅读量:7004 次
发布时间:2019-06-27

本文共 8567 字,大约阅读时间需要 28 分钟。

前言

网络编程的基本模型是Client/Server模型,也就是两个进程之间进行相互通信,其中服务端提供位置信息(绑定的IP地址和监听端口),客户端通过连接操作向服务器监听的地址发起连接请求,如果连接建立成功 ,双方就可以通过Socket进行通信。

在传统的BIO网络编程中,ServerSocket负责绑定IP地址,启动监听端口;Socket负责发起连接操作。连接成功之后,双方通过输入和输出流进行同步阻塞式通信。

下面我们会一步一步的实现BIO的网络编程,并且对代码进行不断的修改和优化。

BIO网络编程

正如上文所言,进行BIO网络编程需要Server和Client,客户端我们只编写一个版本,保证能够向服务器发送请求,而服务端我们会从最基本的只能够进行一次请求处理的版本开始,不断的完善。

客户端

package nio;import java.io.*;import java.net.InetSocketAddress;import java.net.Socket;public class BIOClient {    public static void main(String[] args) throws Exception{        for (int i=0;i<=99;i++){            System.out.println(sendMsg("你好"+i));        }    }    public static String sendMsg(String msg) throws Exception{        //        创建socket 只负责发送请求 不需要监听        Socket socket = new Socket();//        连接服务器        socket.connect(new InetSocketAddress("localhost",9999));//        写入数据给服务器        OutputStream outputStream = socket.getOutputStream();//        java 基础的IO操作        PrintWriter printWriter = new PrintWriter(outputStream);        printWriter.println(msg);        printWriter.flush();//        关闭输出流        socket.shutdownOutput();//        接受服务器的响应信息        InputStream inputStream = socket.getInputStream();//        java 基础的IO操作        InputStreamReader inputStreamReader = new InputStreamReader(inputStream);        BufferedReader bufferedReader = new BufferedReader(inputStreamReader);        StringBuffer stringBuffer = new StringBuffer();        String value = null;        while ((value=bufferedReader.readLine())!=null){            stringBuffer.append(value);        }        socket.close();        return "客户端收到:"+ stringBuffer.toString();    }}复制代码

服务端

第一版

服务器启动一次就关闭

优化方向:保证能够连续的处理请求

public static void test1() throws Exception{        //        创建一个ServerSocket        ServerSocket ss = new ServerSocket();//        绑定服务器监听端口        ss.bind(new InetSocketAddress(9999));        //代表服务器和客户端的会话 (InputStream = HttpServletRequest | OutputStream = HttpServletResponse)//      socket阻塞的  accept会监听有没有请求        System.out.println("我在9999监听");        Socket socket = ss.accept();        System.out.println("请求处理");        //获取请求数据 InputStream        InputStream inputStream = socket.getInputStream();//        java 基础的IO操作        InputStreamReader inputStreamReader = new InputStreamReader(inputStream);        BufferedReader bufferedReader = new BufferedReader(inputStreamReader);        StringBuffer stringBuffer = new StringBuffer();        String value = null;        while ((value=bufferedReader.readLine())!=null){            stringBuffer.append(value);        }        System.out.println("服务器收到:"+ stringBuffer.toString());//        获取响应 OutputStream        OutputStream outputStream = socket.getOutputStream();//        java 基础的IO操作        PrintWriter printWriter = new PrintWriter(outputStream);        printWriter.println("你好,我是服务器");        printWriter.flush();//        关闭资源        socket.close();    }复制代码
第二版

使用死循环,保证可以一直处理请求。

缺点:

  • 虽然可以处理多次请求,但是所有的请求都是依次执行,并不是实际意义上的并发处理,也就是说没有实现高并发
  • 串行执行如果第一个请求没有处理结束,不可以处理第二个请求

升级方向:多线程

public static void test2() throws Exception{        //        创建一个ServerSocket        ServerSocket ss = new ServerSocket();//        绑定服务器监听端口        ss.bind(new InetSocketAddress(9999));        //代表服务器和客户端的会话 (InputStream = HttpServletRequest | OutputStream = HttpServletResponse)//      socket阻塞的  accept会监听有没有请求        while (true){            System.out.println("我在9999监听");            Socket socket = ss.accept();            System.out.println("请求处理");            //获取请求数据 InputStream            InputStream inputStream = socket.getInputStream();//        java 基础的IO操作            InputStreamReader inputStreamReader = new InputStreamReader(inputStream);            BufferedReader bufferedReader = new BufferedReader(inputStreamReader);            StringBuffer stringBuffer = new StringBuffer();            String value = null;            while ((value=bufferedReader.readLine())!=null){                stringBuffer.append(value);            }            System.out.println("服务器收到:"+ stringBuffer.toString());//        获取响应 OutputStream            OutputStream outputStream = socket.getOutputStream();//        java 基础的IO操作            PrintWriter printWriter = new PrintWriter(outputStream);            printWriter.println("你好,我是服务器");            printWriter.flush();//        关闭资源            socket.close();        }    }复制代码
版本三

多线程处理 一旦有请求过来就交给一个新的线程处理 缺点:

  • 虽然实现了线程并发处理,但是并没有对线程创建做限制,如果每次处理10秒,并发量10万,服务器会阻塞成千上万个线程
  • 直接new线程比较耗费系统的资源,在高并发服务器中会使用多线程,不可能无限制的new线程,会耗尽服务器的资源

改进方向:使用线程池

public static void test3() throws Exception{        //        创建一个ServerSocket        ServerSocket ss = new ServerSocket();//        绑定服务器监听端口        ss.bind(new InetSocketAddress(9999));        //代表服务器和客户端的会话 (InputStream = HttpServletRequest | OutputStream = HttpServletResponse)//      socket阻塞的  accept会监听有没有请求        while (true){            System.out.println("我在9999监听");            Socket socket = ss.accept();//            多线程处理 一旦有请求过来就交给一个新的线程处理            SocketProcessRunable socketProcessRunable = new SocketProcessRunable(socket);            Thread thread = new Thread(socketProcessRunable);            thread.start();        }    }class SocketProcessRunable implements Runnable{    private Socket socket;    public SocketProcessRunable(Socket socket){        this.socket = socket;    }    @Override    public void run() {        try {            Thread.sleep(1000);            //获取请求数据 InputStream            InputStream inputStream = socket.getInputStream();//        java 基础的IO操作            InputStreamReader inputStreamReader = new InputStreamReader(inputStream);            BufferedReader bufferedReader = new BufferedReader(inputStreamReader);            StringBuffer stringBuffer = new StringBuffer();            String value = null;            while ((value=bufferedReader.readLine())!=null){                stringBuffer.append(value);            }            System.out.println("服务器收到:"+ stringBuffer.toString());//        获取响应 OutputStream            OutputStream outputStream = socket.getOutputStream();//        java 基础的IO操作            PrintWriter printWriter = new PrintWriter(outputStream);            printWriter.println("你好,我是服务器");            printWriter.flush();        }catch (Exception e){            e.printStackTrace();        }finally {            try {                socket.close();            } catch (IOException e) {                e.printStackTrace();            }        }    }}复制代码
版本四

使用线程池管理线程

public static void main(String[] args) throws Exception{//        创建线程池 Executors创建线程的缺点        ExecutorService executorService = Executors.newFixedThreadPool(10);        //        创建一个ServerSocket        ServerSocket ss = new ServerSocket();//        绑定服务器监听端口        ss.bind(new InetSocketAddress(9999));        //代表服务器和客户端的会话 (InputStream = HttpServletRequest | OutputStream = HttpServletResponse)//      socket阻塞的  accept会监听有没有请求        while (true){            System.out.println("我在9999监听");            Socket socket = ss.accept();//            多线程处理 一旦有请求过来就交给一个新的线程处理            SocketProcessRunable socketProcessRunable = new SocketProcessRunable(socket);//           将任务交给线程池处理            executorService.submit(socketProcessRunable);        }    }class SocketProcessRunable implements Runnable{    private Socket socket;    public SocketProcessRunable(Socket socket){        this.socket = socket;    }    @Override    public void run() {        try {            Thread.sleep(1000);            //获取请求数据 InputStream            InputStream inputStream = socket.getInputStream();//        java 基础的IO操作            InputStreamReader inputStreamReader = new InputStreamReader(inputStream);            BufferedReader bufferedReader = new BufferedReader(inputStreamReader);            StringBuffer stringBuffer = new StringBuffer();            String value = null;            while ((value=bufferedReader.readLine())!=null){                stringBuffer.append(value);            }            System.out.println("服务器收到:"+ stringBuffer.toString());//        获取响应 OutputStream            OutputStream outputStream = socket.getOutputStream();//        java 基础的IO操作            PrintWriter printWriter = new PrintWriter(outputStream);            printWriter.println("你好,我是服务器");            printWriter.flush();        }catch (Exception e){            e.printStackTrace();        }finally {            try {                socket.close();            } catch (IOException e) {                e.printStackTrace();            }        }    }}复制代码

我不能保证每一个地方都是对的,但是可以保证每一句话,每一行代码都是经过推敲和斟酌的。希望每一篇文章背后都是自己追求纯粹技术人生的态度。

永远相信美好的事情即将发生。

转载地址:http://nnytl.baihongyu.com/

你可能感兴趣的文章