Java NIO简易聊天室(一)

简介:

 Java NIO简易聊天室

         NIO方式实现简易通讯。代码注释较少,将就看看吧。
 
         哎,越来越懒了。也没什么东西可写的,直接贴贴代码==。不过,有附件工程,觉着这都没什么必要。
 
         运行效果不弄了,可以看后一篇《 Android NIO简易聊天室》。核心的没变,就是包了层Android的简单界面。
 
一、 Chat.java
         服务器、客户端的基类。继承Observable,作为被观察者。定义些状态啊什么的。
 
 
  1. public abstract class Chat extends Observable { 
  2.   
  3.     public static final int SEV_ON = 0
  4.     public static final int SEV_OFF = 1
  5.     public static final int CLT_CONNECT = 2
  6.     public static final int CLT_DISCONNECT = 3
  7.     public static final int MSG_SEND = 4
  8.     public static final int MSG_RECEIVE = 5
  9.     public static final int ERROR = 6
  10.   
  11.     /** 缓存区大小 */ 
  12.     protected static final int BUFFERSIZE = 1024 * 10
  13.     /** 字符编码 */ 
  14.     protected static final String CHARSET = "UTF-8"
  15.   
  16.     /** 字符编码器 */ 
  17.     protected static CharsetEncoder encoder; 
  18.     /** 字符解码器 */ 
  19.     protected static CharsetDecoder decoder; 
  20.   
  21.     static { 
  22.        encoder = Charset.forName(CHARSET).newEncoder(); 
  23.        decoder = Charset.forName(CHARSET).newDecoder(); 
  24.     } 
  25.   
  26.     /** 当前状态 */ 
  27.     protected int status; 
  28.   
  29.     /** 获得当前状态 */ 
  30.     public int getStatus() { 
  31.        return status; 
  32.     } 
  33.   
  34.     /** 
  35.      * 通知状态改变 
  36.      * @param status 状态 
  37.      * @param arg 参数 
  38.      */ 
  39.     protected void notifyStateChanged(int status, Object arg) { 
  40.        this.status = status; 
  41.        notifyStateChanged(arg); 
  42.     } 
  43.   
  44.     /** 
  45.      * 通知状态改变 
  46.      * @param arg 参数 
  47.      */ 
  48.     protected void notifyStateChanged(Object arg) { 
  49.        setChanged(); 
  50.        notifyObservers(arg); 
  51.     } 
  52.   
 
二、 ChatServer.java
         服务器核心类。

 
  1. public class ChatServer extends Chat implements Runnable { 
  2.   
  3.     private boolean isPrepared = false
  4.     private ServerSocketChannel ssc; 
  5.     private Selector selector; 
  6.     private ArrayList<SelectionKey> serverKeyList; 
  7.     private String receiveMessage; 
  8.   
  9.     /** 
  10.      * 服务器构造函数 
  11.      * 
  12.      * @param port 端口 
  13.      */ 
  14.     public ChatServer(int port) { 
  15.        try { 
  16.            selector = Selector.open(); 
  17.            ssc = ServerSocketChannel.open(); 
  18.            ssc.configureBlocking(false); 
  19.            ssc.socket().bind(new InetSocketAddress(port)); 
  20.            ssc.register(selector, SelectionKey.OP_ACCEPT); 
  21.            serverKeyList = new ArrayList<SelectionKey>(); 
  22.            isPrepared = true
  23.        } catch (IOException e) { 
  24.            notifyStateChanged(ERROR, e); 
  25.            e.printStackTrace(); 
  26.        } 
  27.     } 
  28.   
  29.     public void start() { 
  30.        if (isPrepared) 
  31.            new Thread(this).start(); 
  32.     } 
  33.   
  34.     /** 针对同一个SelectionKey在一次写操作之前,后attach进去的消息会被覆盖。 */ 
  35.     public void send(String msg, InetSocketAddress... toIps) { 
  36.        notifyStateChanged(MSG_SEND, msg); 
  37.        if (null == serverKeyList || serverKeyList.size() <= 0) { 
  38.            return
  39.        } 
  40.        if (null != toIps && toIps.length >= 1) { 
  41.            /* 发送给部分 */ 
  42.            for (SelectionKey serverKey : serverKeyList) { 
  43.               SocketChannel sc = (SocketChannel) serverKey.channel(); 
  44.               SocketAddress ip = sc.socket().getRemoteSocketAddress(); 
  45.               for (InetSocketAddress toIp : toIps) { 
  46.                   if (toIp.equals(ip)) { 
  47.                      serverKey.attach(msg); 
  48.                      serverKey.interestOps(SelectionKey.OP_READ 
  49.                             | SelectionKey.OP_WRITE); 
  50.                      serverKey.selector().wakeup(); 
  51.                      break
  52.                   } 
  53.               } 
  54.            } 
  55.        } else { 
  56.            /* 发送给全部 */ 
  57.            for (SelectionKey serverKey : serverKeyList) { 
  58.               serverKey.attach(msg); 
  59.               serverKey.interestOps(SelectionKey.OP_READ 
  60.                      | SelectionKey.OP_WRITE); 
  61.               serverKey.selector().wakeup(); 
  62.            } 
  63.        } 
  64.     } 
  65.   
  66.     @Override 
  67.     public void run() { 
  68.        notifyStateChanged(SEV_ON, null); 
  69.        try { 
  70.            while (isPrepared) { 
  71.               int keysCount = selector.select(); 
  72.               if (keysCount < 1) { 
  73.                   continue
  74.               } 
  75.               Set<SelectionKey> set = selector.selectedKeys(); 
  76.               Iterator<SelectionKey> it = set.iterator(); 
  77.               while (it.hasNext()) { 
  78.                   SelectionKey key = it.next(); 
  79.                   if (key.isAcceptable()) { 
  80.                      doAccept(key); 
  81.                   } 
  82.                   if (key.isValid() && key.isReadable()) { 
  83.                      doRead(key); 
  84.                   } 
  85.                   if (key.isValid() && key.isWritable()) { 
  86.                      doWrite(key); 
  87.                   } 
  88.               } 
  89.               set.clear(); 
  90.            } 
  91.        } catch (IOException e) { 
  92.            e.printStackTrace(); 
  93.        } finally { 
  94.            // close(); 
  95.            notifyStateChanged(SEV_OFF, null); 
  96.        } 
  97.     } 
  98.   
  99.     public void close() { 
  100.        isPrepared = false
  101.        try { 
  102.            if (null != serverKeyList) { 
  103.               for (SelectionKey key : serverKeyList) { 
  104.                   key.channel().close(); 
  105.               } 
  106.            } 
  107.            if (null != selector) { 
  108.               selector.close(); 
  109.            } 
  110.            if (null != ssc) { 
  111.               ssc.close(); 
  112.            } 
  113.        } catch (IOException e) { 
  114.            e.printStackTrace(); 
  115.        } 
  116.     } 
  117.   
  118.     private void doAccept(SelectionKey key) { 
  119.        ServerSocketChannel ssc = (ServerSocketChannel) key.channel(); 
  120.        try { 
  121.            SocketChannel sc = ssc.accept(); 
  122.            sc.configureBlocking(false); 
  123.            SelectionKey newKey = sc.register(selector, SelectionKey.OP_READ); 
  124.            // newKey.attach(new ArrayList<String>()); 
  125.  
  126.            serverKeyList.add(newKey); 
  127.            notifyStateChanged(CLT_CONNECT, sc.socket() 
  128.                   .getRemoteSocketAddress()); 
  129.        } catch (IOException e) { 
  130.            e.printStackTrace(); 
  131.        } 
  132.     } 
  133.   
  134.     private void doRead(SelectionKey key) { 
  135.        SocketChannel sc = (SocketChannel) key.channel(); 
  136.        ByteBuffer bb = ByteBuffer.allocate(BUFFERSIZE); 
  137.        StringBuffer sb = new StringBuffer(); 
  138.        try { 
  139.            int count = 0
  140.            while ((count = sc.read(bb)) > 0) { 
  141.               bb.flip(); 
  142.               sb.append(decoder.decode(bb)); 
  143.            } 
  144.            if (count == -1) { 
  145.               disconnect(key, sc); 
  146.            } else { 
  147.               receiveMessage = sb.toString().trim(); 
  148.               notifyStateChanged(MSG_RECEIVE, sc.socket() 
  149.                      .getRemoteSocketAddress()); 
  150.   
  151.            } 
  152.        } catch (IOException e) { 
  153.            disconnect(key, sc); 
  154.            // e.printStackTrace(); 
  155.  
  156.        } 
  157.     } 
  158.   
  159.     private void doWrite(SelectionKey key) { 
  160.        SocketChannel sc = (SocketChannel) key.channel(); 
  161.        String msg = (String) key.attachment(); 
  162.        if (null == msg) { 
  163.            key.interestOps(SelectionKey.OP_READ); 
  164.            return
  165.        } 
  166.        try { 
  167.            sc.write(encoder.encode(CharBuffer.wrap(msg))); 
  168.        } catch (IOException e) { 
  169.            disconnect(key, sc); 
  170.            // e.printStackTrace(); 
  171.  
  172.        } 
  173.        key.interestOps(SelectionKey.OP_READ); 
  174.     } 
  175.   
  176.     /** 断开连接 */ 
  177.     private void disconnect(SelectionKey key, SocketChannel sc) { 
  178.        serverKeyList.remove(key); 
  179.        notifyStateChanged(CLT_DISCONNECT, sc.socket().getRemoteSocketAddress()); 
  180.  
  181.        try { 
  182.            key.cancel(); 
  183.            sc.close(); 
  184.        } catch (IOException e) { 
  185.            e.printStackTrace(); 
  186.        } 
  187.     } 
  188.   
  189.     public String getReceiveMessage() { 
  190.        return receiveMessage; 
  191.     } 
  192.   
 
三、 ChatClient.java
         客户端核心类。

 
  1. public class ChatClient extends Chat implements Runnable { 
  2.   
  3.     private boolean isPrepared = false
  4.     private Selector selector; 
  5.     private SelectionKey clientKey; 
  6.     private InetSocketAddress address; 
  7.   
  8.     /** 
  9.      * 客户端构造函数 
  10.      * 
  11.      * @param host 服务器地址 
  12.      * @param port 服务器端口 
  13.      */ 
  14.     public ChatClient(String host, int port) { 
  15.        address = new InetSocketAddress(host, port); 
  16.        try { 
  17.            selector = Selector.open(); 
  18.        } catch (IOException e) { 
  19.            notifyStateChanged(ERROR, e); 
  20.            e.printStackTrace(); 
  21.        } 
  22.     } 
  23.   
  24.     public void start() { 
  25.        new Thread(this).start(); 
  26.     } 
  27.   
  28.     public void send(String msg) { 
  29.        notifyStateChanged(MSG_SEND, msg); 
  30.        if (null == clientKey) { 
  31.            return
  32.        } 
  33.        clientKey.attach(msg); 
  34.        clientKey.interestOps(SelectionKey.OP_READ | SelectionKey.OP_WRITE); 
  35.        clientKey.selector().wakeup(); 
  36.     } 
  37.   
  38.     @Override 
  39.     public void run() { 
  40.        try { 
  41.            SocketChannel sc = SocketChannel.open(); 
  42.            sc.configureBlocking(false); 
  43.            sc.connect(address); 
  44.            clientKey = sc.register(selector, SelectionKey.OP_CONNECT); 
  45.            isPrepared = true
  46.            while (isPrepared) { 
  47.               int keysCount = selector.select(); 
  48.               if (keysCount < 1) { 
  49.                   continue
  50.               } 
  51.               Set<SelectionKey> set = selector.selectedKeys(); 
  52.               Iterator<SelectionKey> it = set.iterator(); 
  53.               while (it.hasNext()) { 
  54.                   SelectionKey key = it.next(); 
  55.                   if (key.isConnectable()) { 
  56.                      doConnect(key); 
  57.                   } 
  58.                   if (key.isValid() && key.isReadable()) { 
  59.                      doRead(key); 
  60.                   } 
  61.                   if (key.isValid() && key.isWritable()) { 
  62.                      doWrite(key); 
  63.                   } 
  64.               } 
  65.               set.clear(); 
  66.            } 
  67.        } catch (IOException e) { 
  68.            notifyStateChanged(ERROR, e); 
  69.            e.printStackTrace(); 
  70.        } finally { 
  71.            // close(); 
  72.            notifyStateChanged(CLT_DISCONNECT, null); 
  73.        } 
  74.     } 
  75.   
  76.     public void close() { 
  77.        isPrepared = false
  78.        try { 
  79.            if (null != clientKey) { 
  80.               clientKey.channel().close(); 
  81.            } 
  82.            if (null != selector) { 
  83.               selector.close(); 
  84.            } 
  85.        } catch (IOException e) { 
  86.            e.printStackTrace(); 
  87.        } 
  88.     } 
  89.   
  90.     private void doConnect(SelectionKey key) { 
  91.        SocketChannel sc = (SocketChannel) key.channel(); 
  92.        try { 
  93.            // http://www.velocityreviews.com/forums/t145075-whats-the-proper-way-to-use-socketchannel-finishconnect.html 
  94.  
  95.            sc.finishConnect(); 
  96.            key.interestOps(SelectionKey.OP_READ); 
  97.            notifyStateChanged(CLT_CONNECT, null); 
  98.        } catch (IOException e) { 
  99.            disconnect(key); 
  100.            e.printStackTrace(); 
  101.        } 
  102.     } 
  103.   
  104.     private void doRead(SelectionKey key) { 
  105.        SocketChannel sc = (SocketChannel) key.channel(); 
  106.        ByteBuffer bb = ByteBuffer.allocate(BUFFERSIZE); 
  107.        StringBuffer sb = new StringBuffer(); 
  108.        try { 
  109.            int count = 0
  110.            while ((count = sc.read(bb)) > 0) { 
  111.               bb.flip(); 
  112.               sb.append(decoder.decode(bb)); 
  113.            } 
  114.            if (count == -1) { 
  115.               disconnect(key); 
  116.            } else { 
  117.               notifyStateChanged(MSG_RECEIVE, sb.toString().trim()); 
  118.            } 
  119.        } catch (IOException e) { 
  120.            disconnect(key); 
  121.            e.printStackTrace(); 
  122.        } 
  123.     } 
  124.   
  125.     private void doWrite(SelectionKey key) { 
  126.        SocketChannel sc = (SocketChannel) key.channel(); 
  127.        String msg = (String) key.attachment(); 
  128.        if (null == msg) { 
  129.            key.interestOps(SelectionKey.OP_READ); 
  130.            return
  131.        } 
  132.        try { 
  133.            sc.write(encoder.encode(CharBuffer.wrap(msg))); 
  134.        } catch (IOException e) { 
  135.            disconnect(key); 
  136.            e.printStackTrace(); 
  137.        } 
  138.        key.interestOps(SelectionKey.OP_READ); 
  139.     } 
  140.   
  141.     /** 断开连接 */ 
  142.     private void disconnect(SelectionKey key) { 
  143.        notifyStateChanged(CLT_DISCONNECT, null); 
  144.        try { 
  145.            key.cancel(); 
  146.            key.channel().close(); 
  147.        } catch (IOException e) { 
  148.            e.printStackTrace(); 
  149.        } 
  150.     } 
  151.   
 
 

     本文转自winorlose2000 51CTO博客,原文链接:http://blog.51cto.com/vaero/921770,如需转载请自行联系原作者



相关文章
|
4月前
|
Java 大数据
解析Java中的NIO与传统IO的区别与应用
解析Java中的NIO与传统IO的区别与应用
|
18天前
|
消息中间件 缓存 Java
java nio,netty,kafka 中经常提到“零拷贝”到底是什么?
零拷贝技术 Zero-Copy 是指计算机执行操作时,可以直接从源(如文件或网络套接字)将数据传输到目标缓冲区, 而不需要 CPU 先将数据从某处内存复制到另一个特定区域,从而减少上下文切换以及 CPU 的拷贝时间。
java nio,netty,kafka 中经常提到“零拷贝”到底是什么?
|
1月前
|
Java
让星星⭐月亮告诉你,Java NIO之Buffer详解 属性capacity/position/limit/mark 方法put(X)/get()/flip()/compact()/clear()
这段代码演示了Java NIO中`ByteBuffer`的基本操作,包括分配、写入、翻转、读取、压缩和清空缓冲区。通过示例展示了`position`、`limit`和`mark`属性的变化过程,帮助理解缓冲区的工作原理。
31 2
|
2月前
|
存储 网络协议 Java
Java NIO 开发
本文介绍了Java NIO(New IO)及其主要组件,包括Channel、Buffer和Selector,并对比了NIO与传统IO的优势。文章详细讲解了FileChannel、SocketChannel、ServerSocketChannel、DatagramChannel及Pipe.SinkChannel和Pipe.SourceChannel等Channel实现类,并提供了示例代码。通过这些示例,读者可以了解如何使用不同类型的通道进行数据读写操作。
Java NIO 开发
|
3月前
|
Java
"揭秘Java IO三大模式:BIO、NIO、AIO背后的秘密!为何AIO成为高并发时代的宠儿,你的选择对了吗?"
【8月更文挑战第19天】在Java的IO编程中,BIO、NIO与AIO代表了三种不同的IO处理机制。BIO采用同步阻塞模型,每个连接需单独线程处理,适用于连接少且稳定的场景。NIO引入了非阻塞性质,利用Channel、Buffer与Selector实现多路复用,提升了效率与吞吐量。AIO则是真正的异步IO,在JDK 7中引入,通过回调或Future机制在IO操作完成后通知应用,适合高并发场景。选择合适的模型对构建高效网络应用至关重要。
89 2
|
3月前
|
网络协议 C# 开发者
WPF与Socket编程的完美邂逅:打造流畅网络通信体验——从客户端到服务器端,手把手教你实现基于Socket的实时数据交换
【8月更文挑战第31天】网络通信在现代应用中至关重要,Socket编程作为其实现基础,即便在主要用于桌面应用的Windows Presentation Foundation(WPF)中也发挥着重要作用。本文通过最佳实践,详细介绍如何在WPF应用中利用Socket实现网络通信,包括创建WPF项目、设计用户界面、实现Socket通信逻辑及搭建简单服务器端的全过程。具体步骤涵盖从UI设计到前后端交互的各个环节,并附有详尽示例代码,助力WPF开发者掌握这一关键技术,拓展应用程序的功能与实用性。
121 0
|
4月前
|
安全 Java Linux
(七)Java网络编程-IO模型篇之从BIO、NIO、AIO到内核select、epoll剖析!
IO(Input/Output)方面的基本知识,相信大家都不陌生,毕竟这也是在学习编程基础时就已经接触过的内容,但最初的IO教学大多数是停留在最基本的BIO,而并未对于NIO、AIO、多路复用等的高级内容进行详细讲述,但这些却是大部分高性能技术的底层核心,因此本文则准备围绕着IO知识进行展开。
165 1
|
3月前
|
存储 网络协议 Java
【Netty 神奇之旅】Java NIO 基础全解析:从零开始玩转高效网络编程!
【8月更文挑战第24天】本文介绍了Java NIO,一种非阻塞I/O模型,极大提升了Java应用程序在网络通信中的性能。核心组件包括Buffer、Channel、Selector和SocketChannel。通过示例代码展示了如何使用Java NIO进行服务器与客户端通信。此外,还介绍了基于Java NIO的高性能网络框架Netty,以及如何用Netty构建TCP服务器和客户端。熟悉这些技术和概念对于开发高并发网络应用至关重要。
74 0
|
4月前
|
监控 网络协议 Java
Java面试题:解释Java NIO与BIO的区别,以及NIO的优势和应用场景。如何在高并发应用中实现NIO?
Java面试题:解释Java NIO与BIO的区别,以及NIO的优势和应用场景。如何在高并发应用中实现NIO?
75 0
|
4月前
|
Java
Java中的NIO编程详解
Java中的NIO编程详解
下一篇
无影云桌面