lq1115 2017-05-08 13:27 采纳率: 50%
浏览 1688
已采纳

java nio selector怎么达到与Linux select一样的效果

前几天做了一个linux下的socket实验使用了select,可以让程序在不使用多线程的情况下,实现io的异步,也就是可以收数据,也可以发数据,但不阻塞。
于是我就想能不能移植到Java下来实现。结果我发现Java也有select类似的功能,但是我发现Java nio的Chanel无法对标准输入进行处理,要发数据的时候就会阻塞。
可能是我技术不够,我想问问大家Java nio到底能不能实现与linux select一样的效果?
package server;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Scanner;
import java.nio.ByteBuffer;
import java.nio.channels.Channel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;

public class ServerSock {
public ServerSock() {
// TODO Auto-generated constructor stub
try {
ServerSocketChannel server= ServerSocketChannel.open();
server.bind(new InetSocketAddress(InetAddress.getLocalHost(), 8899), 5);
System.out.println("服务器启动....");
Selector selector = Selector.open();
server.configureBlocking(false);
server.register(selector, SelectionKey.OP_ACCEPT);

        ByteBuffer buf = ByteBuffer.allocate(48);
        SocketChannel channel = null;
        while(true){
            int a=selector.select();

            Iterator<SelectionKey> keyIter = selector.selectedKeys().iterator();
            while(keyIter.hasNext()){
                SelectionKey key = keyIter.next();
                if (key.isAcceptable()) {
                    channel = server.accept();
                    System.out.println("接受: ");
                    channel.configureBlocking(false);
                    channel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE);
                }else if (key.isReadable()) {
                    System.out.println("读取:");
                    int bytesRead = channel.read(buf);
                    buf.flip();
                    String aString = new String(buf.array()).trim();
                    System.out.println(aString);
                    buf.clear();
                }else if (key.isWritable()) {
                    System.out.println("写入:");

                    Scanner scanner = new Scanner(System.in);
                    String b = scanner.nextLine();
                    buf.put(b.getBytes());
                    buf.flip();
                    channel.write(buf);
                    buf.clear();
                }
                keyIter.remove();
            }
        }

    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}
public static void main(String[] args) {
    new ServerSock();
}

}


  • 写回答

3条回答 默认 最新

  • 高级Java进阶之路 2017-05-08 16:18
    关注

    Java中Selector实现的是非阻塞IO,异步IO需要使用JDK7中的NIO2支持,方式是使用Future或Listener来进行异步处理。看代码中
    ```else if (key.isWritable()) {
    System.out.println("写入:");

                    Scanner scanner = new Scanner(System.in);
                    String b = scanner.nextLine();
                    buf.put(b.getBytes());
                    buf.flip();
                    channel.write(buf);
                    buf.clear();```
    这里使用到的Scanner和System.in是阻塞IO的方式。新建连接总是isWriable的,所以要先注册OP_READ,等读完完整的请求后再设置OP_WRITE, 然后发送数据,判断
    是否是完整的请求可以采用一些带消息长度标识的长度字段。write时返回内容要从System.in中读取的话会阻塞整个IO处理线程,导致while循环卡住,所以最好是放到单独的线程判断要write的内容,不阻塞主的IOloop线程。还有不太清楚你描述的阻塞和不阻塞是什么样的效果
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(2条)

报告相同问题?

悬赏问题

  • ¥15 如何在scanpy上做差异基因和通路富集?
  • ¥20 关于#硬件工程#的问题,请各位专家解答!
  • ¥15 关于#matlab#的问题:期望的系统闭环传递函数为G(s)=wn^2/s^2+2¢wn+wn^2阻尼系数¢=0.707,使系统具有较小的超调量
  • ¥15 FLUENT如何实现在堆积颗粒的上表面加载高斯热源
  • ¥30 截图中的mathematics程序转换成matlab
  • ¥15 动力学代码报错,维度不匹配
  • ¥15 Power query添加列问题
  • ¥50 Kubernetes&Fission&Eleasticsearch
  • ¥15 報錯:Person is not mapped,如何解決?
  • ¥15 c++头文件不能识别CDialog