在读取广播流时关闭inputstream挂起

js4nwp54  于 2021-06-30  发布在  Java
关注(0)|答案(1)|浏览(265)

我正在使用apachehttpclient从无线流中获取元数据。我要做的是发出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-mp3, http://live-mp3-128.kexp.org example 由于流永远不会关闭和挂起,因此代码无法正常工作的流:https://kexp-mp3-128.streamguys1.com/kexp128.mp3

n3schb8v

n3schb8v1#

发生此问题的原因是调用 close() 在内容流上,将尝试使用剩余的内容。目前文档中没有明确提到这一点(另请参见httpcore-656),但教程中提到了这一点:
关闭内容流和关闭响应之间的区别在于,前者将尝试通过使用实体内容来保持底层连接的活动性,而后者则立即关闭并丢弃连接。
[...]
但是,在某些情况下,只需要检索整个响应内容的一小部分,而消耗剩余内容并使连接可重用的性能代价太高,在这种情况下,可以通过关闭响应来终止内容流。
因此,在您的情况下,似乎不关闭 InputStream 退回人 getContent() 但只关闭 HttpResponse (显然你还没有做到)。

相关问题