我正在编写一个简单的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标头,我目前让程序在每次完整响应后关闭连接。
答案 0 :(得分:0)
我在做了一些数据包嗅探后发现了这个设计的问题。在客户端确认接收它们之前,服务器发送太多数据包的速度太快。结果,服务器向客户端发送TCP重置。当客户端尝试重新建立连接时,服务器拒绝接受连接,因为它已经退出语句以发送文件并关闭了套接字连接。客户端继续使用其他文件,并尝试再次请求不完整的文件。然后服务器将再次发送文件,但客户端将无法像往常一样及时确认。此时,客户端只是放弃了该文件。
由于我的设计一次只能处理一个请求,并且无法从它可能停止的地方获取,因此修改我的代码以将文件分成块并在睡眠后一次发送一个块一毫秒
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();
}