美文网首页
Java Socket通过读取数据阻塞的解决方案

Java Socket通过读取数据阻塞的解决方案

作者: popesa | 来源:发表于2021-04-02 11:24 被阅读0次

写了一个简单的web后台,用socket接收并解析http请求。然而在网页发出第一次请求时总会卡住(其实是流阻塞了),刷新后可以访问。以及总是读取不到最后一部分数据。

刚开始是这样写的

private String getStringFromIOStream(InputStream ios){
        BufferedReader reader = new BufferedReader( new InputStreamReader(ios));
        StringBuilder ret = new StringBuilder();
        String tstr=null;
        while ((tstr=reader.readLine()) != null) {
           ret.append(tstr).append("\n");
           System.out.println(tstr);
        }
        return ret.toString();
}
image.gif

查看线程信息发现是阻塞在了“tstr=reader.readLine()”这一行。得知是socket输入流读取信息阻塞了,可以理解阻塞在了信息最后一行。于是给socket对象添加超时,并处理异常,如下:

Socket client = tm.serverSocket.accept();
client.setSoTimeout(10); // 这里设置超时时长为10毫秒,对于读取http请求足够了
image.gif
private String getStringFromIOStream(InputStream ios){
        BufferedReader reader = new BufferedReader( new InputStreamReader(ios));
        StringBuilder ret = new StringBuilder();
        String tstr=null;
        try {
            while ((tstr=reader.readLine()) != null) {
                ret.append(tstr).append("\n");
                System.out.println(tstr);
            }
        }catch (IOException e){ // 读取完成时,超时会报异常,结束阻塞。
         }
        return ret.toString();
}
image.gif

这是一旦超时便出发异常,从而解决了阻塞的问题。正在感觉完事大吉时,发现接收不到post请求发来的参数,而http请求,post的参数正是数据的最后一行。于是想到应该是http请求最后没有换行,所以readLine()阻塞在了最后一行数据上,而一旦发生异常,最后一行数据就拿不到了。想过添加参数,但发现添加了参数的Http请求,将所有参数封装在了同一行上,解决。于是换思路,考虑使用字节流解析来避免丢失最后一行数据的问题。代码如下

    private String getStringFromIOStream(InputStream ios) {
        int byteArrLen = 128;

        byte[] bytes = new byte[byteArrLen];
        StringBuilder ret = new StringBuilder();
        int len = byteArrLen;
        try{
            while ((len=ios.read(bytes)) != -1 ){ // 当客户端主动中断连接时此处会返回-1
                ret.append(new String(bytes,0,len)); // 在最后一次读取,len会小于数组大小,此处设置len避免末尾无效数据
                System.out.println(new String(bytes,0,len));
                if(len<byteArrLen){   // 获取不到预定大小说明可以结束
                    break;
                }
            }
        }catch (IOException e){ // 超时结束

        }
        return ret.toString();
    }
image.gif

有4处细节需要注意,都写在上面备注里了。其中三处是结束循环,都不可少。

相关文章

  • Java Socket通过读取数据阻塞的解决方案

    写了一个简单的web后台,用socket接收并解析http请求。然而在网页发出第一次请求时总会卡住(其实是流阻塞了...

  • 理解Java NIO:选择器,这一篇就够了(墙裂推荐)

    传统监控多个Socket的Java解决方案是为每一个Socket创建一个线程并使线程阻塞在read调用处, 直到数...

  • Java NIO系列教程(一) Java NIO 概述

    一、阻塞IO与非阻塞IO 阻塞IO: 通常在进行同步I/O操作时,如果读取数据,代码会阻塞直至有 可供读取的数据。...

  • 从Java Socket非阻塞到Netty入门流程

    Java IO,Socket非阻塞通信流程 这里我们使用一个内嵌的永久循环,来让Socket成为一个非阻塞的通信流...

  • tcp值bio示例

    bio:大概是cpu和内存之间交互数据时,cpu读取数据时的方法,是同步阻塞方法。 nio: aio:大概java...

  • 网络编程总结

    使用read读取非阻塞socket read()函数可能有三种返回值: -1:出错或者无数据可读。 0:对端关闭s...

  • zero-copy

    场景: 从本地磁盘读取数据,然后将这些数据通过socket发送到远端。 read(file, user_buf, ...

  • 零拷贝

    读取数据过程: 两头(从磁盘读取,输出到Socket),中间过程(系统内核Read Buffer,Socket B...

  • java nio解决拆包粘包问题

    一.复现拆包粘包问题: NIO socket是非阻塞的通讯模式,与IO阻塞式的通讯不同点在于NIO的数据要通过ch...

  • java Socket应用

    一、Socket使用时应当注意的一些问题 1.设置超时,从套接字读取信息时,在有数据可供访问之前,读操作会被阻塞,...

网友评论

      本文标题:Java Socket通过读取数据阻塞的解决方案

      本文链接:https://www.haomeiwen.com/subject/hdifkltx.html