`

基于事件的NIO多线程服务器的问题

 
阅读更多

        最近看了很好的一篇博客:http://www.ibm.com/developerworks/cn/java/l-niosvr/

         于是我按照作者给的源码做实验(源码以上传到附件中NIOServer.jar),我模拟发送1000次消息,服务器做出一千次响应。

public static void main(String args[]) {
        Socket client = null;
        DataOutputStream out = null;
        DataInputStream in = null;
        try {
        	for(int i=0;i<CLIENT_NUM;i++){
        		client = new Socket("10.13.30.160", 5100);
                client.setSoTimeout(10000);
                out = new DataOutputStream( (client.getOutputStream()));
                String query = "GB";
                byte[] request = query.getBytes();
                out.write(request);
                out.flush();
                client.shutdownOutput();
                in = new DataInputStream(client.getInputStream());
                byte[] reply = new byte[40];
                in.read(reply);
               System.out.println("Time: " + new String(reply, "GBK"));
                in.close();
                out.close();
                client.close();
        	}
        }
        catch (Exception e) {
        	e.printStackTrace();
            System.out.println(e.getMessage());
        }
    }
}

      但是在运行过程中抛出了异常:

java.io.IOException: 您的主机中的软件放弃了一个已建立的连接。

    经过我调试代码,发现是在Response类的send(byte[] data)中SocketChannel调用write(byte[])的时候出错了。

 

        我在上面的测试代码的System.out.println("Time: " + new String(reply, "GBK"));之后让其Thread.sleep(200);一会儿发现就不会出现上面的放弃建立连接的异常了。

        我在想难道是服务器发送数据的时候,客户端已经关闭了?所以我们让客户端在关闭之前Thread.sleep(200);延迟一会儿等服务器发消息发完?

我查了一下Connect reset的原因,具体可以参考:http://wjy320.iteye.com/blog/2069518

 

        应该可以断定是服务端发送数据的时候,客户端已经关闭了(调用了close());但是客户端中的  in.read(reply)应该会阻塞呀,会一直等到服务端发来的数据后才返回呀,难道是in.read(byte[])是非阻塞的?于是好奇心促使我看了一下DataInputStream和InputStream的read(byte[])的源码。

        

//DataInputStream的read(byte[])源码
public final int read(byte b[]) throws IOException {
        return in.read(b, 0, b.length);
    }
//其中调用了InputStream的read(byte b[], int off, int len);InputStream的read(byte b[], int off, int len)的源代码如下:
public int read(byte b[], int off, int len) throws IOException {
        if (b == null) {
            throw new NullPointerException();
        } else if (off < 0 || len < 0 || len > b.length - off) {
            throw new IndexOutOfBoundsException();
        } else if (len == 0) {
            return 0;
        }

        int c = read();
        if (c == -1) {
            return -1;
        }
        b[off] = (byte)c;

        int i = 1;
        try {
            for (; i < len ; i++) {
                c = read();
                if (c == -1) {
                    break;
                }
                b[off + i] = (byte)c;
            }
        } catch (IOException ee) {
        }
        return i;
    }

 我稍微对InputStream的read(...)进行一下说明:

     从所包含的输入流中读取一定数量的字节,并将它们存储到缓冲区数组 b 中。以整数形式返回实际读取的字节数。在输入数据可用、检测到文件末尾 (end of file) 或抛出异常之前,此方法将一直阻塞。
     如果 b 为 null,则抛出 NullPointerException。如果 b 的长度为零,则不读取字节并返回 0;否则试图读取至少一个字节。如果因为该流在文件末尾而无字节可用,则返回值 -1;否则至少读取一个字节并将其存储到 b 中。
     将读取的第一个字节存储到元素 b[0] 中,将下一个字节存储到 b[1] 中,依此类推。读取的字节数至多等于 b 的长度。设 k 为实际读取的字节数;这些字节将存储在从 b[0] 到 b[k-1] 的元素中,b[k] 到 b[b.length-1] 的元素不受影响。
     如果因为文件末尾以外的其他原因而无法读取第一个字节,则抛出 IOException。尤其在输入流已关闭的情况下,将抛出 IOException。

     顺便说一句,read()每次读一个byte。

 

 由此可见read(...)返回的原因有三个:

      1:给定的参数不合法。

      2:读到了文件末尾(-1) ps:一方关闭也会发送-1。

      3:缓冲区(就是那个byte[])被写满。

 

所以应该不是read(byte[])非阻塞的原因。

      看到第三条,我恍然大悟。难道是我的缓冲区开辟小了,我只开辟了40个byte;而服务器返回的信息是:“Time: 2014年5月22日 星期四 上午11时24分58秒 CST”。长度却是41个byte。所以每次read(...)返回的原因都是缓冲区被写满,而不是服务端发送完毕的文件结尾。那么第二次读的时候操作系统的缓冲区中本身就有一个byte的数据。所以在第二次读数据的时候可能服务端还没有发送完毕,但是客户端因为缓冲区写满就已经关闭了。所以服务器端会报出“放弃一个已经建立的连接”的异常。

     所以客户端每条显示少了最后一个"T",但是肯定能正常显示,不会报异常。而服务器有时候会报出以上异常,跟时机有关。

       所以解决办法就是将客户端的缓冲区开辟大一些就行了,开辟41个byte就行了,服务端就不会报错了。

分享到:
评论

相关推荐

    基于事件的 NIO 多线程服务器

    基于事件的 NIO 多线程服务器

    基于事件的_NIO_多线程服务器

    ### 基于事件的NIO多线程服务器解析 #### 概述 在Java的网络编程中,NIO(Non-blocking I/O)作为一种高效的数据处理模式,自JDK 1.4版本引入以来,逐渐成为了开发高性能网络应用的重要工具之一。与传统的阻塞I/O...

    基于事件的NIO多线程服务器

    【事件回调机制】在基于事件的NIO多线程服务器设计中,事件回调机制是核心组件之一。事件回调允许服务器在特定事件发生时调用预定义的处理函数,以执行相应的业务逻辑。这种方式使得代码更加模块化,易于扩展和维护...

    基于时间的NIO多线程服务器

    ### 基于时间的NIO多线程服务器——深入解析与关键技术点 #### 引言 在服务器端编程领域,随着互联网应用的不断发展,如何高效处理大量的并发连接成为了一个重要议题。Java NIO(非阻塞I/O)作为一种先进的I/O处理...

    基于事件的NIO多线程服务器打包

    该包封装过的NIO比sun本身的更容易处理 server中只有区区几行就搞定了: //创建listener TimeHandler timer = new TimeHandler(); //获取Notifier Notifier notifier = Notifier.getNotifier(); //注册监听 notifier....

    Nio多线程CS收发信息问题(问题已经解决)

    总结来说,"Nio多线程CS收发信息问题"涉及到在Java NIO环境下,如何构建一个多线程、高并发的客户端-服务器通信系统,并解决在这个过程中可能遇到的各种挑战。通过理解NIO的核心概念,合理设计线程管理和异常处理...

    使用多线程的NIO构建简易的多线程java服务器

    构建一个基于NIO的多线程服务器,主要步骤如下: 1. **创建ServerSocketChannel**: 首先,我们需要创建一个`ServerSocketChannel`,它是服务器端接收客户端连接的入口。通过`ServerSocketChannel.open()`方法初始...

    java多线程nio服务器

    Java NIO服务器的多线程设计有助于提高服务器的并发性能,特别是在高并发场景下,可以有效地利用系统资源,避免大量线程导致的内存消耗和上下文切换开销。同时,通过选择器的使用,减少了对主线程的占用,使得服务器...

    Java实现基于NIO的多线程Web服务器实例

    Java实现基于NIO的多线程Web服务器实例 Java实现基于NIO的多线程Web服务器实例是使用Java语言基于NIO(New I/O)技术实现的多线程Web服务器。NIO技术可以提供高性能、低延迟的I/O操作,非常适合高并发的Web服务器。...

    基于HTTP、NIO、多线程实现浏览器高并发非阻塞访问服务器文件

    实现功能:基于HTTP协议,解析请求和拼接响应,基于NIO的非阻塞,线程池,文件传输。代码有详细注释和清晰的框架。 程序入口是: /HttpServerReactor/src/com/StartServer.Java 访问1,浏览:...

    基于多线程的web服务器java源码

    【标题】基于多线程的Web服务器Java源码解析 在Web开发领域,服务器是至关重要的组成部分,它们负责处理客户端的HTTP请求并返回相应的HTTP响应。本篇文章将深入探讨一个基于多线程的Web服务器Java源码,帮助你理解...

    基于Java NIO的网络服务器Netty生产实例.zip

    3. **Netty的事件驱动模型**:Netty采用 reactor 模式,通过EventLoopGroup来管理事件循环线程,每个线程负责处理多个连接的事件。当有新连接、读写事件发生时,会触发相应的ChannelHandler进行处理。 4. **Netty的...

    基于多线程的web服务器

    6. **性能优化**:为了最大化效率,多线程服务器可能采用各种策略,如使用非阻塞I/O(NIO)以减少线程等待时间,或者利用异步事件驱动模型(如Reactor模式)来减少线程上下文切换的开销。 然而,多线程模型并非没有...

    一个基于java nio的简单的http服务器.zip

    1. **Selector(选择器)**:选择器允许单个线程检查多个通道(Channels)上的事件,如连接建立、数据到达等。通过注册通道到选择器,并设置感兴趣的事件类型,我们可以避免创建大量线程来处理每个连接,从而提高...

    多线程web服务器 附实验报告 java

    在IT领域,尤其是在服务器开发中,多线程技术扮演着至关重要的角色,特别是在构建高性能的Web服务器时。本文将深入探讨多线程Web服务器的概念、Java中的Socket编程以及如何通过实现Runnable接口来创建多线程。 多...

    基于nio实现的多文件上传源码

    本主题“基于nio实现的多文件上传源码”探讨的是如何利用Java NIO来实现高效的多文件上传功能,尤其对于小文件数量较大的情况。 首先,理解NIO的基本概念是必要的。NIO中的“非阻塞”意味着当数据不可用时,读写...

    多线程精品资源--Java NIO+多线程实现聊天室.zip

    在这个“多线程精品资源--Java NIO+多线程实现聊天室”的压缩包中,我们可以推测它包含了一套关于如何使用Java NIO和多线程技术来创建一个实时聊天应用的教程或示例代码。 首先,多线程是Java中并行处理的基础。...

    基于java NIO的socket通信demo

    这个文件中包含了一个基于NIO的服务器端实现。服务器的核心组件是`Selector`,它允许一个单独的线程监听多个套接字通道的状态变化。当客户端发起连接请求时,服务器会注册`ServerSocketChannel`到`Selector`上,等待...

Global site tag (gtag.js) - Google Analytics