接收http请求时,简单的Web服务器挂起

时间:2011-03-30 11:40:40

标签: java sockets networking

我正在编写一个简单的Web服务器,代码片段:

 ServerSocket server = new ServerSocket(80);  
  Socket client=server.accept();  
  InputStream in=client.getInputStream();  
  OutputStream out=client.getOutputStream();  
  int val = -1;  
  while ((val = in.read()) != -1) {  
    System.out.print((char) val);  
  }   
  BufferedWriter writer = new BufferedWriter(new OutputStreamWriter( out));  
  writer.write("HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=utf-8\r\n\r\nhello world!");  
  writer.close();  
  out.close();  
  in.close();

我在计算机上运行它,然后在Firefox中访问http://127.0.0.1。页面挂起,无法显示“hello world”。我认为问题发生在while ((val = in.read()) != -1),如何解决?

1 个答案:

答案 0 :(得分:4)

HTTP(至少1.1版本)允许打开连接。然后请求以空行(即"\r\n\r\n")结束,如果它不是带有内容的POST或PUT请求。在此之后,客户端可以在同一连接上发送下一个请求。

所以你必须阅读输入,至少扫描你的空行。


编辑:为了澄清这一点,来自RFC 2616(定义HTTP 1.1)的一些引用。

部分 4.1,消息类型

  

请求(第5节)和响应(第6节)消息使用通用     用于传输实体的RFC 822 [9]的消息格式(有效载荷     的消息)。两种类型的消息都包含一个起始行,即零     或更多标题字段(也称为“标题”),空行(即,     CRLF之前没有任何内容的行)表示结束     标题字段,可能还有消息正文。

   generic-message = start-line
                     *(message-header CRLF)
                     CRLF
                     [ message-body ]
   start-line      = Request-Line | Status-Line

因此,消息头和消息体由空行(起始行后面的第一行)分隔。

部分 4.3消息正文

  

HTTP消息的消息体(如果有的话)用于携带     与请求或响应关联的实体主体。 [...]

     

邮件中允许邮件正文的规则有所不同     请求和回复。

     

请求中存在消息正文     包含Content-Length或Transfer-Encoding标头字段     请求的消息头。邮件正文不得包含在内     如果请求方法的规范请求(第5.1.1节)     不允许在请求中发送实体主体。服务器应该     在任何请求上读取和转发消息正文;如果是请求方法     不包含实体主体的定义语义,然后是     处理请求时,应该忽略message-body。

因此原则上,客户端必须只在方法允许时发送一个正文,但是服务器应该忽略多余的消息体,如果它们是在不支持它的方法上发送的。 Content-LengthTransfer-Encoding标题字段表示正文的存在。

第9节的小节定义了各个方法。

  • 9.2选项
    • 可以包含正文,但意义未定义
  • 9.3 GET
    • 不能包含身体
  • 9.4 HEAD
    • 不能包含身体
  • 9.5 POST
    • 应该(或必须?)包含一个正文
  • 9.6 PUT
    • 应该(或必须?)包含一个正文
  • 9.7删除
    • 不能包含身体
  • 9.8 TRACE
    • 不能包含身体
  • 9.9连接
    • (此方法保留)

无论如何,无论客户端是否发送正文,以及它是否重新使用连接以进行下一个请求,通常都不会在读取响应之前关闭连接,否则您的服务器无法重新发送总的来说。因此,您在阅读请求时无法等待结束,但必须知道何时结束发送您的回复。

对于只处理获取请求的简单hello world服务器,您可以简单地说“直到第一个空行”。

对于真实服务器(即外部世界可见的服务器),您至少应该解析请求,忽略任何正文,并以不同于GET的方式处理HEAD(即不发送任何正文),并发送不支持的方法的错误响应。