Java 代理 - 无法接收来自 host/Socket 问题的响应
Java Proxy - Can't receive response from host/Socket issue
我正在编写一个简单的 Java 代理。总体架构已提供给我(方法签名等),这就是 Main class 的外观:
private static Socket clientSocket;
private static ServerSocket client;
private static int myPort;
public static void init(int port) throws IOException {
client = new ServerSocket(port);
clientSocket = client.accept();
}
public static void handle(Socket clientSocket) {
try {
BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
HttpRequest httpRequest = new HttpRequest(in);
String hostname = httpRequest.getHost();
//443 hardcoded from reading the http headers.
//Testing using isitchristmas.com
Socket serverSocket = new Socket(hostname, 443);
BufferedReader out = new BufferedReader(new InputStreamReader(serverSocket.getInputStream()));
HttpResponse httpResponse = new HttpResponse(out);
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String args[]) {
try {
myPort = Integer.parseInt(args[0]);
try {
System.out.println("Initializing socket...");
init(myPort);
} catch (IOException e) {
System.out.println("[ERROR]: " + e.getMessage());
}
handle(clientSocket);
} catch (Exception e) {
System.out.println("[ERROR]: " + e.getMessage());
}
}
但是在读入 HttpResponse
时控制台挂起并且从未完成请求 class:
public HttpResponse(BufferedReader fromServer) throws IOException {
String line;
String statusLine = "";
// Never goes past here
while ((line = fromServer.readLine()) != null) {
if (line.isEmpty()) {
break;
}
if (line.toLowerCase().contains("status")) {
statusLine = line;
}
response.append(line);
}
if (!response.toString().isEmpty()) {
getDataAndHeadersFromResponse(response.toString());
System.out.println("\n\nHTTP Response:\n");
System.out.println("Status Line: " + statusLine);
System.out.println("Header Lines: " + headerLines + "\n\n");
System.out.println("Data: " + data);
}
}
我怀疑这与我创建套接字的方式有关...不在 ServerSocket
上调用 close()
会发出 Address already in use: JVM_Bind 异常。我似乎也没有正确获取 serverSocket 参数。正如您现在所知道的,我不是很精通套接字编程。这里有什么问题?
- 您需要在端口 80 上侦听:作业中没有关于 HTTPS 的内容。
- 请求body不会在流结束时终止,因为客户端仍然打开套接字来读取响应。
- 您需要从客户端读取 Content-length header,然后准确读取那么多字节的请求 body。
- 因此您无法使用
BufferedReader
解决此问题,因为您必须计算字节数,而不是字符数。
- 将请求发送到服务器后,您真正需要做的就是将响应字节直接从服务器复制到客户端:不是作业。
- 为了坚持作业所说的内容,您同样必须从服务器读取 Content-Length header,以及所有其他 header 和空白行,以及来自服务器的 content-length 字节的响应,并将它们全部复制到客户端。您可以看到,与仅复制字节相比,这是浪费时间。
- HTTP 中的行终止符是
\r\n
,而不是 \n
。
作业不足:
- 指定不可行的
BufferedReader
- 然后不一致地指定
DataInputStream
从服务器读取
- 根本没有理由使用
DataInputStream
:InputStream
就足够了
- 未提及 RFC 2616 或其前身或后继者
- 未指定是 HTTP 1.0 还是 1.1
- 不多说 'to cache Web pages',仅在第 2 页提及,此后再未提及。
学生应该抱怨。
我正在编写一个简单的 Java 代理。总体架构已提供给我(方法签名等),这就是 Main class 的外观:
private static Socket clientSocket;
private static ServerSocket client;
private static int myPort;
public static void init(int port) throws IOException {
client = new ServerSocket(port);
clientSocket = client.accept();
}
public static void handle(Socket clientSocket) {
try {
BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
HttpRequest httpRequest = new HttpRequest(in);
String hostname = httpRequest.getHost();
//443 hardcoded from reading the http headers.
//Testing using isitchristmas.com
Socket serverSocket = new Socket(hostname, 443);
BufferedReader out = new BufferedReader(new InputStreamReader(serverSocket.getInputStream()));
HttpResponse httpResponse = new HttpResponse(out);
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String args[]) {
try {
myPort = Integer.parseInt(args[0]);
try {
System.out.println("Initializing socket...");
init(myPort);
} catch (IOException e) {
System.out.println("[ERROR]: " + e.getMessage());
}
handle(clientSocket);
} catch (Exception e) {
System.out.println("[ERROR]: " + e.getMessage());
}
}
但是在读入 HttpResponse
时控制台挂起并且从未完成请求 class:
public HttpResponse(BufferedReader fromServer) throws IOException {
String line;
String statusLine = "";
// Never goes past here
while ((line = fromServer.readLine()) != null) {
if (line.isEmpty()) {
break;
}
if (line.toLowerCase().contains("status")) {
statusLine = line;
}
response.append(line);
}
if (!response.toString().isEmpty()) {
getDataAndHeadersFromResponse(response.toString());
System.out.println("\n\nHTTP Response:\n");
System.out.println("Status Line: " + statusLine);
System.out.println("Header Lines: " + headerLines + "\n\n");
System.out.println("Data: " + data);
}
}
我怀疑这与我创建套接字的方式有关...不在 ServerSocket
上调用 close()
会发出 Address already in use: JVM_Bind 异常。我似乎也没有正确获取 serverSocket 参数。正如您现在所知道的,我不是很精通套接字编程。这里有什么问题?
- 您需要在端口 80 上侦听:作业中没有关于 HTTPS 的内容。
- 请求body不会在流结束时终止,因为客户端仍然打开套接字来读取响应。
- 您需要从客户端读取 Content-length header,然后准确读取那么多字节的请求 body。
- 因此您无法使用
BufferedReader
解决此问题,因为您必须计算字节数,而不是字符数。 - 将请求发送到服务器后,您真正需要做的就是将响应字节直接从服务器复制到客户端:不是作业。
- 为了坚持作业所说的内容,您同样必须从服务器读取 Content-Length header,以及所有其他 header 和空白行,以及来自服务器的 content-length 字节的响应,并将它们全部复制到客户端。您可以看到,与仅复制字节相比,这是浪费时间。
- HTTP 中的行终止符是
\r\n
,而不是\n
。
作业不足:
- 指定不可行的
BufferedReader
- 然后不一致地指定
DataInputStream
从服务器读取 - 根本没有理由使用
DataInputStream
:InputStream
就足够了 - 未提及 RFC 2616 或其前身或后继者
- 未指定是 HTTP 1.0 还是 1.1
- 不多说 'to cache Web pages',仅在第 2 页提及,此后再未提及。
学生应该抱怨。