网络编程中,服务端提供IP和监听端口,客户端经过服务端的IP和端口发送请求,进行通讯。这篇是讲传统的同步阻塞模型--BIO。java
BioClient主要是建立一个Socket,并经过Socket把请求发送服务端,代码以下:编程
public class BioClient { public static void main(String[] args) { try { // 经过服务IP,端口建立一个Socket Socket socket = new Socket(Const.IP, Const.PORT); // 获取Socket输出流 OutputStream outputStream = socket.getOutputStream(); // 输出流 outputStream.write("hello world".getBytes()); // 关闭流 outputStream.close(); // 关闭Socket socket.close(); } catch (IOException e) { e.printStackTrace(); } } }
服务端先建立一个ServerSocket,用于监听指定端口的链接请求。accept方法会一直阻塞,直到新的链接创建,创建后,建立一个Socket与客户端进行通讯。在读取输入流的时候,br.readLine()也是阻塞的。服务器
public class BioServer { public static void main(String[] args) { try { //获取ServerSocket,绑定服务器的端口 ServerSocket serverSocket = new ServerSocket(Const.PORT); while (true) { // 建立一个Socket接收链接 Socket socket = serverSocket.accept(); // 获取输入流 InputStream inputStream = socket.getInputStream(); BufferedReader br = new BufferedReader(new InputStreamReader(inputStream)); String message; while (null != (message = br.readLine())) { System.out.println(message); } // 关闭流 inputStream.close(); socket.close(); } } catch (IOException e) { e.printStackTrace(); } } }
在上面的实例中,有个比较大的缺点,就是同时只能处理一个链接,要想处理多个并发客户端,咱们能够简单地用多线程来管理,每次有新的sockert,建立一个线程或则放入线程池来处理。
咱们把sockert的部分抽出来:网络
public class BioServerHandler implements Runnable { private Socket socket; public BioServerHandler(Socket socket) { this.socket = socket; } @Override public void run() { try { // 获取输入流 InputStream inputStream = socket.getInputStream(); BufferedReader br = new BufferedReader(new InputStreamReader(inputStream)); String message; while (null != (message = br.readLine())) { System.out.println(message); } // 关闭流 inputStream.close(); socket.close(); } catch (IOException e) { e.printStackTrace(); } } }
建立线程的方式:多线程
public class BioServer2 { public static void main(String[] args) { try { //获取ServerSocket,绑定服务器的端口 ServerSocket serverSocket = new ServerSocket(Const.PORT); while (true) { // 建立一个Socket接收链接 Socket socket = serverSocket.accept(); new Thread(new BioServerHandler(socket)).start(); } } catch (IOException e) { e.printStackTrace(); } } }
建立线程池的方式:并发
public class BioServer3 { private static ExecutorService executorService = Executors.newFixedThreadPool(5); public static void main(String[] args) { try { //获取ServerSocket,绑定服务器的端口 ServerSocket serverSocket = new ServerSocket(Const.PORT); while (true) { // 建立一个Socket接收链接 Socket socket = serverSocket.accept(); executorService.execute(new BioServerHandler(socket)); } } catch (IOException e) { e.printStackTrace(); } } }
BioServer2和BioServer3经过线程,能够比BioServer同时处理更多的客户端请求,可是依然存在着不足:在任什么时候候,都有大量的线程处于休眠状态,只能等待输入或则输出数据就绪,浪费资源。为此,java提供了另一直方式-NIO。socket