上一节我们对 Java 的 BIO 编程进行了理论上的讲解,我们知道了 Java BIO 就是一请求一处理。它需要有客户端和服务端。网络通信,我们就用到了 Socket。
我们新建两个 java 项目,一个是服务端,一个是客户端。代码结构如下:
服务端:
客户端:
package net.haicoder.server;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class BioServer {
public static void main(String[] args) {
int port = 9999;
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(port);
//一直监听,是否有客户端请求过来
while (true) {
Socket socket = serverSocket.accept();
//每次都会新建一个线程,来处理接收到到请求
new Thread(new SocketHandler(socket)).start();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (serverSocket != null) {
try {
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
serverSocket = null;
}
}
}
static class SocketHandler implements Runnable {
Socket socket = null;
public SocketHandler(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
BufferedReader reader = null;
PrintWriter writer = null;
try {
//读取数据,BIO 是面向流到,所以定义流 BufferedReader 来读取数据
reader = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8"));
//将收到的数据返回给客户端
writer = new PrintWriter(new OutputStreamWriter(socket.getOutputStream(), "UTF-8"));
String readMessage = null;
while (true) {
if ((readMessage = reader.readLine()) == null) {
break;
}
System.out.println("server reading ........" + readMessage);
//将数据返回给客户端
writer.println("server recive : " + readMessage);
writer.flush();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
socket = null;
}
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
reader = null;
}
if (writer != null) {
writer.close();
writer = null;
}
}
}
}
}
package net.haicoder.client;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;
public class BioClient {
public static void main(String[] args) {
//服务端到 ip 地址
String host = "127.0.0.1";
//和服务端到端口号一致
int port = 9999;
Socket socket = null;
BufferedReader reader = null;
PrintWriter writer = null;
//接收键盘输入数据
Scanner scanner = new Scanner(System.in);
try {
socket = new Socket(host, port);
String message = null;
reader = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8"));
writer = new PrintWriter(socket.getOutputStream(), true);
while (true) {
message = scanner.nextLine();
if (message.equals("exit")) {
break;
}
//数据发送服务端
writer.println("客户端输入:" + message);
writer.flush();
System.out.println(reader.readLine());
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
socket = null;
}
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
reader = null;
}
if (writer != null) {
writer.close();
writer = null;
}
}
}
}
项目启动的时候,我们先启动服务端,再启动客户端。如果先启动客户端,会报连接拒绝异常。因为服务端启动的时候,需要知道服务端的地址和端口号。然后在客户端输入 你好,嗨客网!
效果如下
客户端输出
服务端输出
这样,客户端和服务端就通信了,我们看到服务端和客户端一直没有退出,一直启动着。
我们知道,伪异步 IO 是将 server 端的线程处理,维护到线程池当中,客户端不会改变,所以我们就改变一下 Server 端的代码即可,代码如下:
package net.haicoder.server;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class BioThreadPoolServer {
public static void main(String[] args) {
int port = 9999;
ServerSocket serverSocket = null;
ExecutorService service = Executors.newFixedThreadPool(50);
try {
serverSocket = new ServerSocket(port);
//一直监听,是否有客户端请求过来
while (true) {
Socket socket = serverSocket.accept();
//每次都会新建一个线程,来处理接收到到请求
service.execute(new SocketHandler(socket));
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (serverSocket != null) {
try {
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
serverSocket = null;
}
}
}
static class SocketHandler implements Runnable {
Socket socket = null;
public SocketHandler(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
BufferedReader reader = null;
PrintWriter writer = null;
try {
//读取数据,BIO 是面向流到,所以定义流 BufferedReader 来读取数据
reader = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8"));
//将收到的数据返回给客户端
writer = new PrintWriter(new OutputStreamWriter(socket.getOutputStream(), "UTF-8"));
String readMessage = null;
while (true) {
if ((readMessage = reader.readLine()) == null) {
break;
}
System.out.println("server reading ........" + readMessage);
//将数据返回给客户端
writer.println("server recive : " + readMessage);
writer.flush();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
socket = null;
}
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
reader = null;
}
if (writer != null) {
writer.close();
writer = null;
}
}
}
}
}
本章节,我们将 socket 的 BIO 编程的客户端和服务端代码编写,将运行效果展示。客户端每输入一次请求,服务端都会处理,然后再回写给客户端。我们也将伪异步 IO 端代码列出。执行效果和 Server 端的代码一样的,有兴趣的同学可以按照上面的代码试一下,找一下感觉。