Netty杂记1—BIO网络编程

前言

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

在传统的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();
    }
复制代码
第二版

使用死循环,保证能够一直处理请求。app

缺点:socket

  • 虽然能够处理屡次请求,可是全部的请求都是依次执行,并非实际意义上的并发处理,也就是说没有实现高并发
  • 串行执行若是第一个请求没有处理结束,不能够处理第二个请求

升级方向:多线程ide

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();
            }
        }

    }

}
复制代码

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

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

相关文章
相关标签/搜索