`
teasp
  • 浏览: 61145 次
  • 性别: 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基本

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

    java NIO socket聊天室

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

    java nio socket 例子

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

    java nio 实现socket

    ### Java NIO 实现Socket通信详解 #### 一、NIO与传统IO的区别及优势 在探讨如何使用Java NIO实现Socket通信之前,我们需要先理解NIO(Non-blocking I/O,非阻塞I/O)与传统阻塞I/O之间的区别。 **传统阻塞I/O...

    java NIO socket聊天

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

    Ioserver java Nio socket 框架

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

    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的socket通信demo

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

    NioSocket,包括server端和client端

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

    JavaNIO chm帮助文档

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

    nio.rar_NIO_NIO-socket_java nio_java 实例_java.nio

    标题“nio.rar_NIO_NIO-socket_java nio_java 实例_java.nio”表明这个压缩包包含了一个关于Java NIO的实例,特别是关于NIO套接字(Socket)的编程示例。NIO套接字是Java NIO库中用于网络通信的关键组件,它们允许...

    nio.rar_Java socketA_java nio_java socket a

    标题中的“Java socketA_java nio_java socket a”可能是指使用Java NIO实现的Socket通信,这里的"A"可能是表示"Advanced"或"Alternative",意味着比传统的阻塞I/O模型更为高级或替代方案。 在Java Socket API中,...

    java NIO.zip

    Java NIO,全称为Non-Blocking Input/Output(非阻塞输入/输出),是Java标准库提供的一种替代传统的I/O模型的新技术。自Java 1.4版本引入NIO后,它为Java开发者提供了更高效的数据传输方式,尤其是在处理大量并发...

    Java NIO英文高清原版

    Java NIO,全称为Non-Blocking Input/Output(非阻塞输入/输出),是Java平台中用于替代标准I/O(BIO)模型的一种新机制。NIO在Java 1.4版本引入,提供了更高效的数据处理和通道通信方式,特别适用于高并发、大数据...

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

    《网络通信测试与Java NIO Socket编程详解》 在信息技术高速发展的今天,网络通信成为了软件开发中的重要一环。为了确保网络应用的稳定性和效率,网络通信测试工具扮演了不可或缺的角色。"默蓝网络通信测试工具(NIO...

    Java Socket学习---nio实现阻塞多线程通信

    在Java编程领域,Socket是网络通信的基础,它允许两个或多个应用程序通过TCP/IP协议进行数据交换。本篇文章将深入探讨如何使用Java NIO(非阻塞I/O)来实现阻塞多线程通信,这对于高性能服务器端应用尤其重要。我们...

    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基于字节流和字符流进行操作的,...

Global site tag (gtag.js) - Google Analytics