网络通信在编程世界中是必不可少的一部分,到目前为止网络通信主要经历了三个阶段BIO,NIO,AIO。本文主要介绍网络通信涉及到的一些概念,并且采用一个网络通信的Demo展示何为BIO——阻塞IO。
基础概念
1、阻塞、非阻塞
阻塞和非阻塞是指进程在访问数据的时候,数据内部是否准备就绪的一种处理方式。当数据没有准备的时候
阻塞:需要等待缓冲区的数据准备好才去处理之后的事情,否则一直等待下去
非阻塞:无论缓冲区的数据是否准备好,都立刻返回
2、同步、异步
同步和异步都是基于应用程序和操作系统处理IO时间锁采用的方式。
同步:应用程序要直接参与IO读写的操作,在处理IO事件的时候必须阻塞在某个方法上的等待我们IO完成的时间(阻塞IO事件或者通过轮询IO事件的方式)。阻塞直到IO事件遇到write或者read,这个时候我们不能做任何我们想去做的事情,让读写方法加入到线程中,通过阻塞线程来实现,这样对线程的性能消耗比较大。
异步:所有的IO读写都交给操作系统处理,此时应用程序可以处理其他事情,当操作系统完成IO后给应用程序一个通知即可。
3、Java IO实现方式
1)、同步,阻塞IO——BIO-(JDK1.4以前)
2)、IO事件轮询,多路复用技术(select)——NIO-(JDK1.4—1.6)
3)、异步非阻塞IO——AIO-(JDK1.7以及以后)
接下小编主要介绍BIO的一个Demo,实现类似于聊天室的功能,用于理解何为阻塞IO
SocketService 服务端
package com.mandy.nio.service;
import com.mandy.nio.headler.ServerHandler;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
/**
* @author 贾文静
* @version 1.0
* @title
* @description 服务端socket 当没有客户连接时会一直堵塞
*/
public class SocketService {
final static int PORT = 7789;
public static void main(String[] args) {
try {
ServerSocket server = new ServerSocket(PORT);
System.out.println("server start...");
//堵塞
Socket socket = server.accept();
//创建线程用于真正的读写处理
new Thread(new ServerHandler(socket)).start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
服务端真正的线程处理逻辑
package com.mandy.nio.headler;
import java.io.*;
import java.net.Socket;
/**
* @author 贾文静
* @version 1.0
* @title
* @description 真正用于处理读写操作的线程
*/
public class ServerHandler implements Runnable {
private Socket socket;
public ServerHandler(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try (BufferedReader in = new BufferedReader(new InputStreamReader(this.socket.getInputStream()));
PrintWriter out = new PrintWriter(this.socket.getOutputStream(), true)) {
String body = null;
while (true) {
//用于接收客户的请求数据
body = in.readLine();
if (body == null) {
break;
}
System.out.println("客户端say:");
System.out.println(body);
System.out.println("服务端say:");
//为客户端响应数据
String s = new BufferedReader(new InputStreamReader(System.in)).readLine();
out.println(s);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
客户端请求连接
package com.mandy.nio.client;
import org.springframework.util.StringUtils;
import java.io.*;
import java.net.Socket;
import java.util.Scanner;
/**
* @author 贾文静
* @version 1.0
* @title
* @description 客户端socket 通过ip+端口去连接serviceSocket ,当没有找服务端直接抛出java.net.ConnectException: Connection refused (Connection refused)
*/
public class SocketClient {
final static String ADDRESS = "127.0.0.1";
final static int PORT = 7789;
public static void main(String[] args) {
try (Socket socket = new Socket(ADDRESS, PORT)) {
//从服务器读取数据
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//向服务端发送数据
PrintStream output = new PrintStream(socket.getOutputStream());
System.out.println("客户端说:");
String str = new BufferedReader(new InputStreamReader(System.in)).readLine();
output.println(str);
String response = null;
while (true) {
response = reader.readLine();
if (StringUtils.isEmpty(response)) {
break;
}
System.out.println("服务器说:");
System.out.println(response);
if ("OK".equals(response)) {
System.out.print("程序即将关闭");
break;
} else {
System.out.println("客户端说:");
String client = new BufferedReader(new InputStreamReader(System.in)).readLine();
output.println(client);
}
}
output.close();
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
当没有客户端请求,服务端启动后一直处于阻塞状态
当客户端发送请求通信时,客户端阻塞等待服务端的响应
从功能实现来说利用socket bio的原理实现一个简单聊天室,这个相比我们平常使用的微信,QQ,钉钉等来说只能和一个人聊天,要想和其他人通信只能等这个通信彻底结束,对于实际场景来说不满足实际情况,对于服务器,对线程资源也是极大的损耗, 从技术上来说 JDK1.4之后推出了NIO 多路复用技术来解决线程资源损耗的问题,关于聊天室这个功能也会伴随着NIO而逐步增强的,具体内容,下篇博客更新。