用IO,NIO,MINA三种方式抓百度,返回结果大不同

超级呆子 发布于 2012/01/31 11:53
阅读 5K+
收藏 6

采用阻塞IO,NIO,MINA三种方式去抓取百度首页,打印出首页的内容。我发现NIO和MINA返回的结果跟阻塞IO返回的结果不同,尤其是MINA,差别很大。JDK版本为1.6.0_29

首先是阻塞方式的IO去连接:

        Socket socket = new Socket("www.baidu.com", 80);
        OutputStream os = socket.getOutputStream();
        os.write("GET / HTTP/1.1\r\n".getBytes());
        os.write("Host:www.baidu.com\r\n\r\n".getBytes());
        os.flush();
       
        InputStream is = socket.getInputStream();
        String line = null;
        BufferedReader br = new BufferedReader(new InputStreamReader(is));
       
        while((line=br.readLine()) != null) {
            System.out.println(line);

        }

 

之后将返回的结果保存为一个html文件,a.html

 

第二次,使用NIO的方式抓取百度

            InetSocketAddress socketAddress = new InetSocketAddress(
                    "www.baidu.com", 80);

            channel = SocketChannel.open(socketAddress);
            //channel.configureBlocking(false);   使用阻塞或者非阻塞的方式返回结果都一样
           
            byte[] buf = "GET / HTTP/1.1\r\nHost:www.baidu.com\r\n\r\n".getBytes();
            ByteBuffer bb = ByteBuffer.allocate(buf.length);
            bb.put(buf);
            bb.flip();
            channel.write(bb);

            ByteBuffer buffer = ByteBuffer.allocate(1024);
            while (channel.read(buffer) != -1) {
                buffer.flip();
                if(buffer.limit() > 0) {
                    System.out.println(new String(buffer.array()));
                }
                buffer.clear();
            }

将返回结果保存为b.html

 

最后是用MINA:

        NioSocketConnector connector = new NioSocketConnector();
        DefaultIoFilterChainBuilder chain = connector.getFilterChain();

        chain.addLast("myChin", new ProtocolCodecFilter(
                new TextLineCodecFactory()));
       
        connector.setHandler(new ClientHandle());
        connector.setConnectTimeout(30);
        ConnectFuture cf = connector.connect(new InetSocketAddress("www.baidu.com",80));

        cf.awaitUninterruptibly();
        cf.getSession().getCloseFuture().awaitUninterruptibly();
        connector.dispose();

 

ClientHandle类:

public class ClientHandle extends IoHandlerAdapter {
    @Override
    public void messageReceived(IoSession session, Object message)
    throws Exception {
        System.out.println(message);
    }

    @Override
    public void messageSent(IoSession session, Object message) throws Exception {
        System.out.println(message);
    }

    @Override
    public void sessionOpened(IoSession session) throws Exception {
        session.write("GET / HTTP/1.0\r\n");

//        session.write("GET / HTTP/1.1\r\n");
//        session.write("Host:www.baidu.com\r\n\r\n");
    }
}

用MINA采用HTTP1.0和HTTP1.1的方式返回结果都是一样的。

将mina返回的结果保存为c.html

 

最后将这三个html都打开,对比正常的www.baidu.com页面,发现阻塞IO获取到的结果是正确的,和原始的baidu首页是一模一样,而NIO获取到的有一点点不同,主要是在格式上有一点不同。但是MINA差别就非常大了。从对比来看,阻塞IO返回的内容应该是完全正确的,NIO好像少了一点内容。

这里我弄不清楚的是,为什么NIO和阻塞IO获取的结果会不同,将NIO设置为阻塞的方式返回的结果还是跟阻塞IO有差别。而MINA则很离谱了,返回的结果跟原始的百度页面差很多,似乎是一些数据没获取到,不知道为什么。

加载中
0
GETMISTAKE
GETMISTAKE
应该是你代码的问题
0
超级呆子
超级呆子

又试了一下NIO的方式,代码如下:

        InetSocketAddress ia = new InetSocketAddress("www.baidu.com",80);
        SocketChannel socket = SocketChannel.open(ia);
        String header = "GET / HTTP/1.1\r\nHost:www.baidu.com\r\n\r\n";
        byte[] buf = header.getBytes();
        ByteBuffer bb = ByteBuffer.allocate(buf.length);
        bb.put(buf);
        bb.flip();
        socket.write(bb);
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        while(socket.read(buffer) != -1) {
            buffer.flip();
            //if(buffer.limit() > 0) {
                System.out.print(new String(buffer.array()));
            //}
            buffer.clear();
        }

 

这回返回的内容,保存为html后打开,显示的结果跟正常的百度就非常类似了,但是却多收到了一些内容:

 

 

如果是阻塞IO,到红框那段后面就没有了,但是NIO收到的结果却多出了一些内容。

我不知道哪里有问题,请指教。

0
wad12302
wad12302

使用mina时候看看编码转换问题是否有影响

网页是别人的,不好控制,调试起来不方便

或者你自己起个jsp界面然后用3中方式获取看看,

0
ExtremeTalk
ExtremeTalk
Mina获得数据可能只是一部分,得继续读取后面还有
0
依然范特西
依然范特西

是什么问题呢、楼主解决了吗?@超级呆子

0
0x0001
0x0001
NIO 收到那多余的部分其实是上一次的在bytebuffer中的缓存,
             if(buffer.limit() > 0) {
                 System.out.println(new String(buffer.array()));
             }
上面这段代码修改为:
while(buffer.hasRemaining()) {
            byte[] ret = new byte[buffer.limit()];
            buffer.get(ret,0,ret.length);
            System.out.print(new String(ret));
             }
就正常了
如果是阻塞IO,到红框那段后面就没有了,但是NIO收到的结果却多出了一些内容。 我不知道哪里有问题,请指教。

返回顶部
顶部