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

重温Java NIO Socket

阅读更多

    好多年都没用Java里面的NIO写Socket应用了,Mina等框架封装了太多东西,现在重新写个NIO Socket的小例子回顾下。其实NIO写正确还是挺不容易的,太多的东西要注意,这个例子太过简单,要想在生产中使用还有更多的东西要注意,比如读和写由于是非阻塞的,每次操作了多少数据是没保证的,读的数据要进行累积拼接,业务逻辑应在线程池中处理等等。。。

public class TestNioServer
{
    private Selector selector;
    
    private List<SocketChannel> channels = new ArrayList<SocketChannel>();
    
    private final byte[] resp; 
    
    ByteBuffer readBuffer = ByteBuffer.allocate(1024);
    
    
    public TestNioServer(int port) throws IOException
    {
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();   
        serverSocketChannel.socket().bind(new InetSocketAddress(port));  
        serverSocketChannel.configureBlocking(false); 
        selector = Selector.open();   
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
        System.out.println("Server is listening at : " + port);
        
        StringBuilder sb = new StringBuilder();
        for (int i=0; i<1000; i++)
        {
            sb.append("how are you? ");
        }
        resp = sb.toString().getBytes();
    }
    
    public void work() throws IOException
    {
        while(true)
        {
            selector.select(); //在此处阻塞
            Set<SelectionKey> keys = selector.selectedKeys();
            /* 此处不可放到另外的线程中处理,原因至少有两个
            1. selector.select()阻塞时刚刚accept的连接是无法进行注册的,
                                    注册行为会因select()阻塞,具体请看register方法的说明。
            2. 如果读或者写事件没被及时处理会导致无数读或者写触发事件*/
            handleSelectionKey(keys, false);
        }
    }
    
    private void handleSelectionKey(Set<SelectionKey> keys, boolean tryAnsyc) throws IOException
    {
        if (keys == null)
        {
            System.out.println("keys == null");
            return;
        }
        Iterator<SelectionKey> itr = keys.iterator();
        while (itr.hasNext())
        {
            SelectionKey key = itr.next();
            itr.remove();
            System.out.println(key);
            if (key.isAcceptable())
            {
                System.out.println("isAcceptable");
                //处理接入的连接
                SocketChannel ch = ((ServerSocketChannel)key.channel()).accept(); //此处与read和wirte处不同
                ch.configureBlocking(false);//默认是阻塞的
                channels.add(ch);
                //如果想异步地执行handleSelectionKey,可以使用wakeup来解除selector.select()阻塞,否则后面的注册会阻塞
                if (tryAnsyc)
                    selector.wakeup();
                ch.register(selector, SelectionKey.OP_READ);
            }
            //一个SelectionKey可以同时有多个状态,因此此处不可用else
            if (key.isReadable())
            {
                System.out.println("isReadable");
                //处理读数据,每个channel的数据需要进行累积,业务逻辑应在另外的线程中处理
                SocketChannel socketChannel = (SocketChannel)key.channel();
                int len = socketChannel.read(readBuffer);//此处非阻塞,读到多少数据没任何保证
                readBuffer.flip();
                byte[] b = new byte[readBuffer.limit()];
                readBuffer.get(b);
                System.out.println("len : " + len + " : " + new String(b));
                readBuffer.clear();
                //回点数据
                socketChannel.register(selector, SelectionKey.OP_WRITE|SelectionKey.OP_READ, ByteBuffer.wrap(resp));
            }
            if (key.isWritable())
            {
                System.out.println("isWritable");
                //处理写数据,也可以放在另外的线程中
                SocketChannel socketChannel = (SocketChannel)key.channel();
                ByteBuffer buf = (ByteBuffer)key.attachment();
                while (buf.hasRemaining())
                {
                    int writtenLen = socketChannel.write(buf);//非阻塞,每次写多少不能保证
                    System.out.println("writtenLen=" + writtenLen);
                }
                //改成注册读事件,否则会有无数写事件被触发,因为只要是IO处于可写状态就会触发
                socketChannel.register(selector, SelectionKey.OP_READ);
            }
            if (key.isConnectable())
            {
                //客户端用的,此处ignore
            }
        }
    }
    
