2 回答

TA贡献1829条经验 获得超6个赞
首先,您必须删除类中的行fis.close();(就在 之前os.close();)HttpRequest:如果不存在文件,则会引发此行,NullPointerException因为它fis为空,因此在向Not Found浏览器发送响应后,您的服务器不会关闭从该浏览器接受的套接字,那就是为什么即使您Not Found在浏览器中看到,您的请求也永远不会结束。
其次,您的客户端卡住的原因是writeUTF()您用于发送请求标头的方法。似乎这一行out.writeUTF(CRLF);并没有真正发送空字符串,而是添加了一些其他与 UTF 相关的字符(您可能会在服务器的控制台输出中注意到这一点),因此您的服务器卡在while((headerLine = br.readLine()).length()!=0)等待客户端发送空字符串,但从未收到它。您需要替换out.writeUTF(CRLF);为out.writeBytes(CRLF);.
此外,BufferedReader用于从套接字接收二进制文件也没什么意义。Reader通常与字符输入流一起使用,因此不适用于您的情况。您可以InputStream通过替换此片段来使用:
String headerLine = null;
while((headerLine = br.readLine()).length()!=0){
System.out.println("asd"+headerLine);
}
有了这个(我选择了 4096 的缓冲区大小,你可以用你喜欢的值替换它):
int readBytes;
byte[] cbuf = new byte[4096];
while((readBytes=inFromServer.read(cbuf, 0, 4096))>-1){
System.out.println("read: " + readBytes);
}
注意:您可能很容易注意到这里不仅InputStream.read()会获取文件本身,还会获取statusLine,contentTypeLine和两个CRLFs,因此如果您想将它们与文件分开,您可以先读取它们,通过发出两个“readLines”然后仅通过以下方式获取文件read()

TA贡献1802条经验 获得超6个赞
在您的服务器中,您使用 writeBytes()
将字符串作为字节序列写入底层输出流。通过丢弃其高八位,按顺序写出字符串中的每个字符。如果没有抛出异常,则写入的计数器增加 s 的长度。
虽然您可能会担心非 ASCII 文本,但通常这正是您所需要的。
在您的客户端中,您尝试使用 writeUTF()
首先,两个字节被写入输出流,就像通过 writeShort 方法给出要跟随的字节数一样。该值是实际写出的字节数,而不是字符串的长度。在 length 之后,使用修改后的 UTF-8 字符编码按顺序输出字符串的每个字符。如果没有抛出异常,写入的计数器会增加写入输出流的总字节数。这将至少是 2 加上 str 的长度,至多是 2 加上 str 长度的三倍。
虽然开头的 2 字节长度在其他情况下可能很有用,但这不是 Web 服务器所期望的,包括您的(这是正确的)。所以writeBytes()在你的客户端到处使用,它会突然起作用:
out.writeBytes("GET /" +args[2] +" HTTP/1.1");
out.writeBytes(CRLF);
out.writeBytes("Host: "+client.getLocalSocketAddress());
out.writeBytes(CRLF);
out.writeBytes("Connection: close" + CRLF);
out.writeBytes("User-agent: close" + CRLF);
out.writeBytes(CRLF);
事实上,这些额外的字节可能在您的服务器输出中可见,至少当我在 Eclipse 中运行它时,我看到了垃圾字符,作为神秘的空白空间和矩形中的一个小问号的组合(注意它们如何也出现在CRLF 单独发送时的行尾):
(第一个请求是由 发出的writeUTF
,第二个来自 Chrome)
添加回答
举报