准备抽时间深入学习netty,在此之前先回顾BIO 扫清NIO盲点,本篇先回顾一下BIO
传统的socket编程是BIO即阻塞,因此为了对并发的支持,传统的BIO模型只能每个线程都封装一个socket,以达到支持并发的效果
下面我们上一段模拟向一个服务端并发发起请求的代码,基于Socket阻塞IO模型实现
服务端SocketServer:
package cn.qu.socket;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/*
服务器端:
① 创建ServerSocket对象,绑定监听端口
② 通过accept()方法监听客户端请求
③ 连接建立后,通过输入流读取客户端发送的请求信息
④ 通过输出流向客户端发送乡音信息
⑤ 关闭相关资源
*/
public class SocketServer {
final static int port = 8081;
private static ServerSocket serverSocket = null;
private static ExecutorService fixedThreadExecutor = Executors.newFixedThreadPool(2);
public static void main(String[] args) {
start();
}
public static void start() {
try {
serverSocket = new ServerSocket(port);
System.out.println("........SocketServer.start..........");
while (true) {
Socket socket = serverSocket.accept();
fixedThreadExecutor.execute(() -> {
try {
Thread.sleep(50);
String addr = socket.getInetAddress().getHostAddress() + ":" + socket.getPort();
System.out.println(addr + " 发起请求");
System.out.println(Thread.currentThread().getName() + "->" + System.currentTimeMillis());
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String line = "";
while (!"".equals((line = reader.readLine())) && line != null) {
System.out.print(line);
}
System.out.println();
System.out.println();
socket.shutdownInput();
OutputStream out = socket.getOutputStream();
out.write("来自SocketServer response".getBytes());
socket.shutdownOutput();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if(!socket.isClosed()) {
socket.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
以上代码大致逻辑介绍如下:
1.构建ServerSocket绑定到8081端口
2.循环监听ServerSocket
3.如果有请求建立socket连接,则异步处理
4.打印请求内容,取消输入阻塞
5.对请求进行回应,取消输出阻塞
6.关闭socket。
客户端SocketClient:
package cn.qu.socket;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
/*
Socket通信的步骤
① 创建ServerSocket和Socket
② 打开连接到Socket的输入/输出流
③ 按照协议对Socket进行读/写操作
④ 关闭输入输出流、关闭Socket
*/
public class SocketClient {
final static int listenerPort = 8081;
final static String listenerInet4Address = "127.0.0.1";
public static void main(String[] args) {
for(int i = 0; i < 4; i ++) {
start(8091 + i, "SocketClient say hello");
}
}
private static void start(int port, String data) {
Socket socket = null;
try {
socket = new Socket(listenerInet4Address, listenerPort, InetAddress.getByName(listenerInet4Address), port);
OutputStream out = socket.getOutputStream();
out.write(data.getBytes());
socket.shutdownOutput();
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String line = "";
while (!"".equals((line = reader.readLine())) && line != null) {
System.out.print(line);
}
System.out.println();
socket.shutdownInput();
}catch (Exception e) {
e.printStackTrace();
}finally {
try {
if(!socket.isClosed()) {
socket.close();
}
} catch (IOException e) {
}
}
}
}
以上代码大致逻辑介绍如下:
1.并发创建socket连接,4个参数:远程服务IP,远程服务端口,当前服务IP,当前服务端口
2.向服务端发起请求,并关闭输出阻塞
3.接收服务端的响应,并关闭输入阻塞
4.关闭socket连接