我有一个Java小程序,可以从服务器流式传输视频(MJPEG)。我用C#(Windows服务)编写了一个代理服务器,用于放置小程序和多个视频服务器之间。HTML/CSS/Js前端与Java小程序一起使用。除了一件事之外,所有功能都很好(终于!!)。
视频服务器允许您通过REST接口播放录制的视频。剪辑完成后,服务器会打开连接,以防您想向其发送倒带或查找等命令。剪辑在小程序中一直播放到最后。如果你试图启动一个新的剪辑(这需要从Javscript向小程序发送一个命令),浏览器就会冻结。但是,使用相同连接的后续命令会起作用,例如播放、暂停和查找。如果我停止windows服务,浏览器将再次响应。
这就是我假设正在发生的情况:剪辑结束(或暂停);不再发送数据,但连接仍然处于活动状态。小程序正在代理服务器上等待下一帧,但代理服务器正在视频服务器上等待不会再发送任何数据的下一帧。
这是while循环中读取每帧的代码
byte[] img = new byte[mContentLength];
inputStream.skipBytes(headerLen);
inputStream.readFully(img);
我需要以某种方式中断这个代码。
当在HTML前端选择了一个新的视频剪辑时,我们会通知小程序,它会调用CameraStream类上的disconnect()。这就是功能:
// DataInputStream inputStream
// HttpURLConnection conn
public void disconnect() {
System.out.println("disconnect called.");
if(running) {
running = false;
try {
// close the socket
if(inputStream != null) {
inputStream.close();
}
if(conn != null) {
conn.disconnect();
}
inputStream = null;
System.out.println("closed.");
} catch(Exception ignored) {
System.out.println("exc:" + ignored.getMessage());
main.reportErrorFromThrowable(ignored);
}
}
}
为了测试这一点,我播放了一个快速剪辑并运行到最后。然后我选择一个新剪辑。在我的Java控制台中,我得到了输出disconnect called.
,但我没有得到后续的closed.
消息,也没有捕捉到一般的Exception。当我停止Windows服务时,我终于收到了closed.
消息,所以看起来inputStream.close();
正在阻塞。
所以我想我的问题是,我该如何阻止阻塞?readFully(img)
呼叫阻塞了吗?还是断开连接功能(正如我得到的控制台输出所建议的那样)?
编辑:只是为了澄清,我编写了Java小程序、HTML、CSS、Javascript和C#代理服务器,所以我可以访问所有这些代码。我唯一不能修改的代码是视频服务器上的REST接口。
edit2:我本想为这篇文章赚大钱https://stackoverflow.com/questions/12219758/proxy-design-pattern
通常,Java I/O方法会阻塞。最好的解决方案似乎是创建另一个线程来读取数据并使用NIO缓冲区。基于NIO的读取示例(警告:未测试!):
// get the InputStream from somewhere (a queue possibly)
ReadableByteChannel inChannel = Channels.newChannel(inputStream);
ByteBuffer buf = ByteBuffer.allocate(mContentLength + headerLen);
inChannel.read(buf);
byte[] img = new byte[mContentLength];
inChannel.get(img, headerLen, mContentLength);
此代码从InputStream
创建一个Channel
,并使用Channel
读取数据。ReadableByteChannel.read(ByteBuffer)
函数的JavaDoc表示,中断包含对inChannel.read(buf)
调用的线程将停止读取。
你必须修改这个代码,我刚刚把它从脑子里想出来了。祝你好运
我终于找到了答案:
public void disconnect() {
if(running) {
running = false;
try {
try{
// had to add this
conn.getOutputStream().close();
}
catch(Exception exc){
}
// close the socket
if(inputStream != null) {
inputStream.close();
}
if(conn != null) {
conn.disconnect();
}
inputStream = null;
} catch(Exception ignored) {
main.reportErrorFromThrowable(ignored);
}
}
}
尽管我使用的是HttpUrlConnection,这是一种方法,并且没有输出流,但尝试关闭输出流会引发异常,出于某种原因,这一切都成功了。