`
friendsys
  • 浏览: 348218 次
  • 性别: Icon_minigender_1
  • 来自: 福州
社区版块
存档分类
最新评论

基于Nio的socket连接 随记

阅读更多
随便了解了下,也用搜到的代码理解了一下,稍微做了一些修改
package com.orz.gen;

import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.*;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;

/**
 * Created by IntelliJ IDEA.
 * User: felix
 * Date: 2010-5-11
 * Time: 13:45:31
 */
public class GemClass {

    int port = 12345;
    int BUFFERSIZE = 1024;
    Selector selector = null;
    ServerSocketChannel serverChannel = null;
    HashMap<SocketChannel, ClientChInstance> clientChannelMap = null;//用来存放每一个客户连接对应的套接字和通道

    public GemClass(int port) {
        this.clientChannelMap = new HashMap<SocketChannel, ClientChInstance>();
        this.port = port;
    }

    public void initialize() throws IOException {
        //初始化,分别实例化一个选择器,一个服务器端可选择通道
        this.selector = Selector.open();
        this.serverChannel = ServerSocketChannel.open();
        this.serverChannel.configureBlocking(false);
        InetAddress localhost = InetAddress.getLocalHost();
        InetSocketAddress isa = new InetSocketAddress(localhost, this.port);
        this.serverChannel.socket().bind(isa);//将该套接字绑定到服务器某一可用端口
    }

    //结束时释放资源

    public void finalize() throws IOException {
        this.serverChannel.close();
        this.selector.close();
    }

    //将读入字节缓冲的信息解码

    public String decode(ByteBuffer byteBuffer) throws
            CharacterCodingException {
        Charset charset = Charset.forName("UTF-8");
        CharsetDecoder decoder = charset.newDecoder();
        CharBuffer charBuffer = decoder.decode(byteBuffer);
        return charBuffer.toString();
    }

    //监听端口,当通道准备好时进行相应操作
    public void portListening() throws IOException, InterruptedException {
        //服务器端通道注册OP_ACCEPT事件
        SelectionKey acceptKey = this.serverChannel.register(this.selector,
                SelectionKey.OP_ACCEPT);
        //当有已注册的事件发生时,select()返回值将大于0
        while (selector.select() > 0) {
            System.out.println("event happened");
            //取得所有已经准备好的所有选择键
            Set<SelectionKey> readyKeys = this.selector.selectedKeys();
            //使用迭代器对选择键进行轮询
            Iterator<SelectionKey> i = readyKeys.iterator();
            while (i.hasNext()) {
                SelectionKey key = i.next();
                i.remove();//删除当前将要处理的选择键
                if (key.isAcceptable()) {//如果是有客户端连接请求
                    System.out.println("more client connect in!");
                    ServerSocketChannel nextReady = (ServerSocketChannel) key.channel();
                    //获取客户端套接字
                    SocketChannel s = nextReady.accept();
                    //设置对应的通道为异步方式并注册感兴趣事件
                    s.configureBlocking(false);
                    //SelectionKey readWriteKey =s.register(this.selector,SelectionKey.OP_READ);
                    //将注册的事件与该套接字联系起来
                    //readWriteKey.attach(s);
                    s.register(selector,SelectionKey.OP_READ);
                    //将当前建立连接的客户端套接字及对应的通道存放在哈希表//clientChannelMap中
                    this.clientChannelMap.put(s, new ClientChInstance(s));
                } else if (key.isReadable()) {//如果是通道读准备好事件
                    System.out.println("Readable");
                    //取得选择键对应的通道和套接字
                    //SelectableChannel nextReady = key.channel();
                    SocketChannel channel = (SocketChannel) key.channel();
                    //处理该事件,处理方法已封装在类ClientChInstance中
                    this.readFromChannel(channel,clientChannelMap.get(channel));
                } else if (key.isWritable()) {//如果是通道写准备好事件
                    System.out.println("writeable");
                    //取得套接字后处理,方法同上
                    SocketChannel channel = (SocketChannel)key.channel();
                    this.writeToChannel(channel, "This is from server!");
                }
            }
        }
    }

    //对通道的写操作
    public void writeToChannel(SocketChannel channel, String message)
            throws IOException {
        ByteBuffer buf = ByteBuffer.wrap(message.getBytes());
        int nbytes = channel.write(buf);
        SelectableChannel ss;
    }

    //对通道的读操作
    public void readFromChannel(SocketChannel channel, ClientChInstance clientInstance)
            throws IOException, InterruptedException {
        ByteBuffer byteBuffer = ByteBuffer.allocate(BUFFERSIZE);
        int nbytes = channel.read(byteBuffer);
        byteBuffer.flip();
        String result = this.decode(byteBuffer);
        //当客户端发出”@exit”退出命令时,关闭其通道
        if (result.indexOf("@exit") >= 0) {
            channel.close();
        } else {
            clientInstance.append(result);
            //读入一行完毕,执行相应操作
            if (result.indexOf("\n") >= 0) {
                System.out.println("client input:  " + result);
                clientInstance.execute();
            }
        }
    }
    
    //该类封装了怎样对客户端的通道进行操作,具体实现可以通过重载execute()方法
    public class ClientChInstance {
        SocketChannel channel;
        StringBuffer buffer = new StringBuffer();

        public ClientChInstance(SocketChannel channel) {
            this.channel = channel;
        }

        public void execute() throws IOException {
            String message = "This is response after reading from channel!";
            writeToChannel(this.channel, message);
            buffer = new StringBuffer();
        }
        
        //当一行没有结束时,将当前字窜置于缓冲尾
        public void append(String values) {
            buffer.append(values);
        }
    }


    //主程序
    public static void main(String[] args) {
        GemClass nbServer = new GemClass(12345);
        try {
            nbServer.initialize();
        } catch (Exception e) {
            e.printStackTrace();
            System.exit(-1);
        }
        try {
            nbServer.portListening();
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }
}



比较底层的一些类有
ServerSocketChannel  //用于表示服务器,可以bind服务端地址和端口,关键在于使用accept()开启新的socket连接

SocketChannel; //代表一个socket连接的实例,在例子中使用了Map进行保存引用,进而复用,如保存交互记录等操作

Selector; //比较关键和比较难理解的一个地方,用于管理一组基于注册机制的连接对象,通过select()进行循环监听,在其下的连接对象发起新的事件时,响应并允许进行相应的自定义操作,使用selectedKeys表示所注册的子对象

SelectionKey; //配合Selector使用,用于表示一个或一组selector的类型,读/写/请求,比较抽象的包括了一个连接或者一个服务的类型(PS:比较纠结),因此也常需要进行强制向下转换.常用的方法有:channel(),attach(); 两个分别为关联的channel和所附带的对象,后者可能也可以用于保存一个数据.


这个例子忽略了线程安全带来的问题,可以直接使用telnet ip port进行测试,但如果涉及到服务端write操作,代码还需要调整,否则会有死循环产生!






分享到:
评论

相关推荐

    基于NIO的socket举例

    基于NIO的socket举例 基于NIO的socket举例 基于NIO的socket举例 基于NIO的socket举例 基于NIO的socket举例基于NIO的socket举例 基于NIO的socket举例

    NioSocket,包括server端和client端

    NioSocket是一个基于Java NIO(非阻塞I/O)技术实现的网络通信框架,它包含服务器端(Server)和客户端(Client)两部分。在Java编程中,NIO(New Input/Output)提供了一种不同于传统IO模型的I/O操作方式,其核心...

    基于NIO socket高并发的监控系统

    支持高并发,可以通过socket传输文件。 服务机实现了的功能:1、不间断的接收客户端的消息。2、当有指令过来的时候跟客户机建立连接操作完成后断开连接; 客户机实现了的功能:1、不间断的发送本机运行情况。2、监听...

    java NIO socket聊天室

    使用NIO socket不需要多线程来处理多个连接的请求,效率非常高 可以作为NIO socket入门的例子,Reactor模式,重点理解key.attach, jar文件里包含了源代码 1,运行server.bat启动服务器,可以打开编辑,修改端口号 ...

    Java NIO Socket基本

    **Socket编程在NIO中的应用**: 1. **ServerSocketChannel**:用于监听客户端连接,通过调用`ServerSocketChannel.open()`创建,然后绑定到指定的IP和端口,并调用`accept()`方法接收客户端连接。 2. **...

    java NIO socket聊天

    `Socket`在NIO中的实现是`SocketChannel`,它代表了网络上的一个连接。`ServerSocketChannel`则用于监听客户端的连接请求。通过`ServerSocketChannel`的`accept()`方法,服务器可以接收新的客户端连接,然后将其注册...

    一般Socket客户端与Mina NIO Socket客户端对比示例

    2. 并发能力:Mina NIO的并发能力远超普通Socket,因为其可以有效利用线程资源,处理更多连接。 3. 开发复杂度:Mina NIO需要对Java NIO有深入理解,而普通Socket相对简单,学习曲线较平缓。 4. 扩展性:Mina提供了...

    默蓝网络通信测试工具(NIOSocket工具)支持TCP/IP和HTTP通信-网络通信开发人员必备

    通过NIOSocket工具,开发者能模拟大量并发连接,测试服务器在高负载下的表现。 该工具提供了服务端和客户端连接测试功能,包括单条发送、循环发送以及模拟多客户端发送,这些功能覆盖了网络通信的多种场景。单条...

    java nio socket 例子

    本例包含服务器端和客户端,多线程,每线程多次发送,Eclipse工程,启动服务器使用 nu.javafaq.server.NioServer,启动客户端使用 nu.javafaq.client.NioClient。另本例取自javafaq.nv上的程序修改而成

    java基于NIO实现Reactor模型源码.zip

    java基于NIO实现Reactor模型源码java基于NIO实现Reactor模型源码java基于NIO实现Reactor模型源码java基于NIO实现Reactor模型源码java基于NIO实现Reactor模型源码java基于NIO实现Reactor模型源码java基于NIO实现...

    《NIO与Socket编程技术指南》_高洪岩

    《NIO与Socket编程技术指南》是一本深入探讨Java NIO(New Input/Output)和Socket编程的专业书籍,由高洪岩撰写。本书主要针对Java开发者,旨在帮助他们理解和掌握这两种在开发网络应用中至关重要的技术。 Java ...

    java nio 实现socket

    基于Java NIO的Socket通信流程大致如下: 1. **创建ServerSocketChannel**:服务器端首先需要创建一个`ServerSocketChannel`,用于监听客户端的连接请求。 2. **创建Selector**:创建一个`Selector`对象,用于监听`...

    《NIO与Socket编程技术指南》高洪岩.zip

    非常详细地讲解了NIO中的缓冲区、通道、选择器、编码,以及使用Socket技术实现TCP/IP和UDP编程,细化到了演示全部SocketOption的特性,这对理解基于NIO和Socket技术为基础所开发的NIO框架是非常有好处的,本书以案例...

    nio的socket

    1. **SocketChannel**:这是NIO中的客户端连接通道,用于代替传统的`Socket`。`SocketChannel`可以从服务器接收数据,也可以向服务器发送数据。与`Socket`不同的是,`SocketChannel`是非阻塞的,这意味着当没有数据...

    java基于nio的socket通信.rar

    创建一个简单的NIO Socket服务器,需要创建`ServerSocketChannel`,监听连接,然后对每个连接创建`SocketChannel`,将其注册到选择器上,处理读写事件。客户端则创建`SocketChannel`,连接服务器,然后进行数据传输...

    基于java NIO的socket通信demo

    在这个“基于java NIO的socket通信demo”中,我们将探讨如何使用NIO进行服务器和客户端的Socket通信,并解决通信过程中的字符集乱码问题。 首先,我们来看`NioServer.java`。这个文件中包含了一个基于NIO的服务器端...

    原创nio socket mina+javascript+flash实现commet长连接网页聊天室

    【标题】"原创nio socket mina+javascript+flash实现commet长连接网页聊天室"揭示了一个基于Java NIO(Non-blocking I/O)的Socket通信框架Mina与JavaScript、Flash技术结合,实现COMET(Comet是使服务器向浏览器推...

    NIO socket编程小例子 加法服务器

    总结来说,"NIO socket编程小例子 加法服务器"是一个很好的学习NIO网络编程的起点。通过这个实例,我们可以了解NIO Channel、Buffer和Selector的基本用法,以及如何构建一个简单的网络通信应用。对于任何想要提升...

    nio socket 消息推送

    在`Socket`通信中,`NIO Socket`使用`SocketChannel`代替了`Socket`,`ServerSocketChannel`代替了`ServerSocket`。客户端通过`SocketChannel`连接服务器,服务器端则通过`ServerSocketChannel`监听客户端的连接请求...

    socket通信NIO代理模式demo实例

    NIO(Non-blocking I/O)是Java提供的一个高效I/O模型,相较于传统的IO模型,NIO具有非阻塞、多路复用等特性,能够更好地处理大量并发连接。本实例"socket通信NIO代理模式demo"将展示如何利用NIO来构建一个高性能的...

Global site tag (gtag.js) - Google Analytics