我正在编写一个简单的 HTTP 请求处理程序,但在将文件传输到客户端浏览器时总是随机遇到连接重置错误。
由于我的程序比较大,下面我将代码稍微简化一下:
public class HTTPRequestHandler implements Runnable {
private Queue<HTTPRequest> requests;
private volatile boolean flag;
...
public void run() {
flag = true;
while (flag) {
HTTPRequest request = null;
synchronized(this) {
if (requests.size > 0) {
request = requests.removeFirst();
}
}
if (request != null) {
handleRequest(request);
}
}
}
...
private void handleRequest(HTTPRequest request) {
...
try {
// Send HTTP Header
request.getSocket().getOutputStream().write(message.getHeader().getBytes());
// Send HTTP Message Body
Object messageBody = message.getMessageBody();
if (messageBody != null && messageBody.getClass() == File.class) {
Files.copy(((File)messageBody).toPath(), request.getSocket().getOutputStream());
request.getSocket().getOutputStream().flush();
} else if (messageBody != null) {
...
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
...
}
我能够让这部分大部分时间(并非总是)在本地机器上的各种浏览器上工作,但它在远程机器上根本无法工作。它主要针对大文件随机发生,有时也针对小文件随机发生。
至于 HTTP header ,我目前让程序在每次完成响应后关闭连接。
最佳答案
我在做了一些数据包嗅探后发现了这个设计的问题。在客户端确认接收到数据包之前,服务器发送的数据包太多、速度太快。结果,服务器向客户端发送 TCP 重置。当客户端尝试重新建立连接时,服务器拒绝接受连接,因为它已经退出了发送文件的语句并关闭了套接字连接。客户端继续处理其他文件,并将尝试再次请求不完整的文件。服务器随后会再次发送文件,但客户端将无法像往常一样及时确认。此时,客户端只是放弃了该文件。
由于我的设计一次只能处理一个请求,并且无法从它可能停止的地方接起,修改我的代码以将文件分成 block 并在 hibernate 一毫秒后一次发送一个 block .
if (messageBody != null && messageBody.getClass() == File.class) {
InputStream fileStream = new FileInputStream((File)messageBody);
byte[] buffer = new byte[8 * 1460]; // Maximum TCP packet size
int bytesRead;
while ((bytesRead = fileStream.read(buffer)) != -1) {
request.getSocket().getOutputStream().write(buffer, 0, bytesRead);
try {
Thread.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
fileStream.close();
}
关于java - HTTP 请求处理程序连接重置错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48277549/