java NIO socket 通信实例

版权声明:本文为博主原创文章,未经博主同意不得转载。 https://blog.csdn.net/zhuyijian135757/article/details/37672151

java Nio 通信与Bio通信主要不同点:

1.Nio中的单个channel就可以支持读操作也能够支持写操作,而bio中读操作要用inputstream,写操作要outputstream.

2.nio 採用byteBuffer 作为内存缓存区,向channel里写或者度操作,bio基本是用byte[]

3.nio採用 selector组件轮询读取就绪channel


服务端demo代码:

package com.my.socket3;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

import com.sun.xml.internal.messaging.saaj.util.ByteOutputStream;

public class ServerTest {

	public static void main(String[] args) throws Exception {
		server();
	}
	
	public static void server(){
		ServerSocketChannel channel=null;
		try{
			
			Selector selector=Selector.open();
			channel=ServerSocketChannel.open();
			channel.configureBlocking(false);
			channel.socket().setReuseAddress(true); 
			channel.bind(new InetSocketAddress(8020));
			channel.register(selector, SelectionKey.OP_ACCEPT,new Integer(1));
				
			while(true){
				if(selector.select()>0){
					Set<SelectionKey> sets=selector.selectedKeys();
					Iterator<SelectionKey> keys=sets.iterator();
					while(keys.hasNext()){
						SelectionKey key=keys.next();
						keys.remove();
						
						if(key.isAcceptable()){
							key.attach(new Integer(1));
							SocketChannel schannel=((ServerSocketChannel) key.channel()).accept();
							schannel.configureBlocking(false);
							schannel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE);
						}
						
						if(key.isReadable()){
							SocketChannel schannel=(SocketChannel) key.channel();
							ByteBuffer buf=ByteBuffer.allocate(1024);
							ByteOutputStream output=new ByteOutputStream();
							int len=0;
							while((len=schannel.read(buf))!=0){
								buf.flip();
								byte by[]=new byte[buf.remaining()];
								buf.get(by);
								output.write(by);
								buf.clear();
							}
							String str=new String(output.getBytes());
							key.attach(str);
						}
						
						if(key.isWritable()){
							
							Object object=key.attachment();
							String attach=object!=null ? "server replay: "+object.toString() : "server replay: ";
							SocketChannel schannel=(SocketChannel) key.channel();
							schannel.write(ByteBuffer.wrap(attach.getBytes()));  
						}
					}
				}
			}
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			if(channel!=null){
				try {
					channel.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		
	}
}

客户端demo代码

package com.my.socket3;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
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.util.Iterator;
import java.util.Set;

public class ClientTest {

	public static void main(String[] args) throws Exception {
				client();
	}
	
	public static void client() {
		SocketChannel channel=null;
		try {
			
			Selector selector=Selector.open();
			channel = SocketChannel.open();
			channel.configureBlocking(false);
			channel.connect(new InetSocketAddress(8020));
			channel.register(selector, SelectionKey.OP_CONNECT);
			
			while(true){
				if(selector.select()>0){
					
					Iterator<SelectionKey> set=selector.selectedKeys().iterator();
					while(set.hasNext()){
						SelectionKey key=set.next();
						set.remove();
						
						SocketChannel ch=(SocketChannel) key.channel();
						if(key.isConnectable()){
							ch.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE,new Integer(1));
							ch.finishConnect();
						}
						
						if(key.isReadable()){
							key.attach(new Integer(1));
							ByteArrayOutputStream output=new ByteArrayOutputStream();
							ByteBuffer buffer=ByteBuffer.allocate(1024);
							int len=0;
							while((len=ch.read(buffer))!=0){
								buffer.flip();
								byte by[]=new byte[buffer.remaining()];
								buffer.get(by);
								output.write(by);
								buffer.clear();
							}
							System.out.println(new String(output.toByteArray()));
							output.close();
						}
						
						if(key.isWritable()){
							key.attach(new Integer(1));
							ch.write(ByteBuffer.wrap((("client say:hi")).getBytes()));
						}
					}
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			try {
				channel.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	
	static class ClientRunnable implements Runnable{

		private SocketChannel ch;
		
		private ClientRunnable(SocketChannel ch){
			this.ch=ch;
		}
		
		@Override
		public void run() {
			try {
				while(true){
					ch.write(ByteBuffer.wrap((("client say:hi")).getBytes()));
					Thread.sleep(5000);
				}
			} catch (Exception e) {
				e.printStackTrace();
				try {
					ch.close();
				} catch (IOException e1) {
					e1.printStackTrace();
				}
			}
		}
	}
	

}

跑demo时遇到的问题

1.客户端须要进行 ch.finishiCnonnect()操作,否则两边都堵塞着

2.读channel中的bytebuffer时, while((len=ch.read(buffer))!=0) 推断不要写成while((len=ch.read(buffer))!=-1) 

假设SocketChannel被设置为非堵塞,则它的read操作可能返回三个值:
1) 大于0,表示读取到了字节数。
2) 等于0。没有读取到消息,可能TCP处于Keep-Alive状态,接收到的是TCP握手消息。
3) -1,连接已经被对方合法关闭。


猜你喜欢

转载自www.cnblogs.com/ldxsuanfa/p/10919724.html