网络编程的基本模型是Client/Server模型,也就是两个进程之间进行相互通信,其中服务端提供位置信息(绑定的IP地址和监听端口),客户端通过连接操作向服务器监听的地址发起连接请求,如果连接建立成功 ,双方就可以通过Socket进行通信。
在传统的BIO网络编程中,ServerSocket负责绑定IP地址,启动监听端口;Socket负责发起连接操作。连接成功之后,双方通过输入和输出流进行同步阻塞式通信。
下面我们会一步一步的实现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(); } }
多线程处理 一旦有请求过来就交给一个新的线程处理 缺点:
改进方向:使用线程池
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(); } } } }
我不能保证每一个地方都是对的,但是可以保证每一句话,每一行代码都是经过推敲和斟酌的。希望每一篇文章背后都是自己追求纯粹技术人生的态度。
永远相信美好的事情即将发生。