    public void broadcast() throws ClosedChannelException
    {
        for (SocketChannel ch : channels)
        {
            ch.register(selector, SelectionKey.OP_WRITE, ByteBuffer.wrap(resp));
            //如果selector.select()处在阻塞状态,那么新的register将不会影响到它,
            //因此需要在此处将其唤醒,以使register生效
            selector.wakeup();
        }
    }
    
    
    public static void main(String[] args) throws IOException, InterruptedException
    {
        int port = 1234;
        final TestNioServer server = new TestNioServer(port);
        new Thread()
        {
            public void run()
            {
                try
                {
                    server.work();
                }
                catch (IOException e)
                {
                    e.printStackTrace();
                }
            }
        }.start();
        
        Thread.sleep(15000);
        System.out.println("想要广播?");
        server.broadcast();
    }
} 

 

客户端为了简单,使用的是阻塞模式:

public class TestSocketClient
{

    public static void main(String[] args) throws UnknownHostException, IOException, InterruptedException
    {
        int port = 1234;
        Socket socket = new Socket();
        socket.connect(new InetSocketAddress(InetAddress.getByName("localhost"), port));
        final InputStream is = socket.getInputStream();
        OutputStream os = socket.getOutputStream();
        
        new Thread ()
        {
            public void run()
            {
                for (;;)
                {
                    byte[] b = new byte[1024];
                    try
                    {
                        is.read(b);
                    }
                    catch (IOException e)
                    {
                        e.printStackTrace();
                        break;
                    }
                    System.out.println(new String(b));
                }
            }
        }.start();
        
        for (int i=0; i<3; i++)
        {
            os.write(new byte[]{65});
            os.flush();
            System.out.println("written");
            Thread.sleep(1000);
        }
    }
}

  

0
3
分享到:
评论

相关推荐

    java nio 实现socket

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

    java NIO socket聊天室

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

    Java NIO Socket基本

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

    java nio socket 例子

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

    Ioserver java Nio socket 框架

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

    java NIO socket聊天

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

    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...

    JavaNIO chm帮助文档

    Java NIO系列教程(一) Java NIO 概述 Java NIO系列教程(二) Channel Java NIO系列教程(三) Buffer Java NIO系列教程(四) Scatter/Gather Java NIO系列教程(五) 通道之间的数据传输 Java NIO系列教程(六)...

    java nio 包读取超大数据文件

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

    Java NIO英文高清原版

    Java NIO英文高清原版

    java NIO 中文版

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

    基于java NIO的socket通信demo

    java NIO 创建的服务端,能够异步响应客户端的请求,客户端采用nio异步请求服务端,通信之间的乱码使用charset解决

    Java NIO 中文 Java NIO 中文 Java NIO 中文文档

    Java NIO 深入探讨了 1.4 版的 I/O 新特性,并告诉您如何使用这些特性来极大地提升您所写的 Java 代码的执行效率。这本小册子就程序员所面临的有代表性的 I/O 问题作了详尽阐述,并讲解了 如何才能充分利用新的 I/O ...

    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中文版

    java NIO是 java New IO 的简称,在 jdk1.4 里提供的新 api 。 Sun 官方标榜的特性如下: – 为所有的原始类型提供 (Buffer) 缓存支持。 – 字符集编码解码解决方案。 – Channel :一个新的原始 I/O 抽象。 – 支持...

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

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

    Java Nio selector例程

    java侧起server(NioUdpServer1.java),基于Java Nio的selector 阻塞等候,一个android app(NioUdpClient1文件夹)和一个java程序(UI.java)作为两个client分别向该server发数据,server收到后分别打印收到的消息...

    nio.rar_NIO_NIO-socket_java nio_java 实例_java.nio

    java nio 编程一个实例子.服务端程序

    基于Java NIO实现五子棋游戏.zip

    基于Java NIO实现五子棋游戏.zip基于Java NIO实现五子棋游戏.zip 基于Java NIO实现五子棋游戏.zip基于Java NIO实现五子棋游戏.zip 基于Java NIO实现五子棋游戏.zip基于Java NIO实现五子棋游戏.zip 基于Java NIO实现...

    java NIO.zip

    java NIO.zip

Global site tag (gtag.js) - Google Analytics