java.net.ServerSocket 没有捕获所有连接
java.net.ServerSocket does not catch all connections
我正在尝试在 java 中实现一个 Web 代理服务器,它将在我的浏览器和 Web 之间中继请求和响应。在当前设置中,我让我的浏览器将所有页面请求发送到指定端口上的本地主机,我的代理正在该端口上侦听传入请求。
整个事情都是线程化的,因此可以同时处理多个请求,这就是我的代码:
private void startProxy(int serverPort){
try {
// create a socket to listen on browser requests
ServerSocket servSocket = new ServerSocket(serverPort);
while(true) {
// create a thread for each connection
ProxyThread thread = new ProxyThread(servSocket.accept());
thread.start();
}
} catch (IOException e) {}
}
class ProxyThread extends Thread {
private Socket client;
private Socket server;
public ProxyThread(Socket client) {
this.client = client;
server = new Socket();
}
public void run() {
// passes on requests and responses here
}
我注意到,当我尝试加载包含 20 个不同请求的页面时 html/css/js,有时只会创建 18-19 个线程,并在此过程中丢失一些请求。大多数情况下,对 js 资源或图像的请求会被丢弃,而且它们永远不会是浏览器发出的最后一次请求,因此这不是 运行 耗尽资源的问题。
使用 wireshark,我能够确定丢失的请求确实到达了本地主机,因此出于某种原因 ServerSocket.accept() 实际上不接受连接。发生这种情况是否有任何特殊原因?或者我的代码在某些方面是错误的?
编辑
这是 运行()
的正文
try {
BufferedReader clientOut = new BufferedReader(
new InputStreamReader(client.getInputStream()));
OutputStream clientIn = client.getOutputStream();
// assign default port to 80
int port = 80;
String request = "";
// read in the first line of a HTTP request containing the url
String subRequest = clientOut.readLine();
String host = getHost(subRequest);
// read in the rest of the request
while(!subRequest.equals("")) {
request += subRequest + "\r\n";
subRequest = clientOut.readLine();
}
request += "\r\n";
try {
server.connect(new InetSocketAddress(host, port));
} catch (IOException e) {
String errMsg = "HTTP/1.0 500\nContent Type: text/plain\n\n" +
"Error connecting to the server:\n" + e + "\n";
clientIn.write(errMsg.getBytes());
clientIn.flush();
}
PrintWriter serverOut = new PrintWriter(server.getOutputStream(), true);
serverOut.println(request);
serverOut.flush();
InputStream serverIn = server.getInputStream();
byte[] reply = new byte[4096];
int bytesRead;
while ((bytesRead = serverIn.read(reply)) != -1) {
clientIn.write(reply, 0, bytesRead);
clientIn.flush();
}
serverIn.close();
serverOut.close();
clientOut.close();
clientIn.close();
client.close();
server.close();
} catch(IOException e){
e.printStackTrace();
}
for a webpage with 10 requests, I get 10 HTTP GET, 6 SYN and SYN, ACK with 7 requests successfully passing through the proxy and 3 getting stuck.
所以您有 6 个独立的连接但有 10 个请求,并且每个连接只处理一个请求。您忘记实施 HTTP keepalive。请参阅 RFC 2616。每个连接可能会到达一个以上的请求。您需要为每个请求读取与 content-length header 定义的完全一样多的字节,或者块的总和,无论存在什么,如果有的话,然后不仅仅是关闭您需要的套接字返回并尝试读取另一个请求。如果那给了你流的结尾,关闭套接字。
或者将您的响应作为 HTTP 1.0 或 Connection: close
header 发送回客户端,这样它就不会尝试为另一个请求重用连接。
我正在尝试在 java 中实现一个 Web 代理服务器,它将在我的浏览器和 Web 之间中继请求和响应。在当前设置中,我让我的浏览器将所有页面请求发送到指定端口上的本地主机,我的代理正在该端口上侦听传入请求。
整个事情都是线程化的,因此可以同时处理多个请求,这就是我的代码:
private void startProxy(int serverPort){
try {
// create a socket to listen on browser requests
ServerSocket servSocket = new ServerSocket(serverPort);
while(true) {
// create a thread for each connection
ProxyThread thread = new ProxyThread(servSocket.accept());
thread.start();
}
} catch (IOException e) {}
}
class ProxyThread extends Thread {
private Socket client;
private Socket server;
public ProxyThread(Socket client) {
this.client = client;
server = new Socket();
}
public void run() {
// passes on requests and responses here
}
我注意到,当我尝试加载包含 20 个不同请求的页面时 html/css/js,有时只会创建 18-19 个线程,并在此过程中丢失一些请求。大多数情况下,对 js 资源或图像的请求会被丢弃,而且它们永远不会是浏览器发出的最后一次请求,因此这不是 运行 耗尽资源的问题。
使用 wireshark,我能够确定丢失的请求确实到达了本地主机,因此出于某种原因 ServerSocket.accept() 实际上不接受连接。发生这种情况是否有任何特殊原因?或者我的代码在某些方面是错误的?
编辑
这是 运行()
的正文 try {
BufferedReader clientOut = new BufferedReader(
new InputStreamReader(client.getInputStream()));
OutputStream clientIn = client.getOutputStream();
// assign default port to 80
int port = 80;
String request = "";
// read in the first line of a HTTP request containing the url
String subRequest = clientOut.readLine();
String host = getHost(subRequest);
// read in the rest of the request
while(!subRequest.equals("")) {
request += subRequest + "\r\n";
subRequest = clientOut.readLine();
}
request += "\r\n";
try {
server.connect(new InetSocketAddress(host, port));
} catch (IOException e) {
String errMsg = "HTTP/1.0 500\nContent Type: text/plain\n\n" +
"Error connecting to the server:\n" + e + "\n";
clientIn.write(errMsg.getBytes());
clientIn.flush();
}
PrintWriter serverOut = new PrintWriter(server.getOutputStream(), true);
serverOut.println(request);
serverOut.flush();
InputStream serverIn = server.getInputStream();
byte[] reply = new byte[4096];
int bytesRead;
while ((bytesRead = serverIn.read(reply)) != -1) {
clientIn.write(reply, 0, bytesRead);
clientIn.flush();
}
serverIn.close();
serverOut.close();
clientOut.close();
clientIn.close();
client.close();
server.close();
} catch(IOException e){
e.printStackTrace();
}
for a webpage with 10 requests, I get 10 HTTP GET, 6 SYN and SYN, ACK with 7 requests successfully passing through the proxy and 3 getting stuck.
所以您有 6 个独立的连接但有 10 个请求,并且每个连接只处理一个请求。您忘记实施 HTTP keepalive。请参阅 RFC 2616。每个连接可能会到达一个以上的请求。您需要为每个请求读取与 content-length header 定义的完全一样多的字节,或者块的总和,无论存在什么,如果有的话,然后不仅仅是关闭您需要的套接字返回并尝试读取另一个请求。如果那给了你流的结尾,关闭套接字。
或者将您的响应作为 HTTP 1.0 或 Connection: close
header 发送回客户端,这样它就不会尝试为另一个请求重用连接。