我正在尝试编写一个简单的Java http客户端,该客户端仅打印出服务器响应的一行。我的问题是服务器没有响应。这是我所拥有的,正在编译并且没有明显错误地运行,只是在键入主机名(例如“ www.google.com”)后挂起:
import java.io.*; import java.net.*; public class DNSTest { // Constructor public DNSTest() { } // Builds GET request, opens socket, waits for response, closes public static void main(String[] args) throws Exception{ String line; BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); //For each hostname while ((line = br.readLine()) != null){ //Resolve the hostname to an IP address InetAddress ip = InetAddress.getByName(line); //Open socket on ip address Socket socket = new Socket(ip, 80); PrintWriter out = new PrintWriter(socket.getOutputStream(), true); BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); //Send request out.println("GET /index.html HTTP/1.0\n"); //Read one line of input System.out.println("Response from "+line+": "+in.readLine()); } } }
有什么建议?请注意,这假设存在一个“ index.html”-即使为true,它仍会挂起。
我认为我可以通过对代码进行少量更改来重现该问题,因此现在它在我的计算机上不起作用,并且表现出与您的环境相同的行为。我只是将out.println调用更改为更简单的命令out.print,瞧瞧,该程序 在 发出请求之后但 在 最后一次println调用 之前 挂起。
out.println
out.print
println
据我所记得,HTTP请求需要在标头后面提供一个空行,其中行分隔符必须是\r\n几个字符。我想您的环境println不会发送正确的行分隔符(您可以检查的值System.getProperty("line.separator")以验证哪些是系统上使用的分隔符),因此服务器将请求解释为不完整,并且在输入端。一些服务器相当宽容,只接受\n行分隔符,但是如果您碰巧\n显式地和\r\n隐式地发送(通过println),则您假定的空行包含该\r字符并且不再被视为空行,可能会导致请求的结果错误阻止服务器发回任何响应。
\r\n
System.getProperty("line.separator")
\n
\r
因此,我的建议是print显式使用并发送正确的行分隔符。另外,您很可能需要添加对的调用flush,可能是因为输出之间存在空行- 我不是很清楚,但是如果不调用flush我的程序仍然会挂起。因此,总而言之,以下应该起作用:
print
flush
// send request out.print("GET /index.html HTTP/1.0\r\n\r\n"); out.flush(); // read one line of input System.out.println("Response from " + line + ": " + in.readLine());
至少,通过这些更改,我也可以确认程序可以在我的机器上正常工作。