java实现NIO服务器端网络编程

本文介绍了一个使用Java NIO (Non-blocking I/O) 实现的简单服务器,它能处理多个客户端连接,通过Selector实现事件驱动,支持OP_ACCEPT和OP_READ。重点展示了如何处理新连接及数据读取的高效处理方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

package com.example.nettytestall.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Collection;
import java.util.Iterator;
import java.util.Set;

public class NIOServer {

    public static void main(String[] args) throws IOException {

        //创建serverSocketChannel ->ServerSocket
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();

        //绑定一个端口8888,在服务器端监听
        serverSocketChannel.socket().bind(new InetSocketAddress(8888));

        //设置为非阻塞
        serverSocketChannel.configureBlocking(false);

        //得到一个Selector对象
        Selector selector = Selector.open();

        //把serverSocketChannel 注册到selector 关心事件为 OP_ACCEPT
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

        while(true){
            //这里我们等待1秒 如果没有事件发生,返回
           if(selector.select(1000)==0){//没有事件发生
               /*System.out.println("服务器等待1秒无连接");*/

           }
           //如果返回大于0 就获取到相关的selectionkey集合
            //1.如果返回的>0,标识一级获取到关注的事件
            //2.selector.selectedKeys() 返回关注事件的集合
            // 通过selectionKeys 反向获取通道
            Set<SelectionKey> selectionKeys = selector.selectedKeys();

           //遍历set 使用迭代器遍历(遍历出每一个selectionKey)
            Iterator<SelectionKey> iterator = selectionKeys.iterator();


            while (iterator.hasNext()){
                //获取到selectorKet 判断通道里面发生的事件做相应的处理
                SelectionKey key = iterator.next();
                if(key.isAcceptable()){ //如果是OP_ACCEPT,有新客户端连接
                    //该客户端生成一个SocketChannel
                    // (accept 是阻塞方法  此设计巧妙在先确定有客户端连接 在调用此方法    Bio是先调用,等待客户端连接  )
                    SocketChannel socketChannel = serverSocketChannel.accept();
                    System.out.println("客户端连接成功");
                    //非阻塞
                    socketChannel.configureBlocking(false);
                    //将socketChannel 注册到selector ,关注事件为OP_READ 同时给通道绑定buffer
                    socketChannel.register(selector,SelectionKey.OP_READ, ByteBuffer.allocate(1024));
                }
                if(key.isReadable()){//发生读的事件
                    //通过key 反向获取到对应的channel
                    SocketChannel channel = (SocketChannel)key.channel();

                    //获取到关联的buffer
                    ByteBuffer buffer = (ByteBuffer)key.attachment();
                    //这个反回值其实就是读取的字节数。该数字为0时说明就是一般的没有数据可读取,而当为-1时其实表示底层tcp已经断开了。
                    // (但IE的连接有点不同,read时直接给出Exception,反正这些情况都要判断了.)
                    //不做这些处理 如果就读  会出现客户端关闭后,服务端死循环读取
                    try{
                        int num = channel.read(buffer);
                        if(num ==-1){
                            throw new IOException("读完成");
                        }else {
                            System.out.println("客户端:"+new String(buffer.array()));
                        }
                    }catch (IOException e){
                        key.cancel();//取消绑定
                        if(channel!=null){
                            channel.close();
                        }

                    }




                }
                //手动从集合中删除当前的selectionKey 防止重复操作
                selectionKeys.remove(key);

            }


        }
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值