NIO

第一、无阻塞服务器与客户端

主要功能:客户端发一个名字过去(目前只能是英文,比如jack);服务器就会给客户端返回hello jack!

服务器:

public class Server {
	public static final int PORT = 8888;
	private Selector selector;
	private ByteBuffer sendBuffer = ByteBuffer.allocate(1024);
	private ByteBuffer receiverBuffer = ByteBuffer.allocate(1024);
	private Set<SelectionKey> keys;

	public static void main(String[] args) {
		try {
			Server s = new Server();
			s.initServer();
			s.listen();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	// 初始化服务器
	public void initServer() throws IOException {
		selector = Selector.open();
		ServerSocketChannel ssc = ServerSocketChannel.open();
		ssc.configureBlocking(false);
		ServerSocket ss = ssc.socket();
		ss.bind(new InetSocketAddress(PORT));
		ssc.register(selector, SelectionKey.OP_ACCEPT);
	}

	// 开始进行对客户端的监听
	public void listen() throws IOException {
		while (true) {
			selector.select();
			keys = selector.selectedKeys();
			for (SelectionKey sk : keys) {
				if (sk.isAcceptable()) {
					ServerSocketChannel ssc = (ServerSocketChannel) sk.channel();
					SocketChannel sc = ssc.accept();
					sc.configureBlocking(false);
					sc.register(selector, SelectionKey.OP_READ);
				}
				if (sk.isReadable()) {
					SocketChannel sc = (SocketChannel) sk.channel();
					receiverBuffer.clear();
					StringBuilder sb = new StringBuilder();
					while (sc.read(receiverBuffer) > 0) {
						receiverBuffer.flip();
						// 由于buffer的clear方法不是清空buffer中以前数据,只是重置position与limit,所以在取数据的时候需要下面的操作
						String temp = new String(receiverBuffer.array(), receiverBuffer.position(), receiverBuffer.limit());
						sb.append(temp);
						receiverBuffer.clear();
					}
					System.out.println(sb.toString());
					// 这里需要trim()下
					sc.register(selector, SelectionKey.OP_WRITE, sb.toString().trim());
				}
				if (sk.isWritable()) {
					SocketChannel sc = (SocketChannel) sk.channel();
					sendBuffer.clear();
					sendBuffer.put("hello ".getBytes());
					String temp = (String) sk.attachment();
					sendBuffer.put(temp.getBytes());
					sendBuffer.put("!".getBytes());
					sendBuffer.flip();
					System.out.println(new String(sendBuffer.array()));
					// 处理关闭
					if (temp.equals("exit")) {
						sc.write(ByteBuffer.wrap("exit".getBytes()));
						sk.cancel();
						sc.close();
					} else {
						sc.write(sendBuffer);
						sc.register(selector, SelectionKey.OP_READ);
					}

				}
				keys.remove(sk);
			}

		}
	}
}

客户端:

public class Client {
	private InetSocketAddress inetSocketAddress = new InetSocketAddress("localhost", 8888);
	private Selector selector;
	private SocketChannel sc;
	public static int PORT = 8888;
	public static String IP = "localhost";
	public static int SIZE = 1024;
	private ByteBuffer sendBuffer = ByteBuffer.allocate(1024);
	private ByteBuffer receiverBuffer = ByteBuffer.allocate(1024); 
	
	public static void main(String[] args) {
		try {
			Client cn = new Client();
			//cn.initClient();
			cn.listen();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	public void initClient() throws IOException {
		selector = Selector.open();
		sc = SocketChannel.open();
		//配置无阻塞状态需要在连接前面
		sc.configureBlocking(false);
		sc.connect(inetSocketAddress);
		sc.register(selector, SelectionKey.OP_CONNECT);
	}
	
	public void listen() throws IOException {
		initClient();
		while(true) {
			selector.select();
			Set<SelectionKey> keys = selector.selectedKeys();
			for(SelectionKey sk:keys) {
				if(sk.isConnectable()) {
					SocketChannel sc = (SocketChannel)sk.channel();
					if(sc.isConnectionPending()) {
						sc.finishConnect();
					}
					sc.register(selector, SelectionKey.OP_WRITE);
				}
				else if(sk.isWritable()) {
					SocketChannel sc = (SocketChannel)sk.channel();
					Scanner scanner = new Scanner(System.in);
					if(scanner.hasNext()) {
						sendBuffer.clear();
						String temp = scanner.next().trim();
						System.out.println(temp);
						sendBuffer.put(temp.getBytes());
						sendBuffer.flip();
						sc.write(sendBuffer);
						sc.register(selector, SelectionKey.OP_READ);
					}
					
				}else if(sk.isReadable()) {
					SocketChannel sc = (SocketChannel)sk.channel();
					receiverBuffer.clear();
					StringBuilder sb = new StringBuilder();
					while(sc.read(receiverBuffer)>0){
						receiverBuffer.flip();
						if(receiverBuffer.hasArray()) {
							sb.append(new String(receiverBuffer.array(),receiverBuffer.position(),receiverBuffer.limit()));
						}
					};
					System.out.println(sb.toString());
					if(sb.toString().trim().equals("exit")) {
						if(sc != null) {
							sc.close();
							sc = null;
						}
						
						if(selector != null) {
							selector.close();
							selector = null;
						}
						return;
					}
					sc.register(selector, SelectionKey.OP_WRITE);
				}
				keys.remove(sk);
			}
			
		}
		
	}
}

第二、buffer

public class BufferTest {
	public static void main(String[] args) {
		//用wrap来构造一个buffer
		CharBuffer cb1 = CharBuffer.wrap("hello world!");
		System.out.println(cb1.position());
		System.out.println(cb1.limit());
		System.out.println(cb1.toString());
		//用allocate来构造一个buffer
		CharBuffer cb =CharBuffer.allocate(12);
		//往buffer里放入元素
		cb.put("hello world!");
		//这是把limit掷成position,把position掷成0
		cb.flip();
		System.out.println(cb.position());
		System.out.println(cb.limit());
		while(cb.hasRemaining()) {
			//从buffer里取得元素
			System.out.print(cb.get());
		}
		System.out.println();
		//把position重新掷成0,limit不变
		cb.rewind();
		System.out.println(cb.position());
		System.out.println(cb.limit());
		//取得前2个元素
		cb.get();
		cb.get();
		//做压缩操作,把已经读的从buffer中去掉,这时limit=capacity,position指向一个元素
		cb.compact();
		cb.flip();
		while(cb.hasRemaining()) {
			System.out.print(cb.get());
		}
		//重置buffer,position=0,limit=Capacity
		cb.clear();
		System.out.println(cb.position());
		System.out.println(cb.limit());
	}
}

第三、charset

public class CharsetTest {
	public static void main(String[] args) {
		//注意我们一般不会直接用Charset,需要转换字符编码可以用String,InputStreamReader,OutputSreamWriter;
		Charset c = Charset.forName("gbk");
		//下面这个bb已经是flip过后的结果了就不需要在flip了
		ByteBuffer bb = c.encode("你好!中国!");
		System.out.println(bb.position());
		System.out.println(bb.limit());
		System.out.println(bb.toString());
		CharBuffer cb = c.decode(bb);
		/*try {
			System.out.println(new String(bb.array(),"utf8"));
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}*/
	}
}





03-12
### Java NIO 使用教程和示例 #### 一、简介 Java NIO (New Input/Output) 是一种同步非阻塞I/O模型,提供了面向缓冲区以及基于通道的I/O操作方法。NIO库是在JDK 1.4中引入的,旨在改进标准I/O的功能并提高效率[^1]。 #### 二、核心组件介绍 ##### 缓冲区(Buffer) 缓冲区是数据容器,在NIO中所有的数据都必须先放到Buffer对象里才能被处理。常见的有ByteBuffer, CharBuffer等不同类型的数据缓冲区。每个Buffer都有三个重要属性:capacity(容量)、position(位置) 和 limit(界限)。当向buffer写入或从中读取时会改变这些值的状态。 ##### 通道(Channel) 与传统的流不同的是,Channel既可以用来做输入也可以作为输出端点;而且支持异步模式下的多路复用器Selector来管理多个连接。主要实现类包括FileChannel, SocketChannel等等[^3]。 #### 三、Scatter/Gather 特性说明 Scatter/Gather指的是将数据分散读取至多个缓冲区内或将来自几个缓冲区的数据聚集起来一次性写出。这种技术特别适用于需要分段处理大数据集的情况,因为它允许程序一次调用完成多次传输动作而不必反复切换上下文环境。 #### 四、代码实例展示 下面给出一段简单的文件复制例子演示如何使用NIO中的`FileChannel`来进行高效的磁盘间数据搬运工作: ```java import java.io.*; import java.nio.channels.*; public class FileCopy { public static void main(String[] args){ try{ FileInputStream fin = new FileInputStream("source.txt"); FileOutputStream fout = new FileOutputStream("destination.txt"); // 获取源文件和目标文件对应的channel FileChannel fcin = fin.getChannel(); FileChannel fcout = fout.getChannel(); long position=0; long size = fcin.size(); while(position<size){ position += fcin.transferTo(position,size-position,fcout); } fcin.close(); fcout.close(); fin.close(); fout.close(); }catch(IOException e){ System.out.println(e); } } } ``` 此段代码展示了通过transferTo()函数直接在两个file channel之间移动字节序列从而实现了快速拷贝过程[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值