[java]NIO SocketChannel read使用说明

这篇文章只是说说简单的使用,内容不难,很简单很基础。

如果说错了希望纠正。

最近在做NIO的服务器端和客服端开发(虽然有mina 但是自己从头写感觉会好一点 当做练习的话)

 

SocketChannel有两种模式:blocking模式(和原来的Socket类似)和non-blocking模式(不会堵塞)

 

在两种模式下的读写操作是不一样的。 写比较好理解,非堵塞下可能会一个字节都不写(缓存区满了 堵塞的这种情况就是堵塞在那了)

在非堵塞模式下只要用while判断一下ByteBuffer的remaining就可以了:

	public void write(ByteBuffer byteBuffer) throws IOException {
		byteBuffer.flip();
		while(byteBuffer.hasRemaining()){
			sc.write(byteBuffer);
		}
	}

 

 

接下来说说read  read的返回参数有三个

正整数 0和-1

 

正整数在堵塞和非堵塞模式中意义是一样的,就是读入了多少个字节。

 

0的话涵义不同:

  • 在堵塞中,如果返回0就说明服务器发送了请求但请求内容为空.
  • 在非堵塞模式中,如果在read的时候流中暂时还没内容那么返回的也是0(堵塞中没有内容就堵塞在那了).

 

-1都表示连接已经断开(单向的连接 比如用shutdonwInput把Input流断开了 read就返回-1 但直接close的话 会返回一个java.nio.channels.ClosedChannelException的异常

 

有几个实验来证明以上的 实验都是连接www.baidu.com 百度现在用的最多的就是编程中测试了....

	// 阻塞模式下 没有发送请求就read 会一直堵在read方法里
        @Test
	public void testSocketChannel(){
		InetSocketAddress address=new InetSocketAddress("www.baidu.com",80);
		try {
			SocketChannel sc=SocketChannel.open(address);
		    ByteBuffer bb=ByteBuffer.allocate(1024);
                  //sc.configureBlocking(false);
			System.out.println(sc.read(bb));
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

 然后把注释去掉设置成非阻塞模式,就可见读回了0.

 然后是-1的返回情况:

 

        //阻塞和非阻塞一样 这都会返回-1 因为通道已经断了(end-of-stream的意思应该理解成断开比较好吧)
	@Test
	public void testSocketChannel(){
		InetSocketAddress address=new InetSocketAddress("www.baidu.com",80);
		try {
			SocketChannel sc=SocketChannel.open(address);
		    ByteBuffer bb=ByteBuffer.allocate(1024);
		    sc.configureBlocking(false);
		    sc.shutdownInput();
			System.out.println(sc.read(bb));
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

 

 

 

好接下去的实验就让他接受百度返回的回应:

为了看得清楚就写成死循环不断读了,堵塞的情况:

	@Test
	public void testSocketChannel2(){
		InetSocketAddress address=new InetSocketAddress("www.baidu.com",80);
		try {
			SocketChannel sc=SocketChannel.open(address);
			Charset charset=Charset.forName("UTF-8");
		    ByteBuffer bb=ByteBuffer.allocate(1024);
		    String send="GET / HTTP/1.1\r\n\r\n";
                 //sc.configureBlocking(false);
		    sc.write(charset.encode(send));
			while(true){
				bb.clear();
				System.out.println(sc.read(bb));
				bb.flip();
				System.out.println(charset.decode(bb).toString());
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

 输出完后就一直卡在read里了 返回内容太长我就不打出来了

 然后把注释去掉变为非阻塞的话,接下去除了输出完内容外就是不断地打0了 

 

这里也说明不管用堵塞模式和非堵塞模式 用 read()!=-1来判断一次请求已经读完是多么不靠谱 堵塞模式会堵塞还好 非堵塞模式用0来判断还是不错的 这边实验性地写一下有关非堵塞模式完整读完一次请求的(当然只是试验性写一下 正常使用结合Selector写不用担心我这边试验代码的一些问题):

	@Test
	public void testSocketChannel2(){
		InetSocketAddress address=new InetSocketAddress("www.baidu.com",80);
		try {
			SocketChannel sc=SocketChannel.open(address);
			Charset charset=Charset.forName("UTF-8");
		    ByteBuffer bb=ByteBuffer.allocate(1024);
		    String send="GET / HTTP/1.1\r\n\r\n";
		    sc.configureBlocking(false);
		    sc.write(charset.encode(send));
		    try {
				Thread.sleep(5000); //给予足够的时间让服务器返回信息 不然下面直接返回0
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		    //0 -->如果没有信息读入 或者已经把信息读完了
		    //-1-->输入的channel已经关闭了
			while(sc.read(bb)>0){
				if(bb.remaining()<bb.capacity()*0.02){
					ByteBuffer nbb=ByteBuffer.allocate(bb.capacity()*2);
					bb.flip();
					nbb.put(bb);
					bb=nbb;
					System.out.println(bb.capacity());
				}
			}
			bb.flip();
			System.out.println(charset.decode(bb).toString());
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

 

 

你可能感兴趣的:(SocketChannel)