java

位置:IT落伍者 >> java >> 浏览文章

疯狂Java讲义:使用NIO实现非阻塞Socket通信(2)[1]


发布日期:2021年08月14日
 
疯狂Java讲义:使用NIO实现非阻塞Socket通信(2)[1]

经过上面步骤后该ServerSocketChannel可以接受客户端的连接请求但我们需要调用Selector的select()方法来监听所有Channel上的IO操作

程序清单codes///NoBlock/NServerjava

public class NServer

{

//用于检测所有Channel状态的Selector

private Selector selector = null;

//定义实现编码解码的字符集对象

private Charset charset = CharsetforName(UTF

public void init()throws IOException

{

selector = Selectoropen()

//通过open方法来打开一个未绑定的ServerSocketChannel实例

ServerSocketChannel server = ServerSocketChannelopen()

InetSocketAddress isa = new InetSocketAddress(

//将该ServerSocketChannel绑定到指定IP地址

serversocket()bind(isa)

//设置ServerSocket以非阻塞方式工作

serverconfigureBlocking(false)

//将server注册到指定Selector对象

serverregister(selector SelectionKeyOP_ACCEPT)

while (selectorselect() >

{

//依次处理selector上的每个已选择的SelectionKey

for (SelectionKey sk : selectorselectedKeys())

{

//从selector上的已选择Key集中删除正在处理的SelectionKey

selectorselectedKeys()remove(sk) //①

//如果sk对应的通道包含客户端的连接请求

if (skisAcceptable()) //②

{

//调用accept方法接受连接产生服务器端对应的SocketChannel

SocketChannel sc = serveraccept()

//设置采用非阻塞模式

scconfigureBlocking(false)

//将该SocketChannel也注册到selector

scregister(selector SelectionKeyOP_READ)

//将sk对应的Channel设置成准备接受其他请求

skinterestOps(SelectionKeyOP_ACCEPT)

}

//如果sk对应的通道有数据需要读取

if (skisReadable()) //③

{

//获取该SelectionKey对应的Channel该Channel中有可读的数据

SocketChannel sc = (SocketChannel)skchannel()

//定义准备执行读取数据的ByteBuffer

ByteBuffer buff = ByteBufferallocate(

String content = ;

//开始读取数据

try

{

while(scread(buff) >

{

buffflip()

content += charsetdecode(buff)

}

//打印从该sk对应的Channel里读取到的数据

Systemoutprintln(===== + content)

//将sk对应的Channel设置成准备下一次读取

skinterestOps(SelectionKeyOP_READ)

}

//如果捕捉到该sk对应的Channel出现了异常即表明该Channel

//对应的Client出现了问题所以从Selector中取消sk的注册

catch (IOException ex)

{

//从Selector中删除指定的SelectionKey

skcancel()

if (skchannel() != null)

{

skchannel()close()

}

}

//如果content的长度大于即聊天信息不为空

if (contentlength() >

{

//遍历该selector里注册的所有SelectKey

for (SelectionKey key : selectorkeys())

{

//获取该key对应的Channel

Channel targetChannel = keychannel()

//如果该channel是SocketChannel对象

if (targetChannel instanceof SocketChannel)

{

//将读到的内容写入该Channel中

SocketChannel dest = (SocketChannel)targetChannel;

destwrite(charsetencode(content))

}

}

}

}

}

}

}

public static void main(String[] args)

throws IOException

{

new NServer()init()

}

}

上面程序启动时即建立一个可监听连接请求的ServerSocketChannel并将该Channel注册到指定Selector接着程序直接采用循环不断监控Selector对象的select()方法返回值当该返回值大于时处理该Selector上所有被选择的SelectionKey

开始处理指定SelectionKey之后立即从该Selector中的被选择的SelectionKey集合中删除该SelectionKey如程序中①号代码所示

[] []

               

上一篇:疯狂Java讲义:使用NIO实现非阻塞Socket通信(2)[2]

下一篇:疯狂Java讲义:使用DatagramSocket发送、接收数据[2]