`
friendsys
  • 浏览: 338728 次
  • 性别: 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举例

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

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

    java NIO socket聊天室

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

    java nio 实现socket

    java nio 实现socketjava nio 实现socketjava nio 实现socketjava nio 实现socketjava nio 实现socket

    java NIO socket聊天

    java NIO 高性能 socket通讯,服务端采用单线程,降低了cpu的压力,普通io socket通讯,server需要每个连接运行个线程,容易出现问题,效率也低

    Java NIO Socket基本

    NULL 博文链接:https://b-l-east.iteye.com/blog/1254693

    NioSocket,包括server端和client端

    NioSocket,包括server端和client端。server端有自动判定client掉线机制,client端有自动重连机制。本人已在项目实用,未经允许禁止转载!

    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编程技术指南》高洪岩.zip

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

    java基于nio的socket通信.rar

    java基于nio的socket通信.rar

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

    网络通信工具,服务端和客户端连接测试工具,可单条发送,循环发送,模拟多客户端发送,本工具可以作为网络通信工具或压力测试工具, Java NIO Socket编程,需JAVA运行环境

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

    NULL 博文链接:https://ginge.iteye.com/blog/363178

    nio socket 消息推送

    nio socket 消息推送

    nio的socket

    nio的socket小玩意儿, 对于初学者有点用处,大家可以相互学习下嘛

    Ioserver java Nio socket 框架

    Ioserver java Nio socket 框架 是个不错的NIO 通讯框架,本来想学习mina框架,看了看mina的源码太头痛,本人觉得看懂了Ioserver 再看mina的框架,想多的学习 java NIO 的也可以下载 看看,很值得学习啊!!!

    用Netty实现NIO Socket聊天系统示例

    用Netty实现NIO Socket聊天系统示例 ,完整代码,已开源,希望大家多提意见。

    基于NIO的多线程聊天系统

    基于NIO的多线程聊天系统,代码很少,很经典,51CTO网站上的代码。有登陆和聊天界面。代码结构层次清晰,系统只有6个类。

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

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

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

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

Global site tag (gtag.js) - Google Analytics