网络通信IO的方式通常分为几种,同步阻塞BIO,同步非阻塞NIO,异步非阻塞AIO(NIO2)
在JDK1.4之前或者说Tomcat 7之前我们在建立网络通信的时候采用的是BIO模式,需要现在服务端启动一个ServerSocket,然后在客户端启动一个Socket来与服务端进行通信,默认情况下服务端需要对每个请求建立一堆线程等待请求,而客户端发送请求后,先咨询服务端是否有线程响应,如果没有则会一直等待或者拒绝请求,如果有的话,客户端线程会等待请求结束后继续执行。
在BIO通信模型中,我们先需要创建一个SocketServer服务端接收并输出传送过来的数据
public class SocketServer {
static byte[] bs = new byte[1024];
public static void main(String[] args) throws IOException {
java.net.ServerSocket serverSocket = new java.net.ServerSocket(8888);//端口为8888
while (true){
Socket client = serverSocket.accept();
client.getInputStream().read(bs);
System.out.println(new String(bs));
}
}
}
创建客户端SocketClient模拟发送数据
public class SocketClient {
public static void main(String[] args) throws IOException {
//建立连接并且发送数据
Socket socket = new Socket("127.0.0.1",8888);
socket.getOutputStream().write("发送成功!".getBytes());
socket.close();
}
}
启动SocketServer服务端,然后启动SocketClient端发送消息,控制台输出:
发送成功!
一个简单的BIO网络通信模型就建成了,因为accept()方法和read()方法是阻塞的,一旦一个请求进来后不处理完成不会继续接下来的操作,接下来我们通过测试来验证一下
public class SocketServer {
static byte[] bs = new byte[1024];
public static void main(String[] args) throws IOException {
java.net.ServerSocket serverSocket = new java.net.ServerSocket(8888);// 端口为8888
while (true){
System.out.println("连接等待中...");
Socket client = serverSocket.accept();// accept:阻塞
System.out.println("连接成功...");
System.out.println("获取数据中...");
client.getInputStream().read(bs);// read:阻塞
System.out.println("获取数据成功...");
System.out.println(new String(bs));
}
}
}
通过修改服务器端代码打印log验证,在每次获取连接前后及获取数据前后打印日志,启动服务端
连接等待中...
启动客户端SocketClient输出
连接等待中...
连接成功...
获取数据中...
获取数据成功...
发送成功!
连接等待中...
接收消息并且打印了步骤,因为我们创建了一个死循环,所以继续连接等待中,这个时候重新创建一个客户端SocketClient1只连接服务端不发送数据
public class SocketClient1 {
public static void main(String[] args) throws IOException {
Socket socket = new Socket("127.0.0.1",8888);
//只建立连接不发送数据
Scanner scanner = new Scanner(System.in);
String next = scanner.next();
socket.getOutputStream().write(next.getBytes());
socket.close();
}
}
启动客户端SocketClient1之后,SocketServer控制台输出
连接等待中...
连接成功...
之后再回过头来启动客户端SocketClient,会发现服务端会一直阻塞在连接成功...
这个时候我们为每一个连接创建一个线程可以吗?
public class SocketServer {
static byte[] bs = new byte[1024];
public static void main(String[] args) throws IOException {
java.net.ServerSocket serverSocket = new java.net.ServerSocket(8888);// 端口为8888
while (true){
System.out.println("连接等待中...");
Socket client = serverSocket.accept();// accept:阻塞
System.out.println("连接成功...");
new Thread(()->{
try {
System.out.println("获取数据中...");
client.getInputStream().read(bs);// read:阻塞
System.out.println("获取数据成功...");
} catch (IOException e) {
e.printStackTrace();
}
System.out.println(new String(bs));
}).start();
}
}
}
修改代码,为每一个连接创建一个线程,之后再启动SocketClient1跟SocketClient
连接等待中...
连接成功...
获取数据中...
连接等待中...
连接成功...
获取数据中...
获取数据成功...
发送成功!
通过为每一个连接创建一个线程的方式,我们看起来解决了这个问题,但是在实际的应用中,对服务器性能消耗巨大,实际应用中如果为每一个连接都创建一个线程的话,如果100000个连接,创建100000个线程,不现实。
在BIO中accept()方法会一直阻塞到有连接请求,read()方法会一直阻塞到有数据传输过来,直至一个连接或者一个请求处理完成,为每一个连接都分别创建线程在实际应用落地不可取,资源开销巨大,BIO方式适用于链接数目比较小且比较固定的架构,并且对服务器资源要求高,并发局限于应用中,在JDK1.4之前是唯一选择,但程序直观简单易理解。
感谢博主,喝杯咖啡~
感谢博主,喝杯咖啡~
还没有人发表评论