网络编程之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 ----> 就是一个客户端连接后 , 选择器给他分配一个 令牌 ,该令牌描述 该通道的状态 Set
keys = 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 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:MySQL-操作数据库
下一篇:网络编程之TCP

发表评论

最新留言

路过按个爪印,很不错,赞一个!
[***.219.124.196]2024年04月07日 16时30分00秒