对nio 的selector使用的一些问题

超级呆子 发布于 2012/05/29 22:18
阅读 2K+
收藏 0

【Gopher China万字分享】华为云的Go语言云原生实战经验!>>>

大体上是需求这样:

接收线程接收到请求后转给selector线程,然后注册时间,处理读事件,只要检测到客户端有输入后(具体输入什么内容,输入多少内容可以不关心),就往客户端返回一个helloworld内容。而且客户端可以写多次,接收多次,也就是类似一个简单的长连接过程。

接收线接收到一个请求后,交给selector线程,然后由selector线程负责注册read,write事件,将数据写到客户端也是由selector线程负责的。

接收线程主要代码如下:

ServerSocketChannel server = ServerSocketChannel.open();
server.configureBlocking(true);
server.socket().bind(new InetSocketAddress("localhost",8080));

while(true) {
	SocketChannel channel = server.accept();
	channel.configureBlocking(false);
        queue.add(channel);
	selector.wakeup();
}

selector线程主要代码如下:

queue是

ConcurrentLinkedQueue<SocketChannel> queue = new ConcurrentLinkedQueue<SocketChannel>();

SocketChannel channel = queue.poll();
if(channel != null) {
	channel.register(selector, SelectionKey.OP_READ,channel);
}

int count = selector.select(5 * 1000);
if(count == 0) {
	continue;
}

Iterator<SelectionKey> iter = selector.selectedKeys().iterator();
while(iter.hasNext()) {
	SelectionKey key = iter.next();
	if(key.isConnectable()) {
		
	} else if(key.isReadable()) {
		SocketChannel schannel = (SocketChannel)key.attachment();
		buf.flip();
		while(buf.hasRemaining()) {
			schannel.write(buf);
		}
		//schannel.register(selector, key.interestOps()|SelectionKey.OP_READ, schannel);
	} else if(key.isWritable()) {
		SocketChannel schannel = (SocketChannel)key.attachment();
		buf.flip();
		schannel.write(buf);
		schannel.register(selector,SelectionKey.OP_READ,channel);
	}
	iter.remove();
}
selector.selectedKeys().clear();

问题在于

else if(key.isReadable()) 里面的部分

当检测到key可读,于是就将buf里面的内容写到客户端,buf的内容是一段html的helloworld

当第一次将数据写到客户端后,就没有任何行为了,但是

selector.select(5 * 1000);

仍然可以有key可以选择到,返回的始终是1。

我通过telnet模拟客户端访问服务端,输入telnet local 8080后,随便按一个键,结果就是不停的返回数据。

 

如果将 改为key.isReadable()最后那个被注释的那段打开并改为:

schannel.register(selector, key.interestOps()& ~SelectionKey.OP_READ, schannel);

这样当telnet连上服务端后,输入一个字符后,只会返回一遍结果。之后在telnet中怎么敲服务端都不会有响应了,通过debug可以发现,最终卡到了

selector.select(5 * 1000);

也就是没有key被检查到。

如果将key.isReadable()里面的注册事件改为对write感兴趣,那最终又变成了一个死循环,在

key.isWritable()判断可以写,于是写数据到客户端,再注册对读事件感兴趣。于是一个循环后,又到了key.isReadable(),再注册写。。。。 

所以我不清楚这个注册事件该怎么写才能达到我的要求呢?

加载中
0
超级呆子
超级呆子
是否需要在isRead(),isWrite()的时候加一个判断?增加一个阻塞队列?
0
hellomotor
hellomotor
key.isReadable(), 说明系统通知你有数据可读,但你的代码中没有读取任何数据,所以系统不断的通知你,直到你把数据读走为止。
0
超级呆子
超级呆子
果然如此,犯了一个很2的错误啊,呵呵,多谢多谢。
0
超级呆子
超级呆子
 还有一个问题,如何判断超时呢?
返回顶部
顶部