java NIO select非阻塞嵌套字 如何只监听一个通道,给这个通道发送不同的数据,并且返回数据


  有时候,采用java NIO select非阻塞嵌套字,不是为了监听多个通道,而是监听某一个通道;

给这个通道发送不同的数据,返回不同的值,

之所以不用阻塞嵌套字socket,是因为socket.read()和socket.accpet()阻塞太耗时!


package cn.com.nio;

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;

public class ServerSocketChannelDemo {
	static ServerSocketChannel serverSocketChannel;
	static Selector selector = null;
	static SelectionKey key = null;
	public static void init() {
		try {
			// 1.打开监听通道,这个通道类似于道路
			serverSocketChannel = ServerSocketChannel.open();
			// 为这个通道设置阻塞模式-不阻塞
			serverSocketChannel.configureBlocking(false);
			// 为这个通道绑定监听的端口号
			serverSocketChannel.socket().bind(new InetSocketAddress(6031));
			// 开启选择器 类似于道路管理员
			selector = Selector.open();
			// 把通道注册到选择器上面
			serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	public static void main(String[] args) {
		init();
		//这里执行两次的原因是,第一次监听,第二次是读取数据
		for(int i=0;i<2;i++) {
			try {
				// select()阻塞到至少有一个通道在你注册的事件上就绪了
				// 如果没有准备好的channel,就在这一直阻塞
				// select(long timeout)和select()一样,除了最长会阻塞timeout毫秒(参数)。
				selector.select();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			// 返回已经就绪的SelectionKey,然后迭代执行
			Set readKeys = selector.selectedKeys();
			Iterator it = readKeys.iterator();
			key = it.next();
			if(true) {	
				// 把当前的移除,
				it.remove();
				SocketChannel client = null;
				try {
					// 如果有新的连接
					if (key.isAcceptable()) {
						// 获取新的连接
						ServerSocketChannel server = (ServerSocketChannel) key
								.channel();
						// 服务器和传感器之间建立连接
						client = server.accept();
						// 设置不阻塞模式
						client.configureBlocking(false);
						// 开始为这个通道绑定可写事件属性
						client.register(selector, SelectionKey.OP_WRITE);
					
					}
					// 当新的连接建立以后,如果这个通道有可写的属性,就这个里面执行,
					if (key.isWritable()) {
						for(int keys=0;keys<7;keys++){
							// 获取通道,
							client = (SocketChannel) key.channel();
							// 开始创建一个静态的缓存区,这个ByteBuffer就是相当于装载数据的大卡车
							ByteBuffer buffer = ByteBuffer.allocate(8);
							System.out.println("通道"+keys+"开始发送数据....");
							byte [] by=SocketRead.returnBytes(keys);
							SocketRead.writeData(buffer, client, by);
							buffer.flip();
							//key.interestOps(SelectionKey.OP_READ);
							// 开启延迟,如果没有延迟就接受不到数据,程序运行的比接受数据的时间还要短
							key.cancel();
							// 延迟几秒以后在执行下面的任务,程序运行的比接受数据的时间还要短
							SocketRead.ready(client);
							if(keys==6){
								keys=-1;
							}
						}
					}
				
				
				} catch (IOException e) {
					e.printStackTrace();
					key.cancel();
					try {
						key.channel().close();
					} catch (IOException e1) {
						// TODO Auto-generated catch block
						e1.printStackTrace();
					}
				}
			}
		}
	}

}

 

 

package cn.com.nio;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.SocketChannel;
public class SocketRead {
/*author:命运的信徒
 * date:2019/1/22
 * arm:负责读取数据和写入数据
 */
	//读取数据
	public static String ready(SocketChannel client){
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		//创建一个缓存区,接受、发送数据必备的工具
		ByteBuffer readBuff = ByteBuffer.allocate(1024);
		//清理缓存区,不然会接受到以前的信息,不准确
		readBuff.clear();
		//开始读取数据
		int f=0;
		try {
			f = client.read(readBuff);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println("接受数据的长度是:" + f);
		StringBuilder sn = new StringBuilder();
		if (f > 0) {
			//flip():Buffer有两种模式,写模式和读模式。在写模式下调用flip()之后,Buffer从写模式变成读模式。      
			readBuff.flip();
			//新建一个byte类型的数组
			byte[] bytes = new byte[7];
			//把数据放在byte类型的数组里面
			readBuff.get(bytes, 0, f);
			//对数据bytes里面的数据进行16进制的转化
			for (int i = 0; i < bytes.length; i++) {
				int a = bytes[i] & 0xff;
				String w = Integer.toHexString(a);
				if (w.length() == 1) {
					w = "0" + w;
				}
				sn.append(w);
			}
		}
          //打印数据
		System.out.println("received : " + sn);
		readBuff.flip();
		
		return sn.toString();
	}
	//写数据
	public static void writeData(ByteBuffer buffer,SocketChannel client,byte [] by){		
		//把数据放在buffer里面
		buffer = ByteBuffer.wrap(by);
		//写数据
		try {
			client.write(buffer);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		//这个是为读取数据做准备
		////flip():Buffer有两种模式,写模式和读模式。在写模式下调用flip()之后,Buffer从写模式变成读模式。      
		buffer.flip();
		
	}
	//根据keys值返回相应的byte数组
	public static byte[] returnBytes(int keys){
		byte[] by = new byte[8];
		by[0]=03;
		by[1]=03;
		by[2]=00;
		by[3]=(byte) (keys+2);
		by[4]=00;
		by[5]=01;
		switch(keys){
		case 0:by[6]=36;by[7]=40;break;
		case 1:by[6]=117;by[7]=(byte) 232;break;
		case 2:by[6]=(byte) 196;by[7]=41;break;
		case 3:by[6]=(byte) 149;by[7]=(byte) 233;break;
		case 4:by[6]=101;by[7]=(byte) 233;break;
		case 5:by[6]=52;by[7]=41;break;
		case 6:by[6]=04;by[7]=42;break;
		}
		return by;
	}
}

 

你可能感兴趣的:(socket通讯专栏)