微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

读取无线电流时关闭 InputStream 挂起

如何解决读取无线电流时关闭 InputStream 挂起

我正在使用 Apache HttpClient 从无线电流中获取元数据。我想要做的是发出 GET 请求,读取一些字节然后关闭流。对于某些流,它可以正常工作,但对于其他一些流,流的关闭会挂起。看起来它仍在接收数据并且在它发生时没有关闭连接。

    public SongInfo retrieveMetadata(String streamUrl) {
        HttpClient httpClient = HttpClients.createDefault();
        HttpGet httpGet = new HttpGet(streamUrl);
        httpGet.addHeader("Icy-MetaData","1");
        httpGet.addHeader("Connection","close");
        httpGet.addHeader("Accept","");
        HttpResponse response;
        try {
            response = httpClient.execute(httpGet);
        } catch (IOException e) {
            log.warn("An exception occurred while fetching the stream",e);
            return null;
        }

        if (response.getStatusLine().getStatusCode() != 200) {
            log.warn("Could not fetch stream. Status line: "+ response.getStatusLine());
            return null;
        }

        int MetadataOffset = retrieveMetadataOffset(response);

        if (MetadataOffset == 0) {
            log.info("Could not find Metadata for url:"+ streamUrl);
            return null;
        }

        List<Metadata> Metadata = extractMetadata(response,MetadataOffset);
        if (Metadata == null || Metadata.isEmpty()) {
            return null;
        }
        return extractSongInfo(Metadata);
    }
    private List<Metadata> extractMetadata(HttpResponse response,int MetadataOffset) {
        String MetadataStr;
        try(InputStream stream = response.getEntity().getContent()) {
            if (stream.skip(MetadataOffset) != MetadataOffset) {
                log.warn("Something went wrong while skipping to Metadata offset");
                return null;
            }
            int MetaDataLength = stream.read() * 16;
            MetadataStr = getMetadataStr(stream,MetaDataLength);
            if (MetadataStr == null) {
                return null;
            }
        } catch (IOException e) {
            log.warn("Something went wrong while reading the stream",e);
            return null;
        } //Hangs here
        //rest of the method
    }

我注意到 response.getEntity().getContent() 返回的流是 EofSensorInputStream 类型,所以我想知道它是否正在等待一个永远不会到来的 EOF 字符。

代码正常运行且流正常关闭的流示例:https://icecast.omroep.nl/radio2-bb-mp3http://live-mp3-128.kexp.org 代码无法正常工作的流示例,因为流永远不会关闭并永远挂起:https://kexp-mp3-128.streamguys1.com/kexp128.mp3

解决方法

出现这个问题是因为在内容流上调用 close() 会尝试消耗剩余的内容。这目前在 documentation 中没有明确提及(另见 HTTPCORE-656),但在 tutorials 中提及:

关闭内容流和关闭响应的区别在于,前者会尝试通过消耗实体内容来保持底层连接处于活动状态,而后者会立即关闭并丢弃连接。
[...]
然而,在某些情况下,只需要检索整个响应内容的一小部分,而消耗剩余内容和使连接可重用的性能损失太高,在这种情况下,可以通过关闭来终止内容流回应。

因此,在您的情况下,关闭 InputStream 返回的 getContent() 而仅关闭 HttpResponse(您显然还没有这样做)似乎是合适的).

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。