NIO(服务端改造)

package com;

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.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

/**
 *
 * 使用NIO完成聊天室服务端
 * MINA框架(等NIO进一步了解深入后,可以多了解MINA)
 */
public class NIDServer {

    public void start() {

        try {
            //存放对应所有客户端的SocketChannel,用于广播消息
            List<SocketChannel> allChannel = new ArrayList<SocketChannel>();


            //创建ServerSocketChannel
            ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
            //ServerSocketChannel默认是阻塞通道,我们可改为非阻塞通道
            serverSocketChannel.configureBlocking(false);//设置为非阻塞 configure设置
            //为ServerSocketChannel 绑定端口,客户端通过该端口进行连接
            serverSocketChannel.bind(new InetSocketAddress(8088));

           /*
                创建多路选择器
                这个是NIO事项非阻塞的关键API,用于监控多路设备的事件,并可以做出响应
                使得单个线程仅需要轮询多路选择器就可以对多个设备做出事件处理
            */
            Selector selector = Selector.open();
            /*
                将ServerSocketChannel注册到多路选择器上,让其监控是否有客户端连接的事件
                解放了原来需要让主线程调用serverSocket.accept()这里阻塞的情况
                register:注册
             */
            serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

            //让主线程一直关注选择器是否有事件需要处理了
            while (true) {
                //当选择器发现注册在它上面的某些通道有事件时,该方法立即返回,否则会阻塞
                selector.select();

                //处理事件
                // 通过选择器获取目前所有事件的通道
                Set<SelectionKey> keySet = selector.selectedKeys();

//                遍历并处理每一个事件
                for (SelectionKey key : keySet) {
                    //判断该事件是否为可接受客户端连接的(ServerSocketChannel注册的OP_ACCEPT所响应的事件)
                    if (key.isAcceptable()) {
                        //获取该事件对应通道
                        ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
                        //“接电话”
                        SocketChannel socketChannel = ssc.accept();
                        //非阻塞的ServerSocketChannel的accept方法可能返回null
                        if (socketChannel == null) {//null就忽略
                            continue;
                        }
                        //将SocketChannel设置为非阻塞式的
                        socketChannel.configureBlocking(false);
                        //将SocketChannel注册到多路选择器上,关心的事件为:有数据可读取(该客户端发消息过来)
                        socketChannel.register(selector, SelectionKey.OP_READ);
                        //将该SocketChannel存入allChannel集合便于广播消息
                        allChannel.add(socketChannel);
                        //通过SocketChannel获取远端计算机地址信息并输出
                        System.out.println(socketChannel.socket().getInetAddress().getHostAddress()+"上线了,当前在线人数:"+
                                +allChannel.size());

                    //如果该事件是表示有消息可读(该事件一定是一个SocketChannel响应的)
                        //allocate : 分拨,分配
                    } else if (key.isReadable()){
                        SocketChannel sc = (SocketChannel) key.channel();
                        ByteBuffer buffer = ByteBuffer.allocate(1024);
                        sc.read(buffer);//读取客户端发送过来的所有数据存入buffer
                        buffer.flip();//position:0 limit:前面读进来的所有字节
                        if (buffer.limit()==0){//如果本次一个字节都没有读取到就忽略
                            buffer.clear();
                            continue;
                        }
                        //获取缓冲区中
                        // 本次读取到的所有字节:0--limit
                        //创建一个与buffer中目前可用字节一样长的一个字节数组
                        byte[] data = new byte[buffer.limit()];
                        //要求buffer将所有可用字节存入我们传入的字节数组data中
                        buffer.get(data);
                        String message = new String(data, StandardCharsets.UTF_8);
                        message = sc.socket().getInetAddress().getHostAddress()+"说:"+message;

                        //清除buffer后,position= 0,limit = 容量
                        buffer.clear();
                        //put后,position=转换的字节数组长度  limit = 容量
                        buffer.put(message.getBytes(StandardCharsets.UTF_8));
                        //广播消息给所有客户端
                        for (SocketChannel channel: allChannel
                             ) {
                            buffer.flip();//position=0 limit=转换的字节数组长度
                            channel.write(buffer);
                            //write完毕后,position= 转换后的字节数组长度=limit
                        }
//                        buffer.clear();
                        System.out.print(message);
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    public static void main(String[] args) {
        NIDServer server = new NIDServer();
        server.start();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个使用Java NIO实现的TCP Server和Client的示例代码: TCP Server: ```java 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; public class TCPServer { private Selector selector; private ByteBuffer buffer = ByteBuffer.allocate(1024); public TCPServer(int port) throws IOException { ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); serverSocketChannel.configureBlocking(false); serverSocketChannel.socket().bind(new InetSocketAddress(port)); selector = Selector.open(); serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); System.out.println("Server started on port " + port); } private void start() throws IOException { while (true) { selector.select(); Iterator<SelectionKey> keys = selector.selectedKeys().iterator(); while (keys.hasNext()) { SelectionKey key = keys.next(); keys.remove(); if (!key.isValid()) { continue; } if (key.isAcceptable()) { accept(key); } else if (key.isReadable()) { read(key); } else if (key.isWritable()) { write(key); } } } } private void accept(SelectionKey key) throws IOException { ServerSocketChannel serverSocketChannel = (ServerSocketChannel) key.channel(); SocketChannel socketChannel = serverSocketChannel.accept(); socketChannel.configureBlocking(false); socketChannel.register(selector, SelectionKey.OP_READ); System.out.println("Accepted connection from " + socketChannel.getRemoteAddress()); } private void read(SelectionKey key) throws IOException { SocketChannel socketChannel = (SocketChannel) key.channel(); buffer.clear(); int bytesRead = socketChannel.read(buffer); if (bytesRead == -1) { socketChannel.close(); System.out.println("Connection closed by " + socketChannel.getRemoteAddress()); return; } buffer.flip(); byte[] data = new byte[buffer.limit()]; buffer.get(data); System.out.println("Received data from " + socketChannel.getRemoteAddress() + ": " + new String(data)); socketChannel.register(selector, SelectionKey.OP_WRITE, data); } private void write(SelectionKey key) throws IOException { SocketChannel socketChannel = (SocketChannel) key.channel(); byte[] data = (byte[]) key.attachment(); ByteBuffer byteBuffer = ByteBuffer.wrap(data); socketChannel.write(byteBuffer); System.out.println("Sent data to " + socketChannel.getRemoteAddress() + ": " + new String(data)); socketChannel.register(selector, SelectionKey.OP_READ); } public static void main(String[] args) throws IOException { TCPServer server = new TCPServer(8080); server.start(); } } ``` TCP Client: ```java import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.SocketChannel; public class TCPClient { private SocketChannel socketChannel; private ByteBuffer buffer = ByteBuffer.allocate(1024); public TCPClient(String host, int port) throws IOException { socketChannel = SocketChannel.open(); socketChannel.configureBlocking(false); socketChannel.connect(new InetSocketAddress(host, port)); } private void start() throws IOException { while (!socketChannel.finishConnect()) { // Wait for connection to be established } System.out.println("Connected to server " + socketChannel.getRemoteAddress()); String message = "Hello, server!"; buffer.put(message.getBytes()); buffer.flip(); socketChannel.write(buffer); System.out.println("Sent data to server: " + message); buffer.clear(); int bytesRead = socketChannel.read(buffer); if (bytesRead == -1) { socketChannel.close(); System.out.println("Connection closed by server"); return; } buffer.flip(); byte[] data = new byte[buffer.limit()]; buffer.get(data); System.out.println("Received data from server: " + new String(data)); socketChannel.close(); } public static void main(String[] args) throws IOException { TCPClient client = new TCPClient("localhost", 8080); client.start(); } } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值