目录
BIO网络编程
基本的服务端和客户端,Socket+IO。
out.write(msg.getBytes(charset)); // 阻塞,写完成
serverSocket.accept();//阻塞
reader.readLine();// 没有数据,阻塞
出现的问题:因为服务端有阻塞线程的操作,所以在没处理完之前,只能阻塞线程,即同时只能处理一个请求和一个请求的数据。
//客户端
public class BIOClient {
private static Charset charset = Charset.forName("UTF-8");
public static void main(String[] args) throws Exception {
Socket s = new Socket("localhost", 8080);
OutputStream out = s.getOutputStream();
Scanner scanner = new Scanner(System.in);
System.out.println("请输入:");
String msg = scanner.nextLine();
out.write(msg.getBytes(charset)); // 阻塞,写完成
scanner.close();
s.close();
}
}
//服务端
public class BIOServer {
public static void main(String[] args) throws Exception {
ServerSocket serverSocket = new ServerSocket(8080);
System.out.println("服务器启动成功");
while (!serverSocket.isClosed()) {
Socket request = serverSocket.accept();// 阻塞
System.out.println("收到新连接 : " + request.toString());
try {
// 接收数据、打印
InputStream inputStream = request.getInputStream(); // net + i/o
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "utf-8"));
String msg;
while ((msg = reader.readLine()) != null) { // 没有数据,阻塞
if (msg.length() == 0) {
break;
}
System.out.println(msg);
}
System.out.println("收到数据,来自:"+ request.toString());
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
request.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
serverSocket.close();
}
}
利用多线程技术,解决socketServer线程阻塞的问题。
目的:使BIOServer不阻塞。
通过多线程进行多客户端连接。
reader.readLine()这里会阻塞,所以这里创建一个线程来处理,即可以接收后来的请求,BIOServer线程不会阻塞。
并发大小受限于线程池的大小。
// 多线程支持
public class BIOServer1 {
private static ExecutorService threadPool = Executors.newCachedThreadPool();
public static void main(String[] args) throws Exception {
ServerSocket serverSocket = new ServerSocket(8080);
System.out.println("tomcat 服务器启动成功");
while (!serverSocket.isClosed()) {
Socket request = serverSocket.accept();
System.out.println("收到新连接 : " + request.toString());
threadPool.execute(() -> {
try {
// 接收数据、打印
InputStream inputStream = request.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "utf-8"));
String msg;
while ((msg = reader.readLine()) != null) { // 阻塞
if (msg.length() == 0) {
break;
}
System.out.println(msg);
}
System.out.println("收到数据,来自:"+ request.toString());
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
request.close();
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
serverSocket.close();
}
}
Http协议
- 请求数据包解析
- 响应数据包解析
- 状态码
Socket+IO和浏览器进行交互
在浏览器访问可以访问BIOServer2。
此过程可以理解为协议开发的过程,在socket之上支持更多功能,TCP之上运用更多协议。
public class BIOServer2 {
private static ExecutorService threadPool = Executors.newCachedThreadPool();
public static void main(String[] args) throws Exception {
ServerSocket serverSocket = new ServerSocket(8080);
System.out.println("服务器启动成功");
while (!serverSocket.isClosed()) {
Socket request = serverSocket.accept();
System.out.println("收到新连接 : " + request.toString());
threadPool.execute(() -> {
try {
// 接收数据、打印
InputStream inputStream = request.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "utf-8"));
String msg;
while ((msg = reader.readLine()) != null) {
if (msg.length() == 0) {
break;
}
System.out.println(msg);
}
System.out.println("收到数据,来自:"+ request.toString());
// 响应结果 200
OutputStream outputStream = request.getOutputStream();
outputStream.write("HTTP/1.1 200 OK\r\n".getBytes());
outputStream.write("Content-Length: 11\r\n\r\n".getBytes());
outputStream.write("Hello World".getBytes());
outputStream.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
request.close();
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
serverSocket.close();
}
}
小结:
支持应用级开发,更强大的功能,直接使用socket是不支持的,所以需要用更高级的协议,请求数据,响应数据,都要基于此协议的开发。
BIO - 阻塞IO的含义
阻塞和非阻塞式描述怎么样拿资源,同步和异步是表示拿到资源后如何去处理的,两者不相冲突。即可以做成同步阻塞IO,和异步阻塞IO等组合方式。
操作低筒底层API中,socket操作都是阻塞的。