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

Closing InputStream hangs when reading a radio stream

我正在使用 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-mp3, http://live-mp3-128.kexp.org 代码无法正常工作的流示例,因为流永远不会关闭并永远挂起:https://kexp-mp3-128.streamguys1.com/kexp128.mp3

出现此问题是因为在内容流上调用 close() 将尝试使用剩余的内容。 documentation (see also HTTPCORE-656), but is mentioned in the tutorials:

目前没有明确提及

The difference between closing the content stream and closing the response is that the former will attempt to keep the underlying connection alive by consuming the entity content while the latter immediately shuts down and discards the connection.
[...]
There can be situations, however, when only a small portion of the entire response content needs to be retrieved and the performance penalty for consuming the remaining content and making the connection reusable is too high, in which case one can terminate the content stream by closing the response.

因此,在你的情况下,关闭getContent()返回的InputStream似乎是合适的,但只关闭HttpResponse(你显然还没有做)。