`
tang9140
  • 浏览: 35087 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

java nio SocketChannel 服务器端与多客户端 信息交互(聊天功能)

 
阅读更多

服务端代码:

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
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.nio.charset.Charset;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class NIOSServer {
    private int port = 8888;
    
    //解码buffer  
    private Charset cs = Charset.forName("utf-8");
    
    /*接受数据缓冲区*/
    private static ByteBuffer sBuffer = ByteBuffer.allocate(1024);
    
    /*发送数据缓冲区*/
    private static ByteBuffer rBuffer = ByteBuffer.allocate(1024);
    
    /*映射客户端channel */
    private Map<String, SocketChannel> clientsMap = new HashMap<String, SocketChannel>();
    
    private static Selector selector;
    
    public NIOSServer(int port) {
        this.port = port;
        try {
            init();
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    private void init() throws IOException {
        /* 
         *启动服务器端,配置为非阻塞,绑定端口,注册accept事件 
         *ACCEPT事件:当服务端收到客户端连接请求时,触发该事件 
         */
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        serverSocketChannel.configureBlocking(false);
        ServerSocket serverSocket = serverSocketChannel.socket();
        serverSocket.bind(new InetSocketAddress(port));
        selector = Selector.open();
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
        System.out.println("server start on port:" + port);
    }
    
    /** 
     * 服务器端轮询监听,select方法会一直阻塞直到有相关事件发生或超时 
     */
    private void listen() {
        while (true) {
            try {
                selector.select();//返回值为本次触发的事件数  
                Set<SelectionKey> selectionKeys = selector.selectedKeys();
                for (SelectionKey key : selectionKeys) {
                    handle(key);
                }
                selectionKeys.clear();//清除处理过的事件  
            }
            catch (Exception e) {
                e.printStackTrace();
                break;
            }
            
        }
    }
    
    /** 
     * 处理不同的事件 
    */
    private void handle(SelectionKey selectionKey) throws IOException {
        ServerSocketChannel server = null;
        SocketChannel client = null;
        String receiveText = null;
        int count = 0;
        if (selectionKey.isAcceptable()) {
            /* 
             * 客户端请求连接事件 
             * serversocket为该客户端建立socket连接,将此socket注册READ事件,监听客户端输入 
             * READ事件:当客户端发来数据,并已被服务器控制线程正确读取时,触发该事件 
             */
            server = (ServerSocketChannel)selectionKey.channel();
            client = server.accept();
            client.configureBlocking(false);
            client.register(selector, SelectionKey.OP_READ);
        }
        else if (selectionKey.isReadable()) {
            /* 
             * READ事件,收到客户端发送数据,读取数据后继续注册监听客户端 
             */
            client = (SocketChannel)selectionKey.channel();
            rBuffer.clear();
            count = client.read(rBuffer);
            if (count > 0) {
                rBuffer.flip();
                receiveText = String.valueOf(cs.decode(rBuffer).array());
                System.out.println(client.toString() + ":" + receiveText);
                dispatch(client, receiveText);
                client = (SocketChannel)selectionKey.channel();
                //client.register(selector, SelectionKey.OP_READ);
            }
        }
    }
    
    /** 
     * 把当前客户端信息 推送到其他客户端 
     */
    private void dispatch(SocketChannel client, String info) throws IOException {
        Socket s = client.socket();
        String name =
            "[" + s.getInetAddress().toString().substring(1) + ":" + Integer.toHexString(client.hashCode()) + "]";
        if (!clientsMap.isEmpty()) {
            for (Map.Entry<String, SocketChannel> entry : clientsMap.entrySet()) {
                SocketChannel temp = entry.getValue();
                if (!client.equals(temp)) {
                    sBuffer.clear();
                    sBuffer.put((name + ":" + info).getBytes());
                    sBuffer.flip();
                    //输出到通道  
                    temp.write(sBuffer);
                }
            }
        }
        clientsMap.put(name, client);
    }
    
    public static void main(String[] args) throws IOException {
        NIOSServer server = new NIOSServer(7777);
        server.listen();
    }
}

客户端,可运行多个

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.SocketChannel;
import java.util.Date;
import java.util.Scanner;
import java.util.Set;

public class NIOSClient {
    /*发送数据缓冲区*/
    private static ByteBuffer sBuffer = ByteBuffer.allocate(1024);
    
    /*接受数据缓冲区*/
    private static ByteBuffer rBuffer = ByteBuffer.allocate(1024);
    
    /*服务器端地址*/
    private InetSocketAddress SERVER;
    
    private static Selector selector;
    
    private static SocketChannel client;
    
    private static String receiveText;
    
    private static String sendText;
    
    private static int count = 0;
    
    public NIOSClient(int port) {
        SERVER = new InetSocketAddress("localhost", port);
        init();
    }
    
    public void init() {
        try {
            /* 
              * 客户端向服务器端发起建立连接请求 
              */
            SocketChannel socketChannel = SocketChannel.open();
            socketChannel.configureBlocking(false);
            selector = Selector.open();
            socketChannel.register(selector, SelectionKey.OP_CONNECT);
            socketChannel.connect(SERVER);
            /* 
             * 轮询监听客户端上注册事件的发生 
             */
            while (true) {
                selector.select();
                Set<SelectionKey> keySet = selector.selectedKeys();
                for (final SelectionKey key : keySet) {
                    handle(key);
                }
                ;
                keySet.clear();
            }
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    public static void main(String[] args) throws IOException {
        new NIOSClient(7777);
    }
    
    private void handle(SelectionKey selectionKey) throws IOException {
        if (selectionKey.isConnectable()) {
            /* 
             * 连接建立事件,已成功连接至服务器 
             */
            client = (SocketChannel)selectionKey.channel();
            if (client.isConnectionPending()) {
                client.finishConnect();
                System.out.println("connect success !");
                sBuffer.clear();
                sBuffer.put((new Date() + " connected!").getBytes());
                sBuffer.flip();
                client.write(sBuffer);//发送信息至服务器  
                /* 原文来自站长网
                 * 启动线程一直监听客户端输入,有信息输入则发往服务器端 
                 * 因为输入流是阻塞的,所以单独线程监听 
                 */
                new Thread() {
                    @Override
                    public void run() {
                        while (true) {
                            try {
                                sBuffer.clear();
                                Scanner cin = new Scanner(System.in);
                                sendText = cin.nextLine();
                                System.out.println(sendText);
                                /* 
                                 * 未注册WRITE事件,因为大部分时间channel都是可以写的 
                                 */
                                sBuffer.put(sendText.getBytes("utf-8"));
                                sBuffer.flip();
                                client.write(sBuffer);
                            }
                            catch (IOException e) {
                                e.printStackTrace();
                                break;
                            }
                        }
                    };
                }.start();
            }
            //注册读事件  
            client.register(selector, SelectionKey.OP_READ);
        }
        else if (selectionKey.isReadable()) {
            /* 
             * 读事件触发 
             * 有从服务器端发送过来的信息,读取输出到屏幕上后,继续注册读事件 
             * 监听服务器端发送信息 
             */
            client = (SocketChannel)selectionKey.channel();
            rBuffer.clear();
            count = client.read(rBuffer);
            if (count > 0) {
                receiveText = new String(rBuffer.array(), 0, count);
                System.out.println(receiveText);
                client = (SocketChannel)selectionKey.channel();
                client.register(selector, SelectionKey.OP_READ);
            }
        }
    }
}


版权声明:本文为博主原创文章,未经博主允许不得转载。

分享到:
评论

相关推荐

    java nio 聊天室源码

    - 通过选择器,服务器端可以同时处理多个客户端连接,实现了多路复用。 4. **线程模型** - 在这个聊天室项目中,可能采用了一个线程处理多个客户端的模式,即`Selector`在一个单独的线程中运行,处理来自所有...

    Java NIO英文高清原版

    Netty是一个基于NIO的高性能、异步事件驱动的网络应用框架,它简化了网络编程,广泛应用于服务器端应用开发。 NIO的核心概念包括通道(Channel)、缓冲区(Buffer)和选择器(Selector)。以下是对这些核心概念的...

    java NIO推送实例

    - **服务器端代码**:可能包括`ServerSocketChannel`用于监听连接,`SocketChannel`用于与每个客户端建立连接,以及`Selector`的注册和选择操作。 - **客户端代码**:可能涉及`SocketChannel`的创建,用于连接...

    java基于NIO选择器Selector的多人聊天室

    在这个"java基于NIO选择器Selector的多人聊天室"项目中,开发者利用NIO的核心特性构建了一个允许多个客户端同时进行交互的聊天平台。 首先,我们需要了解NIO的基本组件。在Java NIO中,`Selector`是核心角色,它...

    基于java NIO的socket通信demo

    Java NIO(New Input/Output)是Java标准库提供的一种I/O模型,它与传统的 Blocking I/O(BIO)模型不同,NIO提供了非阻塞的读写方式,提高了系统在处理大量并发连接时的效率。在这个“基于java NIO的socket通信demo...

    Java NIO Socket基本

    NIO在Java 1.4版本引入,其设计目标是提供一种更高效、更灵活的I/O操作方式,特别适合处理大量并发连接的场景,如服务器端编程。在NIO中,我们不再像BIO那样等待一个操作完成,而是通过选择器(Selector)监控多个...

    java nio im(server+client)

    - **服务器启动**:服务器端通常会创建一个ServerSocketChannel,监听特定的端口,等待客户端连接。 - **接受连接**:当有客户端连接请求时,ServerSocketChannel会生成一个新的SocketChannel用于与客户端进行通信...

    JavaNIO服务器实例Java开发Java经验技巧共6页

    本资料"JavaNIO服务器实例Java开发Java经验技巧共6页"可能是某个Java开发者或讲师分享的一份关于如何在Java中构建NIO服务器的教程,涵盖了6个关键页面的内容。尽管具体的细节无法在此直接提供,但我们可以根据Java ...

    基于nio的简易聊天室

    在这个简易聊天室中,服务器端会使用Selector监听多个客户端的连接请求,而客户端则通过通道与服务器进行数据交换。下面我们将详细讲解这些关键知识点: 1. **通道(Channels)**: 通道是NIO中的一个重要组成部分...

    实现java网络与nio例子

    Java NIO(New Input/Output)是Java标准库提供的一种I/O模型,它与传统的 ...这个"网络与nio"的压缩包文件很可能包含了服务器端和客户端的完整代码示例,可以帮助我们深入理解并实践Java NIO在网络编程中的应用。

    java-nio.rar_NIO_java nio

    服务器端的读写操作与客户端类似,都是通过`SocketChannel`和`ByteBuffer`进行的。 非阻塞IO的一个重要优势在于它允许单个线程处理多个连接,这在处理高并发场景时非常有用。通过注册`SocketChannel`到`Selector`,...

    一个NIO服务端,客户端的例子

    客户端则会创建Bootstrap实例,设置通道工厂,通常是NioSocketChannel。同样地,客户端也需要配置管道,其中包含一个ByteToMessageDecoder和一个ClientBusinessHandler,后者负责与服务器交互的逻辑。 在启动服务器...

    java nio 入门

    2. **网络通信**:使用SocketChannel和ServerSocketChannel进行客户端和服务器端的连接与数据传输。 3. **多路复用**:通过Selector监听多个SocketChannel,当有连接请求或数据到达时,由选择器通知,实现高效的...

    Java NIO详解及源码下载

    NIO的应用场景广泛,尤其是在高并发、大数据量的网络应用中,比如服务器端的Socket编程。使用NIO,可以创建更高效的服务器,因为它可以同时处理多个客户端连接,而不需要为每个连接创建一个新的线程。 下面是一些...

    基于NIO的Java聊天室2

    3. **ServerSocketChannel**:服务器端用来监听新连接的通道,配合Selector使用可以监听多个客户端的连接请求。 4. **多线程**:虽然NIO可以减少线程的使用,但在某些场景下,我们可能还需要为每个客户端创建单独的...

    NIO.rar_NIO_java nio

    通过分析这个项目,你可以学习如何使用Java NIO进行网络编程,理解服务器端如何设置监听,客户端如何建立连接,以及如何在非阻塞模式下进行数据交换。这对于提升Java服务器开发和网络编程能力是非常有帮助的。

    一个基于java nio的简单的http服务器.zip

    在基于Java NIO的HTTP服务器中,服务器端首先需要监听一个固定的端口,等待客户端的连接请求。当有连接请求到来时,服务器会创建一个SocketChannel,然后将其注册到选择器上,设置感兴趣的事件为OP_ACCEPT(接受连接...

    chacha.rar_NIO soclet java_java nio

    - **认证过程**:客户端发送用户名和动态口令,服务器端验证口令是否正确,通常需要存储用户的密钥和动态口令生成算法。 4. **MongoDB数据库**: - **NoSQL数据库**:MongoDB是非关系型数据库,适合处理大量数据...

Global site tag (gtag.js) - Google Analytics