Java 当连接多个客户端时,套接字 HTTP 服务器变慢
Java Socket HTTP Server gets slow when multiple clients are connected
我正在 Android 制作一个 M-JPEG 服务器,我已经成功地实现了它,但是我遇到了一个问题:
我第一次连接到它(使用浏览器连接),流很好,我得到了实时预览,但是打开一个新客户端(比如,重新加载页面或在新选项卡中打开),流变得越来越慢。即使我关闭以前的客户端,它也不会提高性能。
我试过其他 M-JPEG Android 流媒体(比如 myMobKit),它不会减慢速度。
这是我的服务器代码 -
public class StreamServer implements Runnable {
public static Stack<byte[]> bufferStack;
...
public StreamServer(int port) {
...
bufferStack = new Stack<>();
bufferStack.setSize(100);
}
public void start() {
new Thread(this).start();
}
...
@Override
public void run() {
try {
serverSocket = new ServerSocket(port);
while (isRunning) {
Socket socket = serverSocket.accept();
new Thread(new StreamSocket(socket)).start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
public void addBufferToStack(byte[] buffer) {
bufferStack.push(buffer);
}
}
...以及 Socket 实现 -
public class StreamSocket implements Runnable {
private Stack<byte[]> bufferStack = StreamServer.bufferStack;
...
StreamSocket(Socket socket) throws SocketException {
this.socket = socket;
this.socket.setTcpNoDelay(true);
this.socket.setKeepAlive(false);
...
}
@Override
public void run() {
if (!isStreaming) return;
PrintStream output = null;
try {
output = new PrintStream(socket.getOutputStream());
// Sent the initial header for M-JPEG.
...
// Start the loop for sending M-JPEGs
while (isStreaming && !socket.isClosed() && socket.isConnected()) {
try {
if (bufferStack.empty()) continue;
byte[] buffer = bufferStack.pop();
if (buffer == null) continue;
... (Some headers needed for M-JPEG streaming. Read it on Wikipedia)
output.write(buffer);
} catch (Exception e) {
e.printStackTrace();
}
}
output.flush();
output.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (output != null) output.close();
if (!socket.isClosed() || socket.isConnected()) socket.close();
isStreaming = false;
socket = null;
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
制作新的 JPEG 时调用 addBufferToStack(...)
(拍摄相机的预览帧,并通过本机代码处理成 JPG)。
我认为即使在客户端断开连接后套接字线程也没有关闭,虽然我不确定。请帮助解决这个问题,谢谢!
如果还需要information/code,请告诉我,我会编辑问题并添加。
编辑 -
当服务器启动时,bufferStack
不是空的。服务器启动 在 相机 + 其他一些东西启动之后。
即使对方断开连接,您的循环仍将继续循环:
(注意我的评论)
while (isStreaming && !socket.isClosed() && socket.isConnected()) {
try {
if (bufferStack.empty()) continue;
byte[] buffer = bufferStack.pop();
if (buffer == null) continue;
... (Some headers needed for M-JPEG streaming. Read it on Wikipedia)
output.write(buffer); // <-- will throw Exception if connection is broken
} catch (Exception e) {
e.printStackTrace(); // here you should also reset isStreaming
}
}
通过捕获异常(而不是实际处理它),您可以忽略连接已断开的信息。
检查 isConnected
作为循环条件是多余的 - 如果套接字一旦连接,它将始终为真。见 https://docs.oracle.com/javase/8/docs/api/java/net/Socket.html#isConnected-- :
Note: Closing a socket doesn't clear its connection state, which means this method will return true for a closed socket (see isClosed()) if it was successfuly connected prior to being closed.
我目前不是 100% 确定 isClosed
的行为,但我坚信只有当您调用 close
时它才会变为真,如果底层流抛出 IOException 则不会。
我正在 Android 制作一个 M-JPEG 服务器,我已经成功地实现了它,但是我遇到了一个问题:
我第一次连接到它(使用浏览器连接),流很好,我得到了实时预览,但是打开一个新客户端(比如,重新加载页面或在新选项卡中打开),流变得越来越慢。即使我关闭以前的客户端,它也不会提高性能。
我试过其他 M-JPEG Android 流媒体(比如 myMobKit),它不会减慢速度。
这是我的服务器代码 -
public class StreamServer implements Runnable {
public static Stack<byte[]> bufferStack;
...
public StreamServer(int port) {
...
bufferStack = new Stack<>();
bufferStack.setSize(100);
}
public void start() {
new Thread(this).start();
}
...
@Override
public void run() {
try {
serverSocket = new ServerSocket(port);
while (isRunning) {
Socket socket = serverSocket.accept();
new Thread(new StreamSocket(socket)).start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
public void addBufferToStack(byte[] buffer) {
bufferStack.push(buffer);
}
}
...以及 Socket 实现 -
public class StreamSocket implements Runnable {
private Stack<byte[]> bufferStack = StreamServer.bufferStack;
...
StreamSocket(Socket socket) throws SocketException {
this.socket = socket;
this.socket.setTcpNoDelay(true);
this.socket.setKeepAlive(false);
...
}
@Override
public void run() {
if (!isStreaming) return;
PrintStream output = null;
try {
output = new PrintStream(socket.getOutputStream());
// Sent the initial header for M-JPEG.
...
// Start the loop for sending M-JPEGs
while (isStreaming && !socket.isClosed() && socket.isConnected()) {
try {
if (bufferStack.empty()) continue;
byte[] buffer = bufferStack.pop();
if (buffer == null) continue;
... (Some headers needed for M-JPEG streaming. Read it on Wikipedia)
output.write(buffer);
} catch (Exception e) {
e.printStackTrace();
}
}
output.flush();
output.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (output != null) output.close();
if (!socket.isClosed() || socket.isConnected()) socket.close();
isStreaming = false;
socket = null;
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
制作新的 JPEG 时调用 addBufferToStack(...)
(拍摄相机的预览帧,并通过本机代码处理成 JPG)。
我认为即使在客户端断开连接后套接字线程也没有关闭,虽然我不确定。请帮助解决这个问题,谢谢!
如果还需要information/code,请告诉我,我会编辑问题并添加。
编辑 -
当服务器启动时,bufferStack
不是空的。服务器启动 在 相机 + 其他一些东西启动之后。
即使对方断开连接,您的循环仍将继续循环: (注意我的评论)
while (isStreaming && !socket.isClosed() && socket.isConnected()) {
try {
if (bufferStack.empty()) continue;
byte[] buffer = bufferStack.pop();
if (buffer == null) continue;
... (Some headers needed for M-JPEG streaming. Read it on Wikipedia)
output.write(buffer); // <-- will throw Exception if connection is broken
} catch (Exception e) {
e.printStackTrace(); // here you should also reset isStreaming
}
}
通过捕获异常(而不是实际处理它),您可以忽略连接已断开的信息。
检查 isConnected
作为循环条件是多余的 - 如果套接字一旦连接,它将始终为真。见 https://docs.oracle.com/javase/8/docs/api/java/net/Socket.html#isConnected-- :
Note: Closing a socket doesn't clear its connection state, which means this method will return true for a closed socket (see isClosed()) if it was successfuly connected prior to being closed.
我目前不是 100% 确定 isClosed
的行为,但我坚信只有当您调用 close
时它才会变为真,如果底层流抛出 IOException 则不会。