Java NIO实例:回显服务

NIO概述

NIO是JDK 1.4开始引入的。弥补了旧的IO的不足之处。
NIO的3个重要组件是缓冲区(Buffer)、通道(Channel)、选择器(Selector)。
Buffer使得可以更加灵活的读/写字节流。处理数据时,可以方便的在Buffer里前后移动,提高了处理过程的灵活性。
Channel将之前的单向的输入/输出流整合在一起,既可以读,也可以写。
Selector可以监听多个Channel,一个线程就可以应付成千上万的Client连接,轮询得到就绪的事件进行后续处理,原理是基于OS提供的多路复用技术。
在这里插入图片描述

实例代码

效果

在这里插入图片描述
在这里插入图片描述

Server

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 EchoServer {
    private Selector selector;
    private ServerSocketChannel serverSocketChannel;
    private volatile boolean stop;

    EchoServer() throws IOException {
        selector = Selector.open();
        serverSocketChannel = ServerSocketChannel.open();
        serverSocketChannel.configureBlocking(false);
        serverSocketChannel.socket().bind(new InetSocketAddress(40000),1024);
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
        System.out.println("Server监听在40000端口");
        
        while(!stop){
            selector.select(1000);
            Set<SelectionKey> selectedKeys = selector.selectedKeys();
            Iterator<SelectionKey> it = selectedKeys.iterator();
            SelectionKey key = null;
            while(it.hasNext()){
                key = it.next();
                it.remove();;
                handler(key);
            }
        }
    }

    private void handler(SelectionKey key) throws IOException {
        if(key.isValid()){
            if(key.isAcceptable()){
                ServerSocketChannel serverSocketChannel = (ServerSocketChannel) key.channel();
                SocketChannel socketChannel = serverSocketChannel.accept();
                socketChannel.configureBlocking(false);
                socketChannel.register(selector,SelectionKey.OP_READ);
            }
            if(key.isReadable()){
                SocketChannel socketChannel = (SocketChannel) key.channel();
                ByteBuffer readBytes = ByteBuffer.allocate(1024);
                int readCount = socketChannel.read(readBytes);
                if(readCount > 0){
                    readBytes.flip();
                    byte[] bytes = new byte[readBytes.remaining()];
                    readBytes.get(bytes);
                    String receiveMsg = new String(bytes,"UTF-8");
                    if("bye".equals(receiveMsg)){
                        stop();
                        return;
                    }
                    String responseString ="服务端收到:" + receiveMsg;
                    System.out.println(responseString);
                    responseString = "服务器返回" + receiveMsg;
                    ByteBuffer responseBuffer = ByteBuffer.allocate(responseString.getBytes().length);
                    responseBuffer.put(responseString.getBytes());
                    responseBuffer.flip();
                    socketChannel.write(responseBuffer);
                }
            }
        }
    }

    public void stop(){
        this.stop = true;
    }

    public static void main(String[] args) {
        try {
            new EchoServer();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Client

package com.sss.nio.echo_server;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectableChannel;
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 EchoClient extends Thread {
    private Selector selector;
    private SocketChannel socketChannel;
    private volatile boolean stop;
    SocketChannel channel;

    public EchoClient() throws IOException {
        selector = Selector.open();
        socketChannel = SocketChannel.open();
        socketChannel.configureBlocking(false);
    }

    @Override
    public void run() {
        try {
            boolean connected = socketChannel.connect(new InetSocketAddress("127.0.0.1", 40000));
            if (connected) {
                socketChannel.register(selector, SelectionKey.OP_WRITE);
            } else {
                socketChannel.register(selector, SelectionKey.OP_CONNECT);
            }
            while (!stop) {
                selector.select(1000);
                Set<SelectionKey> keys = selector.selectedKeys();
                Iterator<SelectionKey> it = keys.iterator();
                while (it.hasNext()) {
                    SelectionKey key = it.next();
                    it.remove();
                    handler(key);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void handler(SelectionKey key) throws IOException {
        if (key.isValid()) {
            channel = (SocketChannel) key.channel();
            if (key.isConnectable()) {
                if (channel.finishConnect()) {
                    channel.register(selector, SelectionKey.OP_WRITE);
                }
            }
            if (key.isReadable()) {
                ByteBuffer readBuffer = ByteBuffer.allocate(1024);
                int readCount = channel.read(readBuffer);
                if (readCount > 0) {
                    readBuffer.flip();
                    byte[] bytes = new byte[readBuffer.remaining()];
                    readBuffer.get(bytes);
                    System.out.println("client收到消息:" + new String(bytes, "UTF-8"));
                } else if (readCount < 0) {
                    key.cancel();
                    channel.close();
                }
                channel.register(selector, SelectionKey.OP_WRITE);
            }
            if (key.isWritable()) {
                BufferedReader localReader = new BufferedReader(new InputStreamReader(System.in));
                String msg = null;
                if (((msg = localReader.readLine()) != null)) {
                    ByteBuffer writeBuffer = ByteBuffer.allocate(msg.getBytes().length);
                    writeBuffer.put(msg.getBytes());
                    writeBuffer.flip();
                    socketChannel.write(writeBuffer);
                    socketChannel.register(selector, SelectionKey.OP_READ);
                }
            }
        }
    }


    private void sendMsg(String msg) throws IOException {
        ByteBuffer responseBuffer = ByteBuffer.allocate(msg.getBytes().length);
        responseBuffer.put(msg.getBytes());
        responseBuffer.flip();
        socketChannel.write(responseBuffer);
        channel.register(selector, SelectionKey.OP_READ);
    }

    public static void main(String[] args) {
        EchoClient echoClient = null;
        try {
            echoClient = new EchoClient();
            echoClient.start();
            System.out.println("echoClient已启动");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值