msh24 2011-12-30 10:57
浏览 638
已采纳

java nio SelectionKey isWritable为什么一直是true

服务器
[code="java"]
package test.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.util.Iterator;
import java.util.Set;

public class NonBlockEchoServer {

private ServerSocketChannel serverSocketChannel;
private int port = 8992;
private Selector selector;
private Charset charset;

public NonBlockEchoServer() throws IOException {
    charset = Charset.forName("UTF-8");
    selector = Selector.open();
    serverSocketChannel = ServerSocketChannel.open();
    //可以绑定到同一个端口
    serverSocketChannel.socket().setReuseAddress(true);
    //设置为非阻塞模式
    serverSocketChannel.configureBlocking(false);
    serverSocketChannel.socket().bind(new InetSocketAddress(port));
}

public void service() throws IOException {
    serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
    while(selector.select() > 0) {
        Set<SelectionKey> keys = selector.selectedKeys();
        Iterator<SelectionKey> it = keys.iterator();
        while(it.hasNext()) {
            SelectionKey key = null;
            try {
                key = it.next();
                it.remove();
                if(key.isAcceptable()) {
                    ServerSocketChannel serverSocketChannel = (ServerSocketChannel) key.channel();
                    SocketChannel socketChannel = serverSocketChannel.accept();
                    socketChannel.configureBlocking(false);
                    ByteBuffer byteBuffer = ByteBuffer.allocate(0);
                    socketChannel.register(selector, SelectionKey.OP_READ|SelectionKey.OP_WRITE, byteBuffer);
                }
                if(key.isReadable()) {
                    read(key);
                }
                if(key.isWritable()) {
                    write(key);
                }
            }catch (IOException e) {
                if(key != null) {
                    try {
                        key.cancel();
                        key.channel().close();
                    } catch (IOException e1) {
                        e1.printStackTrace();
                    }
                }
                e.printStackTrace();
            }
        }
    } 
}

private void write(SelectionKey key) throws IOException {
    SocketChannel socketChannel = (SocketChannel) key.channel();
    ByteBuffer byteBuffer = (ByteBuffer) key.attachment();
    byteBuffer.flip();
    String data = decode(byteBuffer);

    if(data.indexOf("\r\n") == -1) {
        return;
    }
    String outputData = data.substring(0, data.indexOf("\n")+1);
    System.out.println("--->" + outputData);
    ByteBuffer outputBuffer = encode("echo:" + outputData);
    while(outputBuffer.hasRemaining()) {
        socketChannel.write(outputBuffer);
    }

    ByteBuffer temp = encode(outputData);
    byteBuffer.position(temp.limit());

    byteBuffer.compact();

    if(outputData.equals("bye\r\n")) {
        key.cancel();
        socketChannel.close();
        System.out.println("链接已经关闭");
    }
}

private void read(SelectionKey key) throws IOException {
    System.out.println("server read");
    SocketChannel socketChannel = (SocketChannel) key.channel();
    socketChannel.configureBlocking(false);
    ByteBuffer byteBuffer = (ByteBuffer) key.attachment();
    ByteBuffer readBuff = ByteBuffer.allocate(32);
    socketChannel.read(readBuff);
    byteBuffer.limit(byteBuffer.capacity());
    readBuff.flip();
    byteBuffer.put(readBuff);
}

/**
 * 解码
 * @param byteBuffer
 * @return
 */
private String decode(ByteBuffer byteBuffer) {
    CharBuffer charBuffer = charset.decode(byteBuffer);
    return charBuffer.toString();
}

/**
 * 编码
 * @param str
 * @return
 */
private ByteBuffer encode(String str) {
    return charset.encode(str);
}

public static void main(String[] args) throws IOException {
    NonBlockEchoServer nonServer = new NonBlockEchoServer();
    nonServer.service();
}

}

[/code]
客户端
[code="java"]
package test.nio;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
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.nio.charset.Charset;
import java.util.Iterator;
import java.util.Set;

