`
tang9140
  • 浏览: 33290 次
  • 性别: 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 通信服务器、客户端完整例子

    用java编写的nio通信的例子,nio是io编程的新版本,比io较流行。同时本例子是适用socket通信的。可以在此基础上,添加您的个人应用。本例子适用于:java通信的学习者,android平台通信的学习者。

    java多路复用socket客户端.

    Java NIO中的SocketChannel是一个连接到TCP网络套接字的通道。可以通过以下2种方式创建SocketChannel: 打开一个SocketChannel并连接到互联网上的某台服务器。 一个新连接到达ServerSocketChannel时,会创建一个...

    Java NIO非阻塞服务端与客户端相互通信

    Java NIO非阻塞服务端与客户端相互通信 每行代码都有注释, 看完后,会让你对非阻塞有一清楚的认识.

    JAVA nio异步长连接服务端与客户端

    JAVA.NIO 异步长连接客户端与服务端都有,大家可以看看,另不知道怎么样将客户端读取的BUFF后的数据进行处理可以给出修改吗?

    JavaNIO chm帮助文档

    Java NIO系列教程(一) Java NIO 概述 Java NIO系列教程(二) Channel Java NIO系列教程(三) Buffer Java NIO系列教程(四) Scatter/Gather Java NIO系列教程(五) 通道...Java NIO系列教程(十二) Java NIO与IO

    java socketNIO 实现多客户端聊天室 代码

    利用socketNIO实现的多客户端聊天室,非阻塞式IO,java代码编写,使用方法:先启动服务端代码再启动客户端代码,可启动多个客户端代码。若使用多个电脑启动客户端,需在客户端代码中更改一下ip地址。

    Java NIO实战开发多人聊天室

    09-Java NIO-Channel-SocketChannel.mp4 10-Java NIO-Channel-DatagramChannel.mp4 11-Java NIO-Channel-分散和聚集.mp4 12-Java NIO-Buffer-概述.mp4 13-Java NIO-Buffer-基本使用.mp4 14-Java NIO-Buffer-三个属性...

    java NIO和java并发编程的书籍

    java NIO和java并发编程的书籍java NIO和java并发编程的书籍java NIO和java并发编程的书籍java NIO和java并发编程的书籍java NIO和java并发编程的书籍java NIO和java并发编程的书籍java NIO和java并发编程的书籍java...

    JAVA NIO 异步通信客户端

    在CMD运行模式下实现的JAVA异步通信,采用Java.nio包,使用线程实现

    nio-chatroom:基于Java Nio的单服务器多客户端聊天室

    聊天室基于Java Nio的单服务器多客户端聊天室实施规范服务器来自客户端的所有请求都显示在服务器端服务器处理连接/断开而没有其他客户端告知所有客户变更客户端显示给所有用户的在线用户列表向所有用户显示连接/断开...

    Java视频教程 Java游戏服务器端开发 Netty NIO AIO Mina视频教程

    jaca视频教程 jaca游戏服务器端开发 Netty NIO AIO Mina视频教程 课程目录: 一、Netty快速入门教程 01、第一课NIO 02、第二课netty服务端 03、第三课netty客户端 04、第四课netty线程模型源码分析(一) 05、...

    java NIO socket聊天室

    使用NIO socket不需要多线程来处理多个连接的请求,效率非常高 可以作为NIO socket入门的例子,Reactor模式,重点理解key.attach, jar文件里包含了源代码 ...5,封装自己的协议可以做成自己需要的服务器端程序,

    Java NIO实现多个客户端之间的消息互发,客户端与服务器完整代码

    服务器在JAVA上,客户端为C++,实现多人聊天消息转发,服务器也可以给客户端发送消息。附上项目完整源代码,client包负责消息发送,sensor包负责消息接收

    java nio 聊天室源码

    此项目基于java nio实现聊天室功能

    高手使用Java NIO编写高性能的服务器

    使用Java NIO编写高性能的服务器

    Java NIO英文高清原版

    Java NIO英文高清原版

    java nio 包读取超大数据文件

    Java nio 超大数据文件 超大数据文件Java nio 超大数据文件 超大数据文件Java nio 超大数据文件 超大数据文件Java nio 超大数据文件 超大数据文件Java nio 超大数据文件 超大数据文件Java nio 超大数据文件 超大数据...

    java NIO 视频教程

    Java NIO(New IO)是一个可以替代标准Java IO API的IO API(从Java 1.4开始),Java NIO提供了与标准IO不同的IO工作方式。 Java NIO: Channels and Buffers(通道和缓冲区) 标准的IO基于字节流和字符流进行操作的,...

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

    本代码是基于JAVA技术NIO流的选择器Selector的多人聊天室,实现了多个客户端之间的聊天,拥有java窗体、画板等。

    java NIO 中文版

    讲解了 JavaIO 与 JAVA NIO区别,JAVA NIO设计理念,以及JDK中java NIO中语法的使用

Global site tag (gtag.js) - Google Analytics