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 这是哪个作者做的宝宝起名网站
  • ¥60 版本过低apk如何修改可以兼容新的安卓系统
  • ¥25 由IPR导致的DRIVER_POWER_STATE_FAILURE蓝屏
  • ¥50 有数据,怎么建立模型求影响全要素生产率的因素
  • ¥50 有数据,怎么用matlab求全要素生产率
  • ¥15 TI的insta-spin例程
  • ¥15 完成下列问题完成下列问题
  • ¥15 C#算法问题, 不知道怎么处理这个数据的转换
  • ¥15 YoloV5 第三方库的版本对照问题
  • ¥15 请完成下列相关问题!