public class NonBlockEchoClient {

private SocketChannel socketChannel;
private ByteBuffer sendBuffer = ByteBuffer.allocate(1024);
private ByteBuffer receiveBuffer = ByteBuffer.allocate(1024);
Charset charset = Charset.forName("utf-8");
private Selector selector;
private int port = 8992;

public NonBlockEchoClient() throws IOException {
    socketChannel = SocketChannel.open();
    socketChannel.connect(new InetSocketAddress(port));
    socketChannel.configureBlocking(false);
    System.out.println("与服务器链接成功");
    selector = Selector.open();
}

public static void main(String[] args) throws IOException {
    final NonBlockEchoClient non = new NonBlockEchoClient();
    Thread client = new Thread(new Runnable() {
        @Override
        public void run() {
            non.receiveFromUser();
        }
    });
    client.start();
    non.talk();
}

private void talk() throws IOException {
    socketChannel.register(selector, SelectionKey.OP_READ|SelectionKey.OP_WRITE);
    while(selector.select() > 0) {
        Set<SelectionKey> keys = selector.selectedKeys();
        Iterator<SelectionKey> it = keys.iterator();
        while(it.hasNext()) {
            SelectionKey key = it.next();
            it.remove();
            if(key.isReadable()) {
                receive(key);
            }
            if(key.isWritable()) {
                send(key);
            }
        }
    }
}

public void receiveFromUser() {
    try {
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
        String msg = null;
        while((msg = bufferedReader.readLine()) != null) {
            System.out.println(msg);
            synchronized (sendBuffer) {
                sendBuffer.put(encode(msg+"\r\n"));
            }

            if("bye".equals(msg)) {
                break;
            }
        }
    } catch(IOException e) {
        e.printStackTrace();
    }
}

private void send(SelectionKey key) throws IOException {
    SocketChannel socketChannel = (SocketChannel) key.channel();
    synchronized (sendBuffer) {
        sendBuffer.flip();
        socketChannel.write(sendBuffer);
        sendBuffer.compact();
    }
}

private void receive(SelectionKey key) throws IOException {
    System.out.println("client RECEIVE");
    SocketChannel socketChannel = (SocketChannel) key.channel();
    socketChannel.read(receiveBuffer);
    receiveBuffer.flip();
    String receiveData = decode(receiveBuffer);

    if(receiveData.indexOf("\n") == -1) return;

    String outputData = receiveData.substring(0, receiveData.indexOf("\n") + 1);
    System.out.println("--->" + outputData);

    if(outputData.equals("echo:bye\r\n")) {
        key.cancel();
        socketChannel.close();
        selector.close();
        System.exit(0);
    }

    ByteBuffer temp = encode(outputData);
    receiveBuffer.position(temp.limit());
    receiveBuffer.compact();
}

private String decode(ByteBuffer byteBuffer) {
    return charset.decode(byteBuffer).toString();
}

private ByteBuffer encode(String str) {
    return charset.encode(str);
}

}

[/code]

各位大侠,最近小弟在学习nio编程,遇到一个问题:客户端在连接服务器端成功后,没有进行任何操作,服务器端并没有触发 写事件 为什么key.isWritable()一直为true ??

  • 写回答

1条回答

  • anranran 2012-01-03 15:19
    关注

    key.isWritable()是表示Socket可写,网络不出现阻塞情况下,一直是可以写的,所认一直为true.一般我们不注册OP_WRITE事件.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 sqlite 附加(attach database)加密数据库时,返回26是什么原因呢?
  • ¥88 找成都本地经验丰富懂小程序开发的技术大咖
  • ¥15 如何处理复杂数据表格的除法运算
  • ¥15 如何用stc8h1k08的片子做485数据透传的功能?(关键词-串口)
  • ¥15 有兄弟姐妹会用word插图功能制作类似citespace的图片吗?
  • ¥200 uniapp长期运行卡死问题解决
  • ¥15 latex怎么处理论文引理引用参考文献
  • ¥15 请教:如何用postman调用本地虚拟机区块链接上的合约?
  • ¥15 为什么使用javacv转封装rtsp为rtmp时出现如下问题:[h264 @ 000000004faf7500]no frame?
  • ¥15 乘性高斯噪声在深度学习网络中的应用