NIO通信代码示例

这篇具有很好参考价值的文章主要介绍了NIO通信代码示例。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

NIO通信架构图

NIO通信代码示例,网络IO,nio,java,开发语言

1.Client

NioClient

package nio;

import constant.Constant;

import java.io.IOException;
import java.util.Scanner;

public class NioClient {
    
    private static NioClientHandle nioClientHandle;
    
    public static void start() {
        nioClientHandle = new NioClientHandle(Constant.DEFAULT_SERVER_IP, Constant.DEFAULT_PORT);
        
        new Thread(nioClientHandle, "Client").start();
    }
    
    // 向服务器发送消息
    public static boolean sendMsg(String msg) throws IOException {
        nioClientHandle.sendMsg(msg);
        return true;
    }

    public static void main(String[] args) throws IOException {
        start();
        Scanner scanner = new Scanner(System.in);
        while (NioClient.sendMsg(scanner.next()));
    }
}

NioClientHandle

package nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

public class NioClientHandle implements Runnable {
    
    private String host;
    
    private int port;
    
    private volatile boolean started;
    
    private Selector selector;
    
    private SocketChannel socketChannel;
    
    public NioClientHandle(String ip, int port) {
        this.host = ip;
        this.port = port;
        
        try {
            // 创建选择器的实例
             selector = Selector.open();
             // 创建ServerSocketChannel的实例
             socketChannel = SocketChannel.open();
             // 设置通道为非阻塞模式
            socketChannel.configureBlocking(false);
            
            started = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public void stop() {
        started = false;
    }
    @Override
    public void run() {
        try {
            doConnect();
        } catch (Exception e) {
            e.printStackTrace();
            System.exit(1);
        }
        
        
        // 循环遍历selector
        while (started) {
            try {
                // 无论是否有读写事件发生,selector每隔1s被唤醒一次
                selector.select(1000);
                // 获取当前有哪些事件可以使用
                Set<SelectionKey> keys = selector.selectedKeys();
                // 转换为迭代器
                Iterator<SelectionKey> it = keys.iterator();
                SelectionKey key = null;
                while (it.hasNext()) {
                    key = it.next();
                    // 我们必须受限将处理过的SelectionKey从选定的集合中删除
                    // 如果我们没有删除处理过的键,那么它仍然会在主集合中以一个激活的键
                    // 出现,这会导致我们尝试再次处理它
                    it.remove();
                    try {
                        handleInput(key);
                    } catch (Exception e) {
                        if (key != null) {
                            key.cancel();
                            if (key.channel() != null) {
                                key.channel().close();
                            }
                        }
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
                System.exit(1);
            }
        }
        
        // selector关闭后会自动释放里面管理的资源
        if (selector != null) {
            try {
                selector.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }


    /**
     * 具体的事件处理方法
     * @param key
     */
    private void handleInput(SelectionKey key) throws IOException {
        if (key.isValid()) {
            // 获得关心当前事件的channel
            SocketChannel sc = (SocketChannel)key.channel();
            // 连接事件
            if (key.isConnectable()) {
                if (sc.finishConnect()) {
                    socketChannel.register(selector, SelectionKey.OP_READ);
                } else {
                    System.exit(1);
                }
            }
            
            // 有数据可读事件
            if (key.isReadable()) {
                // 创建ByteBuffer,并开启一个1M的缓冲区
                ByteBuffer buffer = ByteBuffer.allocate(1024);
                // 读取数据码流 返回读取到的字节数
                int readBytes = sc.read(buffer);
                // 读取到字节 对字节进行编解码
                if (readBytes > 0) {
                    //将缓冲区当前的limit设置为position, position = 0;
                    // 用于后续对缓冲区的读取操作
                    buffer.flip();
                    // 根据缓冲区可读字节数创建字节数组
                    byte[] bytes = new byte[buffer.remaining()];
                    // 将缓冲区可读字节数组复制到新建的数组中
                    buffer.get(bytes);
                    String result = new String(bytes, "UTF-8");
                    System.out.println("客户端收到消息:" + result);
                    
                } else if (readBytes < 0) {
                    key.cancel();
                    sc.close();
                }

            }
        }
    }
    
    
    public void sendMsg(String msg) throws IOException {
        doWrite(socketChannel, msg);
        
    }

    private void doWrite(SocketChannel socketChannel, String request) throws IOException {
        // 将消息编码为字节数组
        byte[] bytes = request.getBytes();
        // 根据数组容量创建ByteBuffer
        ByteBuffer writeBuffer = ByteBuffer.allocate(bytes.length);
        // 将字节数组复制到缓冲区
        writeBuffer.put(bytes);
        // flip操作
        writeBuffer.flip();
        // 发送缓冲区的字节数组
        // 关心事件和读写网络不冲突
        socketChannel.write(writeBuffer);
        
    }
    
    private void doConnect() throws IOException {
        // 非阻塞的连接
        if (socketChannel.connect(new InetSocketAddress(host, port))) {
            socketChannel.register(selector, SelectionKey.OP_READ);
        } else {
            socketChannel.register(selector, SelectionKey.OP_CONNECT);
        }
    }
}

2.Server

NioServer

package nio;

import constant.Constant;

public class NioServer {
    
    private static NioServerHandle nioServerHandle;
    
    public static void main(String[] args) {
        nioServerHandle = new NioServerHandle(Constant.DEFAULT_PORT);
        new Thread(nioServerHandle, "Server").start();
    }
}

NioServerHandle

package nio;

import constant.Constant;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

public class NioServerHandle implements Runnable {
    private volatile boolean started;
    
    private ServerSocketChannel serverSocketChannel;
    
    private Selector selector;
    
    public NioServerHandle(int port) {
        try {
            // 创建选择器实例
            selector = Selector.open();
            // 创建ServerSocketChannel的实例
            serverSocketChannel = ServerSocketChannel.open();
            // 设置通道为非阻塞模式
            serverSocketChannel.configureBlocking(false);
            // 绑定端口
            serverSocketChannel.socket().bind(new InetSocketAddress(port));
            // 注册事件,表示关心客户端连接
            serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
            // 
            started = true;
            System.out.println("服务器已启动, 端口号为:" + port);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    @Override
    public void run() {
        while (started) {
            try {
                // 获取当前有哪些事件
                selector.select(1000);
                // 获取事件的集合
                Set<SelectionKey> selectionKeys = selector.selectedKeys();
                Iterator<SelectionKey> iterator = selectionKeys.iterator();
                while (iterator.hasNext()) {
                    SelectionKey key = iterator.next();
                    // 我们必须首先将处理过的SelectionKey 从选定的键集合中删除
                    // 如果我们没有删除处理过的键,那么它仍然会在主集合中以
                    // 一个激活的键出现,这回导致我们尝试再次处理它
                    iterator.remove();
                    handleInput(key);
                }
            } catch (Exception e) {
                
            }
        }
    }

    /**
     * 处理事件的发生
     * @param key
     */
    private void handleInput(SelectionKey key) throws IOException {
        if (key.isValid()) {
            // 处理新接入的客户端的请求
            if (key.isAcceptable()) {
                // 获取关心当前事件的Channel
                ServerSocketChannel ssc = (ServerSocketChannel)key.channel();
                // 接受连接
                SocketChannel sc = ssc.accept();
                System.out.println("=========建立连接=========");
                sc.configureBlocking(false);
                // 关注读事件
                sc.register(selector, SelectionKey.OP_READ);
            }
            
            // 处理对端的发送的数据
            if (key.isReadable()) {
                SocketChannel sc = (SocketChannel) key.channel();
                // 创建ByteBuffer, 开辟一个缓冲区
                ByteBuffer buffer = ByteBuffer.allocate(1024);
                // 从通道里读取数据,然后写入buffer
                int readBytes = sc.read(buffer);
                if (readBytes > 0) {
                    // 将缓冲区当前的limit设置为position, position = 0
                    // 用于后续对缓冲区的读取操作
                    buffer.flip();
                    // 根据缓冲区可读字节数创建字节数组
                    byte[] bytes = new byte[buffer.remaining()];
                    // 将缓冲区可读字节数组复制到新建的数组中
                    buffer.get(bytes);
                    String message = new String(bytes, "UTF-8");
                    System.out.println("服务器收到消息:" + message);
                    // 处理数据
                    String result = Constant.response(message);
                    // 发送应答消息
                    doWrite(sc, result);
                }
            }
        }
    }

    private void doWrite(SocketChannel sc, String response) throws IOException {
        byte[] bytes = response.getBytes();
        ByteBuffer buffer = ByteBuffer.allocate(bytes.length);
        buffer.put(bytes);
        buffer.flip();
        sc.write(buffer);
    }
}

3.代码运行实例

先启动server再启动client
NIO通信代码示例,网络IO,nio,java,开发语言
NIO通信代码示例,网络IO,nio,java,开发语言文章来源地址https://www.toymoban.com/news/detail-819715.html

到了这里,关于NIO通信代码示例的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • java-IO&NIO

    1.1. 阻塞 IO 模型   最传统的一种 IO 模型,即在读写数据过程中会发生阻塞现象。当用户线程发出 IO 请求之后,内 核会去查看数据是否就绪,如果没有就绪就会等待数据就绪,而用户线程就会处于阻塞状态,用户线程交出 CPU。当数据就绪之后,内核会将数据拷贝到用户线程

    2024年02月12日
    浏览(41)
  • 什么是Java中的NIO(New IO)?

    首先,NIO是什么?NIO全称是Java NIO(New IO),它是一种新的I/O模型,相对于传统的I/O模型,NIO具有更高的性能和更低的延迟。在NIO中,我们使用通道(Channels)和缓冲区(Buffers)来代替传统的输入输出流(InputStream/OutputStream)。 接下来,我们来举个例子。假设我们要读取一个

    2024年02月14日
    浏览(34)
  • Java NIO(Java Non-Blocking IO:非阻塞式IO)(2)

    1.NIO非阻塞网络编程相关的(Selector、SelectionKey、ServerScoketChannel和SocketChannel)关系梳理图: 说明: ①.当客户端连接时,会通过服务器端ServerSocketChannel得到/生成对应的SocketChannel; ②.通过register(Selector sel,int ops)方法将SocketChannel注册到Selector上(一个Selector上可以注册多个SocketChannel); ③

    2024年02月02日
    浏览(47)
  • 9.NIO非阻塞式网络通信入门

    一个 I/O 线程可以并发处理 N 个客户端连接和读写操作,这从根本上解决了传统同步阻塞 I/O 一连接一线程模型。架构的性能、弹性伸缩能力和可靠性都得到了极大的提升。 1、当客户端连接服务端时,服务端会通过 ServerSocketChannel 得到 SocketChannel:获取通道 java ServerSocketChanne

    2024年02月15日
    浏览(37)
  • Java NIO原理 (Selector、Channel、Buffer、零拷贝、IO多路复用)

    系列文章目录和关于我 最近有很多想学的,像netty的使用、原理源码,但是苦于自己对于操作系统和nio了解不多,有点无从下手,遂学习之。 上图粗略描述了网络io的过程,了解其中的拷贝过程有利于我们理解非阻塞io,以及IO多路复用的必要性。 数据从网卡到内核缓冲区 网

    2024年02月08日
    浏览(40)
  • java网络编程——NIO架构

    目录 1.什么是NIO 2.NIO结构 3.基于NIO下的聊天系统实现 4.Netty NIO:java non-blocking IO,同步非阻塞IO。 BIO是阻塞IO,即每一个事件都需要分配一个进程给他,如果客户端没有连接上,则一直阻塞等待。 而NIO,异步 I/O 是一种没有阻塞地读写数据的方法:该架构下我们可以注册对特定

    2023年04月26日
    浏览(54)
  • IO、NIO、IO多路复用

    IO是什么? 网络IO是如何连接的? 下面是一次网络读取内容的I/O示意图,数据先从外设(网卡)到内核空间,再到用户空间(JVM),最后到应用程序的一个过程。 上述一次I/O读取,所谓的阻塞和非阻塞体现在哪里呢? Java最早期的版本的I/O就是这样实现的。当程序调用到读取

    2024年01月20日
    浏览(42)
  • Java分别用BIO、NIO实现简单的客户端服务器通信

    前言: Java I/O模型发展以及Netty网络模型的设计思想 Java BIO是Java平台上的BIO(Blocking I/O)模型,是Java中用于实现同步阻塞网络编程的一种方式。 在Java中,使用BIO模型需要通过Socket和ServerSocket类来完成网络连接和数据传输,但是由于BIO是同步阻塞的,所以会导致线程阻塞和资

    2024年02月09日
    浏览(41)
  • 代码分析Java中的BIO与NIO

    OS:Win10(需要开启telnet服务,或使用第三方远程工具) Java版本:8 BIO(Block IO),即同步阻塞IO,特点为当客户端发起请求后,在服务端未处理完该请求之前,客户端将一直等待服务端的响应。而服务端在此时也专注于该请求的处理,无法处理其它客户端的请求。 在IDEA运行上述

    2024年02月14日
    浏览(38)
  • Java 网络编程之NIO(selector)

                        本编文章意在循环渐进,可看最后一个就可以了                Selector selector = Selector.open();                首先channel必须是非阻塞的情况下                 channel.register(选择器,操作的类型,绑定的组件);返回的是选择键              1)Ch

    2023年04月11日
    浏览(38)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包