InetSocketAddress ia = new InetSocketAddress("www.baidu.com", 80); SocketChannel socket = SocketChannel.open(ia); socket.configureBlocking(false); byte[] get = "GET / HTTP/1.1\r\nHost:www.baidu.com\r\n\r\n".getBytes(); ByteBuffer gets = ByteBuffer.allocate(get.length); gets.put(get); gets.flip(); socket.write(gets); ByteBuffer buf = ByteBuffer.allocate(1024); int len = -1; Thread.sleep(100); while((len=socket.read(buf)) > 0) { buf.flip(); System.out.println(new String(buf.array(),0,buf.limit(),"GBK")); buf.clear(); }
当设置了非阻塞模式后,如果立马就去读取远程主机的数据,会返回0。如果等待一段时间,比如100毫秒,再去读取,则正常。
不清楚NIO内部怎么实现的,但第一次真正读取返回数据之前,似乎有一些准备工作,或者因为写"GET / HTTP/1.1" 数据包还没有真正发送到服务端,就开始读了,导致服务端还没有数据返回。
有没有什么办法能判断出第一次读的时候所有必备条件都已经准备好了。
或者有什么API能判断?
问题不错######设置了非阻塞模式就需要用selector来做了,你这样sleep根据网络条件来的,而且如果缓冲区弄小一点的话,你这样sleep也是不成立的,我改了一个用selector的,希望对你有点帮助
SocketChannel socketChannel = SocketChannel.open(); SocketAddress remote = new InetSocketAddress("www.baidu.com", 80); socketChannel.configureBlocking(false); socketChannel.connect(remote);
Selector selector = Selector.open();
socketChannel.register(selector, SelectionKey.OP_CONNECT); // 关注连接事件
byte[] get = "GET / HTTP/1.1\r\nHost:www.baidu.com\r\n\r\n".getBytes();
ByteBuffer buf = ByteBuffer.wrap(get);
while(true) {
if(selector.select() == 0) {
continue;
}
for(Iterator<SelectionKey> iter = selector.selectedKeys().iterator();iter.hasNext();) {
SelectionKey key = iter.next();
if(key.isConnectable()) {
if(socketChannel.finishConnect()) { // 初始化连接获得 clientsocket
buf.put(get);
buf.flip();
socketChannel.register(selector, SelectionKey.OP_WRITE); // 连接成功关注写事件
}
}
if(key.isWritable()) {
if(buf.hasRemaining()) {
socketChannel.write(buf);
} else { //写入完毕,开始关注读取
socketChannel.register(selector, SelectionKey.OP_READ);
}
}
if(key.isReadable()) {
buf.clear();
if(socketChannel.read(buf) >= 0 ) {
buf.flip();
System.out.print(new String(buf.array(),0,buf.limit(),"GBK"));
}
}
iter.remove();
}
}</pre>
######多谢楼上的兄弟,不过我发现还是有个问题,原因出在这里
if(selector.select() == 0) { continue; }
看了文档,selector.select() 使用的是阻塞的方式,最终是当所有的数据接收到后,又一次执行了
selector.select(),结果就卡在那里了,等了一段时间超时就自己退出了。
如果将if(key.isReadable()) 改为这样:
if(key.isReadable()) { buf.clear(); while(socket.read(buf) > 0) { buf.flip(); System.out.print(new String(buf.array(), 0, buf.limit(),"GBK")); buf.clear(); } break done; }
这样也不行,虽然瞬间就退出了,也没阻塞,但是读取的数据不完整,可能有时候就是会读取到0个字节的数据,但是此时的返回的数据流还没有真正的结束。看来在if(key.isReadable())里面写个循环读取也不靠谱。另外写成 selector.selectNow()也不行。
######建议你再去看看nio方面的东西,非阻塞模式的精髓就是那个select######看了一下,selector作为多线程之间的交互,接受线程当接受到请求之后,将socket注册到selector,注册为已经接受连接,然后继续等待接受。
select线程就处理是请求已经完成了连接建立,读,写准备好的检查,如果都已经完成,则交给工作线程去完成。大体上是分这么三步骤的。
不过如果是客户端的也这么做的话, 当完成了读写逻辑之后,接受线程会再次等待接受,这样程序还是会卡在那里,最多只能加一个超时时间然后退出。
######楼主的例子 貌似跑不起来啊
版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。