package testb.pro.testbpro.nio;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
/**
* @author wxq[IT010511]
* @Description:
* @Date: 2022-09-30
* @Modified by:
*/
public class TestNio2 {
public static void main(String[] args) throws Exception {
//网络编程
/**
* 阻塞模式,相关的方法都会导致线程暂停
* ServerSocketChannel.accept没有连接时挂起
* SocketChannel.read没有数据可读时挂起
* 阻塞模式一个线程只能干一件事件,干了一件事情就无法去处理另一件事情了
*
* 单线程下,阻塞方法之间会相互影响,基本不能正常工作,需要多线程的支持
*
* 但是多线程模式下,又有新的问题
* 1个线程占用内存1M,如果创建太多线程会将内存撑爆并且频繁的上下文切换成本非常高
* 2可以采用线程池来减少线程数量和上下文切换的频率,但是如果过个连接都阻塞,其他连接
* 将无人处理,因此线程池只适合短连接
*/
/**
* 客户端代码如下
* SocketChannel sc = SocketChannel.open();
* sc.connect(new InetSocketAddress("localhost",9999););
* 使用debug模式来发送数据:Editor Configuration
*
*/
//blocking();
//非阻塞模式 accept返回null,read返回0
/* * 非阻塞模式下,相关方法都会不会让线程暂停
* 在 ServerSocketChannel.accept 在没有连接建立时,会返回 null,继续运行
* SocketChannel.read 在没有数据可读时,会返回 0,但线程不必阻塞,可以去执行其它 SocketChannel 的 read 或是去执行 ServerSocketChannel.accept
* 写数据时,线程只是等待数据写入 Channel 即可,无需等 Channel 通过网络把数据发送出去
* 但非阻塞模式下,即使没有连接建立,和可读数据,线程仍然在不断运行,白白浪费了 cpu
* 数据复制过程中,线程实际还是阻塞的(AIO 改进的地方)
* */
noBlocking();
}
private static void blocking() throws Exception {
//创建NIo单线程模式服务端
ByteBuffer buffer = ByteBuffer.allocate(16);
//创建服务端channel
ServerSocketChannel ssc = ServerSocketChannel.open();
//绑定监听的端口
ssc.bind(new InetSocketAddress(9999));
//封装客户端连接
List<SocketChannel> channels = new ArrayList<>();
while (true) {
System.out.println("准备建立连接");
SocketChannel sc = ssc.accept();//此方法为阻塞方法
System.out.println("连接已经建立");
channels.add(sc);
//遍历所有已经建立连接的客户端进行处理
for (SocketChannel channel : channels) {
//将客户端数据读进缓冲区 如果没有数据此方法也是阻塞方法,会挂起
System.out.println("准备处理读事件");
channel.read(buffer);
System.out.println("处理了一个读事件");
buffer.flip();
System.out.println("客户端:" + channel.toString() + "发的数据是:" + StandardCharsets.UTF_8.decode(buffer));
buffer.clear();
}
}
}
/**
* 客户端代码
* SocketChannel sc = SocketChannel.open();
* sc.connect(new InetSocketAddress("localhost", 8080));
* System.out.println("waiting...");
*/
private static void noBlocking()throws Exception {
ByteBuffer buffer = ByteBuffer.allocate(16);
ServerSocketChannel ssc = ServerSocketChannel.open();
//非阻塞模式
ssc.configureBlocking(false);
ssc.bind(new InetSocketAddress(9999));
List<SocketChannel> channels = new ArrayList<>();
while (true){
SocketChannel accept = ssc.accept();//非阻塞模式下没有连接返回null
if (accept!=null){
//将客户端channel也设置为非阻塞模式
accept.configureBlocking(false);//这样read方法也不会阻塞,读不到数据就返回0
channels.add(accept);
}
for (SocketChannel channel :channels){
int read = channel.read(buffer);
if (read>0){
buffer.flip();
System.out.println(new String(buffer.array(),0,buffer.limit()));
buffer.clear()
}
}
}
}
}
NIO<二>
最新推荐文章于 2024-07-09 16:24:23 发布