网络编程之NIO
发布日期:2021-06-29 11:25:27
浏览次数:3
分类:技术文章
本文共 9044 字,大约阅读时间需要 30 分钟。
网络编程之NIO
非阻塞的NIO
1缓冲区
客户端
public class NIOClient { public static void main(String[] args) throws IOException { //1.创建通道对象并打开 SocketChannel socketChannel = SocketChannel.open(); //2.指定IP和端口号 socketChannel.connect(new InetSocketAddress("127.0.0.1",10000)); //3.写出数据 ByteBuffer byteBuffer = ByteBuffer.wrap("一点寒芒先到".getBytes()); socketChannel.write(byteBuffer); //4.关流 socketChannel.close(); }}
服务端
public class NIOServer { public static void main(String[] args) throws IOException { // 1.创建打开服务端通道 ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();// 2.绑定对应的端口号 serverSocketChannel.bind(new InetSocketAddress(10000));// 3.通道默认是阻塞的,需要设置为非阻塞 //如果传递true 表示通道设置为阻塞通道...默认值 //如果传递false 表示通道设置为非阻塞通道 serverSocketChannel.configureBlocking(false);// 4.此时没有门卫大爷,所以需要经常看一下有没有连接发过来没? while (true) { // 5.如果有客户端来连接了,则在服务端通道内部,再创建一个客户端通道 //设置了通道为非阻塞 //所以在调用方法的时候,如果有客户端来连接,那么会创建一个SocketChannel对象 //如果在调用方法的时候,没有客户端来连接,那么他会返回一个null SocketChannel socketChannel = serverSocketChannel.accept(); //System.out.println(socketChannel); if(socketChannel != null){ // 6.客户端将缓冲区通过通道传递给服务端,就到了这个延伸通道socketChannel里面// 7.服务端创建一个空的缓冲区装数据并输出 ByteBuffer byteBuffer = ByteBuffer.allocate(1024); //获取传递过来的数据,并把他们放到byteBuffer缓冲区中. //返回值: //正数: 表示本次读到的有效字节个数. //0 : 表示本次没有读到 //-1 : 表示读完了 int len = socketChannel.read(byteBuffer); System.out.println(new String(byteBuffer.array(),0,len)); //8.关闭 socketChannel.close(); } } }}
2通道
客户端
public class Clinet { public static void main(String[] args) throws IOException { // 1.创建打开通道 SocketChannel socketChannel = SocketChannel.open(); // 2.指定IP和端口号 socketChannel.connect(new InetSocketAddress("127.0.0.1",10000)); // 3.写出数据 ByteBuffer byteBuffer1 = ByteBuffer.wrap("吃俺老孙一棒棒".getBytes()); socketChannel.write(byteBuffer1); // 写入结束标记 socketChannel.shutdownOutput(); System.out.println("数据已经写给服务器"); // 4.读取服务器写回的数据 ByteBuffer byteBuffer2 = ByteBuffer.allocate(1024); int len; while((len = socketChannel.read(byteBuffer2)) != -1){ byteBuffer2.flip(); System.out.println(new String(byteBuffer2.array(),0,len)); byteBuffer2.clear(); } // 5.释放资源 socketChannel.close(); }}
服务端
public class Sever { public static void main(String[] args) throws IOException { // 1,打开一个服务端通道 ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); // 2,绑定对应的端口号 serverSocketChannel.bind(new InetSocketAddress(10000)); // 3,通道默认是阻塞的,需要设置为非阻塞 serverSocketChannel.configureBlocking(false); // 4,此时没有门卫大爷,所以需要经常看一下有没有连接发过来没? while(true){ // 5,如果有客户端来连接了,则在服务端通道内部,再创建一个客户端通道,相当于是客户端通道的延伸 SocketChannel socketChannel = serverSocketChannel.accept(); if(socketChannel != null){ System.out.println("此时有客户端来连接了"); // 6,获取客户端传递过来的数据,并把数据放在byteBuffer1这个缓冲区中 ByteBuffer byteBuffer1 = ByteBuffer.allocate(1024); //socketChannel.read(byteBuffer1); int len; //针对于缓冲区来讲 //如果 从添加数据 ----> 获取数据 flip //如果 从获取数据 ----> 添加数据 clear while((len = socketChannel.read(byteBuffer1)) != -1){ byteBuffer1.flip(); System.out.println(new String(byteBuffer1.array(),0,len)); byteBuffer1.clear(); } System.out.println("接收数据完毕,准备开始往客户端回写数据"); // 7,给客户端回写数据 ByteBuffer byteBuffer2 = ByteBuffer.wrap("哎哟,真疼啊!!!".getBytes()); socketChannel.write(byteBuffer2); // 8,释放资源 socketChannel.close(); } } }}
3选择器
客户端
public static void main(String[] args) throws IOException { //创建并打开通道 SocketChannel socketChannel = SocketChannel.open(); //指定ip和端口 socketChannel.connect(new InetSocketAddress("192.168.1.39",9999)); //写出数据 ByteBuffer byteBuffer1 = ByteBuffer.wrap(("你笑一次,我就可以高兴好几天;" + "可看你哭一次,我就难过了好几年。").getBytes()); socketChannel.write(byteBuffer1); System.out.println("数据已经写给服务器"); //存入字节数组 ByteBuffer byteBuffer2 = ByteBuffer.allocate(1024); int len; while((len = socketChannel.read(byteBuffer2)) != -1){ System.out.println("客户端接收回写数据"); byteBuffer2.flip(); System.out.println(new String(byteBuffer2.array(),0,len)); byteBuffer2.clear(); } //关闭 socketChannel.close(); }
服务端
public static void main(String[] args) throws Exception { //1:建立服务器 的通道 ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); serverSocketChannel.bind(new InetSocketAddress(9999)); //设置非阻塞连接 serverSocketChannel.configureBlocking(false); //2:为了同同时处理多个客户端的连接 // 加上选择器 // 1:获得一个独立的选择器 Selector selector = Selector.open(); // 2:将当前的服务器 通道 注册上该选择器,并设置该通道的状态 // 状态有三种 // 可接受 // 可读取数据 // 可写出数据 serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); //正式开始 通过选择器 操作每一个客户端的数据输入 // 所有的数据输入和输出 通过选择器 while (true) { //:1获得选择器中 的处理的 客户端 个数 int count = selector.select(); // 只有当前有客户才处理 if (count != 0) { // SelectionKey ----> 就是一个客户端连接后 , 选择器给他分配一个 令牌 ,该令牌描述 该通道的状态 Setkeys = selector.selectedKeys(); // 循环使用每一个令牌 , 其实就是循环操作每个 客户端通道 Iterator iterator = keys.iterator(); while (iterator.hasNext()) { SelectionKey key = iterator.next(); // 获得 当前令牌的状态 , 根据不同的状态 执行不同的代码 // 如果是第一次进入 去选择器登记和注册 if (key.isAcceptable()) { // 一个客户端 最先是在次 先执行,后续才能 读或者写 // 获得服务端通道 ServerSocketChannel server = (ServerSocketChannel) key.channel(); // 通过服务端 获得一个连接的客户端通道 SocketChannel client = server.accept(); //将客户端的通道设置为非阻塞 client.configureBlocking(false); //修改当前选择器中 令牌的状态 // 如果填写是 SelectionKey.OP_READ 那么此客户端下一次进来时就是 进入 else if(key.isReadable()) // 如果填写是 SelectionKey.OP_WRITE 那么此客户端下一次进来时就是 进入 else if(key.isWritable()) client.register(selector, SelectionKey.OP_READ); // 如果是读取数据的状态 } else if (key.isReadable()) { //需要读取 客户端中的数据 SocketChannel client = (SocketChannel) key.channel(); //缓冲区获得数据 ByteBuffer buffer = ByteBuffer.allocate(8192); while (true) { buffer.clear(); //获得通道中的数据 写入缓冲中 int len = client.read(buffer); if (len == -1) { //说明 客户端发送全部结束 // 如果我想告诉 客户端 我接受了全部数据 --->我就是想给客户端发送一个消息 // 将当前客户端的状态修改为 可写 client.register(selector, SelectionKey.OP_WRITE); break; } else if (len == 0) { // 通道连接是正常 ,但是数据不来了 break; } else { buffer.flip(); //将数据继续解析 ---> 我们先默认发送的字符串 String msg = new String(buffer.array(), 0, len); String ip = client.getRemoteAddress().toString(); System.out.println(ip + " ---> " + msg); } } // 如果是写出数据的状态 } else if (key.isWritable()) { SocketChannel client = (SocketChannel) key.channel(); ByteBuffer buffer = ByteBuffer.wrap("服务端接受数据完毕 ,你可以正常退出了".getBytes()); client.write(buffer);// client.close();// //可以将次通道关闭// iterator.remove(); } } } } }
转载地址:https://blog.csdn.net/zxy_spure/article/details/117670755 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!
发表评论
最新留言
路过按个爪印,很不错,赞一个!
[***.219.124.196]2024年04月07日 16时30分00秒
关于作者
喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
a标签中href调用js的几种方法
2019-04-29
jstl标签详解
2019-04-29
Eclipse中使用SVN的使用
2019-04-29
JSON.parse和eval的区别
2019-04-29
JQuery中$.ajax()方法参数详解
2019-04-29
正则表达式的数字实例
2019-04-29
OGNL表达式struts2标签“%,#,$”的区别
2019-04-29
struts2中<s:if>标签的使用
2019-04-29
js 刷新页面window.location.reload();
2019-04-29
【转】EasyUI 验证
2019-04-29
java开发时内存溢出问题
2019-04-29
【easyui】combobox 关于省市联动
2019-04-29
设置csdn皮肤方法,更改自己喜欢的老版皮肤
2019-04-29
Eclipse中无法查看JDK源码,解决方法
2019-04-29
Git操作常用口令
2019-04-29
IDEA去除掉虚线,波浪线,和下划线实线的方法
2019-04-29
MYSQL新特性secure_file_priv 读写文件
2019-04-29