1、传统的BIO编程
网络编程的基本模型是Server/Client模型,也就是两个进程直接进行相互通信,其中服务端提供配置信息(绑定的IP地址和监听的端口),客户端通过连接操作向服务端监听的地址发送连接请求,通过三次握手建立连接,如果连接成功,则双方即可进行通信(网络套接字Socket)。
2、传统的BIO实现通讯的方式及优缺点
2.1 服务端单线程形式
BIO的B即blocking,阻塞的意思,那么阻塞的点在哪呢?
server.accept();
:服务端程序会一直阻塞在此处,直到有一个客户端连接过来(客户端程序存在此阻塞点)
reader.readLine();
:服务端程序会一直阻塞在此处,直到客户端发送消息过来
同一时刻,只能处理一个客户端请求
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
| package com.example.part_01_bio.demo001;
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket;
public class Server {
public static final Integer PORT = 8899;
public static void main(String[] args) throws Exception {
ServerSocket server = new ServerSocket(PORT); while (true) { Socket client = server.accept(); handle(client); }
}
private static void handle(Socket client) { try { BufferedReader reader = new BufferedReader(new InputStreamReader(client.getInputStream())); PrintWriter writer = new PrintWriter(client.getOutputStream(), true);
while (true) { String request = reader.readLine(); if (request == null) { break; } System.out.println("server accept:" + request);
writer.println("response:" + request); } } catch (Exception e) { e.printStackTrace(); } finally { if (client != null) { try { client.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| package com.example.part_01_bio.demo001;
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.Socket; import java.net.UnknownHostException;
public class Client {
public static void main(String[] args) { Socket client = null;
try { client = new Socket("127.0.0.1", Server.PORT); PrintWriter writer = new PrintWriter(client.getOutputStream(), true); writer.println("request");
BufferedReader reader = new BufferedReader(new InputStreamReader(client.getInputStream())); String request = reader.readLine(); System.out.println("client accept:" + request); } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { if (client != null) { try {
client.close(); } catch (IOException e) { e.printStackTrace(); } } }
} }
|
2.2 服务端多线程形式
此方式是在服务端接收到一个客户端请求后,直接启动一个线程去处理这个请求,具体的处理过程,服务端不参与,服务端只是负责接收客户端的连接。因此,这种方式可以解决2.1中的同一时刻只能处理一个客户端请求的问题。
但是这种方式存在另一个问题,就是假如同一时刻有大量的客户端建立连接,则服务端需要创建大量的线程去处理这些请求,势必造成性能问题。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
| package com.example.part_01_bio.demo001;
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket;
public class Server2 {
public static final Integer PORT = 8899;
public static void main(String[] args) throws Exception {
ServerSocket server = new ServerSocket(PORT); while (true) { Socket client = server.accept(); new Thread(new Runnable() {
@Override public void run() { handle(client); } }).start(); }
}
private static void handle(Socket client) { try { BufferedReader reader = new BufferedReader(new InputStreamReader(client.getInputStream())); PrintWriter writer = new PrintWriter(client.getOutputStream(), true);
while (true) { String request = reader.readLine(); if (request == null) { break; } System.out.println("server accept:" + request);
writer.println("response:" + request); } } catch (Exception e) { e.printStackTrace(); } finally { if (client != null) { try { client.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
|
2.3 服务端线程池形式
这种方式采用线程池技术来管理线程,解决了2.2中高并发情况下大量创建线程的问题。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
| package com.example.part_01_bio.demo001;
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors;
public class Server3 {
public static final Integer PORT = 8899;
public static void main(String[] args) throws Exception {
ExecutorService threadPool = Executors.newFixedThreadPool(10);
ServerSocket server = new ServerSocket(PORT); while (true) { Socket client = server.accept(); threadPool.execute(new Runnable() {
@Override public void run() { handler(client); } }); }
}
private static void handler(Socket client) { try { BufferedReader reader = new BufferedReader(new InputStreamReader(client.getInputStream())); PrintWriter writer = new PrintWriter(client.getOutputStream(), true);
while (true) { String request = reader.readLine(); if (request == null) { break; } System.out.println("server accept:" + request);
writer.println("response:" + request); } } catch (Exception e) { e.printStackTrace(); } finally { if (client != null) { try { client.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
|