有时候,采用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;
}
}