1 概要
- 本文主要讨论BIO模型下,客户端和服务端如何进行交互;
- 同时遗留一个问题,暂时无解,待以后解决,如果有大神能指点迷津,不胜感激。
所以 socket的连接、读、写都会阻塞住。
2.2 优点
在早期,这种模型也是很好用的。
2.3 缺点
BIO模式下,为了增加服务端的并发, 一个客户端请求往往单开一个线程,而不是占用服务端的主线程。即便是这种情况,服务端的并发量也是捉襟见肘,因为一旦客户端不发送消息了,服务端的一个线程也是阻塞,而不是关闭;也占用资源。
3 具体实现 3.0 代码实现逻辑
客户端发请求,服务端接收请求;服务端接收请求后,在发给客户端一个响应请求;以此往复;
文章图片
3.1 使用原生的InputStream
3.1.1 Server
public static void main(String[] args) {
try (ServerSocket serverSocket = new ServerSocket(8899)) {
Socket accept = serverSocket.accept();
while (true) {
System.out.println("服务端 收到客户端的请求地址:" + accept.getInetAddress());
while (Objects.nonNull(accept)) {
System.out.println(111);
InputStream in = accept.getInputStream();
byte[] bytes = new byte[1024];
int length = 0;
while ((length = in.read(bytes)) != -1) {
System.out.println("msg from client : " + new String(bytes, 0, length));
}
System.out.println(" server read msg over");
OutputStream outputStream = accept.getOutputStream();
String msg = "hello client, I am from Server";
outputStream.write(msg.getBytes(StandardCharsets.UTF_8));
outputStream.flush();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
3.1.2 Client
public static void main(String[] args) {
try (Socket socket = new Socket("localhost", 8899)) {
while (true) {
OutputStream ois = socket.getOutputStream();
String hello = "hello server ,I am from Client;
";
ois.write(hello.getBytes(StandardCharsets.UTF_8));
ois.flush();
System.out.println(" client write msg over");
Thread.sleep(666);
InputStream inputStream = socket.getInputStream();
byte[] bytes = new byte[1024];
int length = 0;
while ((length = inputStream.read(bytes)) != -1) {
System.out.println("msg from server: " + new String(bytes, 0, length));
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
3.1.3 结论 这种方案,会阻塞;通过打印堆栈信息可以看出,都是卡在socketRead0()方法;即调用
inputstream.read(bytes)
的时候卡住;即一直获取不到内容,所以一直卡主;
疑惑点?
- 那应该通信几次再卡住才是,而不是一启动就卡主吧?
- 当前是找到了原因。但没找到解决办法;
- 猜测:当前是不是客服端和服务端共用一个socket,只有有一个写、一个读?
3.2.1 Server
public static void main(String[] args) {
try (ServerSocket serverSocket = new ServerSocket(8899)) {
Socket accept = serverSocket.accept();
while (true) {
System.out.println("当前连接服务器的客户端地址:" + accept.getInetAddress());
DataInputStream dis = new DataInputStream(accept.getInputStream());
String clientMsg = dis.readUTF();
System.out.println("msg from client:" + clientMsg);
DataOutputStream dos = new DataOutputStream(accept.getOutputStream());
dos.writeUTF("hello client , I am from server ,msg received + " + clientMsg);
}
} catch (Exception e) {
e.printStackTrace();
}
}
3.2.2 Client
public static void main(String[] args) {
try (Socket socket = new Socket("localhost", 8899)) {
DataInputStream dis = new DataInputStream(socket.getInputStream());
DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
while(true) {
String msg = " I am from client";
dos.writeUTF(msg);
String s = dis.readUTF();
System.out.println("msg from server: "+ s);
}
}catch (Exception e) {
e.printStackTrace();
}
}
3.2.3 【Netty 入门一BIO模型】不会有阻塞;很奇怪; 双方信息打印很通畅;
3.3 使用telnet 作为客户端进行发送消息
- 使用InputStream,如果没有消息,会卡在socketRead0(); 但是telnet客户端一旦输入内容, 就会立即往下走;
- 但使用DataInputStream会卡主,telnet输入消息 也会卡在socketRead0()方法;
暂无结论;
待问题解决
推荐阅读
- Camunda流程引擎|Camunda 官方快速入门教程中文版(完整版)
- javaweb|mybatis-plus批量逻辑删除,并填充字段
- 工作出现的问题|Charles 安装及配置,详细步骤
- Java网络编程
- javascript|客观评价 增长趋势比 vite 还猛的 TailwindCSS
- thymeleaf|【大型电商项目开发】商城业务-首页搭建-thymeleaf模板引擎-36
- java|Mybatis源码简析——实用框架必看
- #|Mybatis源码分析——插件详解
- Spring源码|Spring源码之整合Mybatis底层实现