|
NIO使用非阻塞IO的方式实现,服务器与客户端的交流,适用于大量连接,而数据量少的情况。通过一个线程轮询所有的通道,处理注册的事件,而主线程可以继续干其他的事情。这样所有的I/O都交给一个线程处理,减少了线程IO的切换。如果具体学习NIO的架构和原理请点击下面的连接
点击打开链接 http://ifeve.com/selectors/
以下为一个使用NIO实现的C/S通信模式,对应简单例子学习,可以更容易入手。
服务端代码如下:
主线程类:MainChannel - import java.io.IOException;
- import java.net.InetSocketAddress;
- import java.nio.channels.SelectionKey;
- import java.nio.channels.Selector;
- import java.nio.channels.ServerSocketChannel;
- public class MainChannel {
- public static void main (String[] args) {
- // TODO Auto-generated method stub
- // 声明服务器监听通道 和select选择器
- ServerSocketChannel serverChannel = null;
- Selector selector = null;
- try {
- // 实例化selector 此种实例化模式说明 selector 是单例的
- selector = Selector.open();
- // 实例化服务器监听端口
- serverChannel = ServerSocketChannel.open();
- // 绑定监听地址。
- serverChannel.socket().bind( new InetSocketAddress( 8881));
- // 设置channel为非阻塞模式,一定要非阻塞模式才能注册到selector中
- serverChannel.configureBlocking( false);
- // 把监听通道注册到选择器中, 监听此通道的连接事件。SelectionKey.OP_ACCEPT 指定为连接事件。
- serverChannel.register(selector, SelectionKey.OP_ACCEPT);
- //所有通道,交给通道管理器,统一管理
- ChannelManager.addChannel(serverChannel);
- // 开启一个线程负责管理selector,并轮询是否有注册监听的事件就绪。
- Thread thread = new Thread( new ServerNIO(selector));
- thread.start();
- // 然后主线程 就可以干其他的事情了。不管客户端连接 还是I/O
- // 都不会阻塞此线程,只会阻塞selector管理线程,且只在等待事件发生时阻塞。
- } catch (IOException e) {
- // TODO Auto-generated catch block
- System.out.println( "服务器监听发生异常");
- }
- }
- }
|
管理selector的线程类:
通道管理类:
- import java.io.IOException;
- import java.nio.channels.Channel;
- import java.util.LinkedList;
- public class ChannelManager {
- private static LinkedList<Channel> list = new LinkedList<>();
- private static Thread thread; //用于开启心跳测试通道连接,实现省略
- public static void addChannel (Channel channel) {
- list.add(channel);
- }
- //关闭所有的通道连接
- public static void closeChannles () {
- for (Channel channel : list) {
- try {
- channel.close();
- } catch (IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- System.out.println( "关闭通道失败");
- }
- list.remove();
- }
- }
- }
|
一个简单的客户端类: 这个脚本可以直接通过cmd 编译运行。
- import java.io.IOException;
- import java.net.InetSocketAddress;
- import java.nio.ByteBuffer;
- import java.nio.channels.SocketChannel;
- import java.util.Scanner;
- public class MainChannel {
- public static void main (String[] args) {
- // TODO Auto-generated method stub
- SocketChannel socketChannel = null;
- boolean flag = true;
- Scanner in = new Scanner(System.in);
- ByteBuffer buffer = ByteBuffer.allocate( 1024);
- try {
- socketChannel = SocketChannel.open();
- // 设置连接为非阻塞模式,可能未连接完成就返回
- // socketChannel.configureBlocking(false);
- socketChannel.socket().connect( new InetSocketAddress( "192.168.1.100", 8881));
- // 判断是否连接成功,等待连接成功
- while (!socketChannel.finishConnect()) {
- }
- while (flag) {
- String temp = in.nextLine();
- buffer.clear();
- buffer.put(temp.getBytes());
- // limit指针 移动到 position位置
- buffer.flip();
- // 当buffer中有足够空间,则写到buffer中
- while (buffer.hasRemaining())
- socketChannel.write(buffer);
- if ( "exit".equals(temp))
- flag = false;
- }
- } catch (IOException e) {
- // TODO Auto-generated catch block
- System.out.println( "与服务断开连接");
- }
- if (socketChannel != null) {
- try {
- socketChannel.close();
- } catch (IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- }
- }
|
上述代码,可以实现客户端向服务器发送消息,然后服务器接受到消息,在自己的控制台打印输出。
----------------------------
原文链接:https://blog.csdn.net/qq_32250495/article/details/76796084
程序猿的技术大观园:www.javathinker.net
[这个贴子最后由 flybird 在 2020-02-06 23:41:23 重新编辑]
|
|