为了账号安全,请及时绑定邮箱和手机立即绑定

BufferReader 卡在 readline()

BufferReader 卡在 readline()

MMMHUHU 2021-12-18 15:31:42
我正在为简单的 Http 请求和响应制作一个 HTTP 服务器和 HTTP Web 客户端。这是服务器的代码import java.io.*;import java.net.*;import java.util.*;public final class WebServer{public static void main(String[] args) throws Exception{    //storing port number    int port = 2048;    //open socket and wait for TCP connection    ServerSocket serverConnect = new ServerSocket(port);    System.out.println("Server started.\nListening for connections on port : " + port + " ...\n");        // we listen until user halts server execution    while (true) {        //Construct an object to process the HTTP request message.         //This will call another class where we do everything else        HttpRequest request = new HttpRequest(serverConnect.accept());        //create a new thread to process the request        Thread thread = new Thread(request);        thread.start();    } //end of while}//end of main}//end of the class webServer
查看完整描述

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()


查看完整回答
反对 回复 2021-12-18
?
呼啦一阵风

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 单独发送时的行尾):

//img1.sycdn.imooc.com//61bd8e880001ddbc08920194.jpg

(第一个请求是由 发出的writeUTF,第二个来自 Chrome)


查看完整回答
反对 回复 2021-12-18
  • 2 回答
  • 0 关注
  • 756 浏览

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号