Socket之阻塞IO(BIO)

366 阅读2分钟

Socket是在应用层和传输层之间的一个抽象层,它把TCP/IP层复杂的操作抽象为几个简单的接口供应用层调用以实现进程在网络中通信。socket是一组接口,在设计模式中,socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在socket接口后面,对用户来说,一组简单的接口就是全部,让socket去组织数据,以符合指定的协议。

参考:

再上一张图,其实跟上图一样:

DEMO测试

  • Server端
public class ServerSocketDemo {

    static ExecutorService executorService= Executors.newFixedThreadPool(20);

    public static void main(String[] args) {
        ServerSocket serverSocket=null;
        try {
            //localhost: 8080
            serverSocket=new ServerSocket(8080);
            while(true) {
            	/**
                 * 监听客户端连接(连接阻塞)
                 * 有客户端请求过来,就产生一个Socket对象,并继续执行。
                 /
                Socket socket = serverSocket.accept(); 
                System.out.println(socket.getPort());
                executorService.execute(new SocketThread(socket)); //异步
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //TODO
            if(serverSocket!=null){
                try {
                    serverSocket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

public class SocketThread implements Runnable{

    private Socket socket;
    
    public SocketThread(Socket socket) {
        this.socket = socket;
    }

    @Override
    public void run() {
        try {
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));//输入流
            String s = bufferedReader.readLine(); //被阻塞了
            String clientStr = s; //读取客户端的一行数据
            System.out.println("接收到客户端的信息:" + clientStr);
            //写回去
            BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
            bufferedWriter.write("我收到了信息\n");
            bufferedWriter.flush();

            bufferedReader.close();
            bufferedWriter.close();
        }catch (Exception e){

        }
    }
}

  • Client端:
public class SocketClientDemo {

    public static void main(String[] args) {
        try {
            Socket socket=new Socket("localhost",8080);
            Thread.sleep(50000);
            BufferedWriter bufferedWriter=new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
            bufferedWriter.write("我是客户端,发送了一个消息\n");
            bufferedWriter.flush();
            BufferedReader bufferedReader=new BufferedReader(new InputStreamReader(socket.getInputStream()));//输入流
            String serverLine=bufferedReader.readLine(); //读取服务端返回的数据(被阻塞了)
            System.out.println("服务端返回的数据:"+serverLine);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

上述案例其实都是 阻塞IO(BIO) 的一个demo,阻塞IO是

  • 连接阻塞 serverSocket.accept()
  • IO阻塞 bufferedReader.readLine()

所以引入了线程池来优化,比如本案列的线程池使用。 但是线程池也有瓶颈,比如设置20个线程(Executors.newFixedThreadPool(20)),线程池的队列大小是1000,如果同时来了1000000个请求,那么大量的请求都会丢失掉!!!关于线程池队列这块,参考文章:线程池队列设置多少

所以就引入了 非阻塞IO(NIO)