NIO(九) - 非阻塞式Socket双向通信

9 篇文章 0 订阅

服务端

package com.xbb.demo.twoway;

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.Scanner;

/**
 * 服务端
 */
public class NonServerSocket {

    public static void main(String[] args) {
        try(
                ServerSocketChannel socketChannel = ServerSocketChannel.open().bind(new InetSocketAddress(9999));
        ){
            String receMsg = "";
            // 切换成非阻塞模式
            socketChannel.configureBlocking(false);
            // 获取一个选择器
            Selector selector = Selector.open();
            /**
             * 把选择器注册到通道上并监听接收
             * 参数一 : 所以注册的选择器
             * 参数二 : SelectionKey
             *      表示 SelectableChannel与Selector之前的关系,每次注册的时候需要选择一个事件.
             *      有四种状态:
             *      SelectionKey.OP_ACCEPT  : 接收
             *      SelectionKey.OP_CONNECT : 连接
             *      SelectionKey.OP_READ    : 读
             *      SelectionKey.OP_WRITE   : 写
             *      如果需要监听多个可以通过竖线串起来
             *
             */
            socketChannel.register(selector, SelectionKey.OP_ACCEPT);
            // 通过循环式的获取选择器上已经"准备就绪"的事件
            // 当选择器上有"准备就绪"的状态时,他的select值会大于0
            while(selector.select() > 0){
                // 所以所有准备就绪的选择器
                Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
                while (iterator.hasNext()){
                    SelectionKey key = iterator.next();
                    if (key.isAcceptable()){
                        // 获取一个阻塞式的Channle
                        SocketChannel sChannel = socketChannel.accept();
                        // 设置他为非阻塞式
                        sChannel.configureBlocking(false);
                        // 注册到选择器 监听读操作
                        sChannel.register(selector,SelectionKey.OP_READ);
                    }else if(key.isReadable()){
                        // 从选择器中获取当前Channel
                        SocketChannel sChannel = (SocketChannel) key.channel();
                        ByteBuffer buf = ByteBuffer.allocate(1024);
                        int len = 0;
                        // 读取客户端发来的消息
                        while((len = sChannel.read(buf)) > 0){
                            buf.flip();
                            receMsg = new String(buf.array(),0,len);
                            System.out.println("来自客户端的消息 : " + receMsg);
                            buf.clear();
                        }
                        // 切换到监听写模式
                        sChannel.register(selector,SelectionKey.OP_WRITE);
                    }else if (key.isWritable()){
                        SocketChannel sChannel = (SocketChannel) key.channel();
                        if ("".equals(receMsg)){
                            sChannel.register(selector,SelectionKey.OP_READ);
                        }else{
                            ByteBuffer buf = ByteBuffer.allocate(1024);
//                            String msg = receMsg + " -- Hello ";
//                            buf.put(msg.getBytes());
                            // 从控制台写入消息并发出去
                            Scanner scanner = new Scanner(System.in);
                            while(scanner.hasNext()){
                                buf.put(scanner.next().getBytes());
                                break;
                            }
                            buf.flip();
                            receMsg = "";
                            sChannel.write(buf);
                        }
                    }
                    iterator.remove();
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

客户端

package com.xbb.demo.twoway;

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.Scanner;

/**
 * 客户端
 */
public class NonClientSocket {

    public static void main(String[] args) {
        try(
                // 创建Socket客户端
                SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress("192.168.93.44",9999));
        ){
            String responseMsg = "";
            boolean isFirst = true;
            // 切换非阻塞模式
            socketChannel.configureBlocking(false);
            // 创建选择器
            Selector selector = Selector.open();
            // 注册选择器,监听读写
            socketChannel.register(selector, SelectionKey.OP_WRITE,SelectionKey.OP_READ);
            while(selector.select() > 0){
                Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
                while(iterator.hasNext()){
                    SelectionKey next = iterator.next();
                    // 写操作,发送消息
                    if (next.isWritable()){
                        socketChannel.register(selector,SelectionKey.OP_READ);
                        // 第一个消息由客户端发出
                        if(isFirst){
                            isFirst = false;
                            SocketChannel sChannel = (SocketChannel) next.channel();
                            sChannel.configureBlocking(false);
                            // 本次发送出去消息后切换为读模式,读服务器回馈的消息

                            ByteBuffer buf = ByteBuffer.allocate(1024);
                            // 从控制台输入消息并发出去
                            Scanner scanner = new Scanner(System.in);
                            while(scanner.hasNext()){
                                buf.put(scanner.next().getBytes());
                                break;
                            }
                            buf.flip();
                            sChannel.write(buf);
                            buf.clear();
                        // 如果不是第一次,判断是否收到对方回馈的消息
                        }else{
                            if(!"".equals(responseMsg)){
                                SocketChannel sChannel = (SocketChannel) next.channel();
                                sChannel.configureBlocking(false);
                                ByteBuffer buf = ByteBuffer.allocate(1024);
                                Scanner scanner = new Scanner(System.in);
                                while(scanner.hasNext()){
                                    buf.put(scanner.next().getBytes());
                                    break;
                                }
                                buf.flip();
                                sChannel.write(buf);
                                buf.clear();
                            }
                        }
                        responseMsg = "";

                    }else if (next.isReadable()){
                        SocketChannel sChannel = (SocketChannel)next.channel();
                        ByteBuffer buf = ByteBuffer.allocate(1024);
                        int len = 0;
                        while((len = sChannel.read(buf)) > 0){
                            buf.flip();
                            responseMsg = new String(buf.array(),0,len);
                            System.out.println("来自服务端的消息 : " + responseMsg);
                            buf.clear();
                        }
                        socketChannel.register(selector,SelectionKey.OP_WRITE);
                    }
                    iterator.remove();
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值