在上次Java Socket现实简单的HTTP服务我 们实现了简单的HTTP服务,它可以用来模拟HTTP服务,用它可以截获HTTP请求的原始码流,让我们很清楚的了解到我们向服务发的HTTP消息的结 构,对HTTP请求消息有个清晰的认识。这一节我想写了一个客户的程序,就是用来模拟浏览器,用来向服务器发送HTTP请求,最得要的是可以用它来显示服 务器发回来的HTTP响应消息的一般结构。

  1. import java.io.IOException;
  2. import java.io.InputStream;
  3. import java.io.OutputStreamWriter;
  4. import java.net.InetAddress;
  5. import java.net.Socket;
  6. import java.net.UnknownHostException;
  7. import java.util.ArrayList;
  8. /**
  9. * 一个简单的HTTP客户端,发送HTTP请求,模拟浏览器
  10. * 可打印服务器发送过来的HTTP消息
  11. */
  12. public class SimpleHttpClient {
  13. private static String encoding = "GBK";
  14. public static void main(String[] args) {
  15. try {
  16. Socket s = new Socket(InetAddress.getLocalHost(), 8080);
  17. OutputStreamWriter osw = new OutputStreamWriter(s.getOutputStream());
  18. StringBuffer sb = new StringBuffer();
  19. sb.append("GET /HttpStream/gb2312.jsp HTTP/1.1\r\n");
  20. sb.append("Host: localhost:8088\r\n");
  21. sb.append("Connection: Keep-Alive\r\n");
  22. //注,这是关键的关键,忘了这里让我搞了半个小时。这里一定要一个回车换行,表示消息头完,不然服务器会等待
  23. sb.append("\r\n");
  24. osw.write(sb.toString());
  25. osw.flush();
  26. //--输出服务器传回的消息的头信息
  27. InputStream is = s.getInputStream();
  28. String line = null;
  29. int contentLength = 0;//服务器发送回来的消息长度
  30. // 读取所有服务器发送过来的请求参数头部信息
  31. do {
  32. line = readLine(is, 0);
  33. //如果有Content-Length消息头时取出
  34. if (line.startsWith("Content-Length")) {
  35. contentLength = Integer.parseInt(line.split(":")[1].trim());
  36. }
  37. //打印请求部信息
  38. System.out.print(line);
  39. //如果遇到了一个单独的回车换行,则表示请求头结束
  40. } while (!line.equals("\r\n"));
  41. //--输消息的体
  42. System.out.print(readLine(is, contentLength));
  43. //关闭流
  44. is.close();
  45. } catch (UnknownHostException e) {
  46. e.printStackTrace();
  47. } catch (IOException e) {
  48. e.printStackTrace();
  49. }
  50. }
  51. /*
  52. * 这里我们自己模拟读取一行,因为如果使用API中的BufferedReader时,它是读取到一个回车换行后
  53. * 才返回,否则如果没有读取,则一直阻塞,直接服务器超时自动关闭为止,如果此时还使用BufferedReader
  54. * 来读时,因为读到最后一行时,最后一行后不会有回车换行符,所以就会等待。如果使用服务器发送回来的
  55. * 消息头里的Content-Length来截取消息体,这样就不会阻塞
  56. *
  57. * contentLe 参数 如果为0时,表示读头,读时我们还是一行一行的返回;如果不为0,表示读消息体,
  58. * 时我们根据消息体的长度来读完消息体后,客户端自动关闭流,这样不用先到服务器超时来关闭。
  59. */
  60. private static String readLine(InputStream is, int contentLe) throws IOException {
  61. ArrayList lineByteList = new ArrayList();
  62. byte readByte;
  63. int total = 0;
  64. if (contentLe != 0) {
  65. do {
  66. readByte = (byte) is.read();
  67. lineByteList.add(Byte.valueOf(readByte));
  68. total++;
  69. } while (total < contentLe);//消息体读还未读完
  70. } else {
  71. do {
  72. readByte = (byte) is.read();
  73. lineByteList.add(Byte.valueOf(readByte));
  74. } while (readByte != 10);
  75. }
  76. byte[] tmpByteArr = new byte[lineByteList.size()];
  77. for (int i = 0; i < lineByteList.size(); i++) {
  78. tmpByteArr[i] = ((Byte) lineByteList.get(i)).byteValue();
  79. }
  80. lineByteList.clear();
  81. return new String(tmpByteArr, encoding);
  82. }
  83. }

运行时访问一个页面打印如下:

HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Set-Cookie: JSESSIONID=61F659691475622CE7AB9C84E7AE7273; Path=/HttpStream
Content-Type: text/html;charset=GB2312
Content-Length: 81
Date: Mon, 09 Nov 2009 13:15:23 GMT

<html>  
    <body>  
  你好,这是一个简单的测试
    </body> 
</html>

下面来个文件下载的看怎么样?

请求的Jsp页面如下:

  1. <%@page import="java.io.InputStream" contentType="text/html; charset=GB2312"%>
  2. <%@page import="java.io.FileInputStream"%>
  3. <%@page import="java.io.OutputStream"%><html>
  4. <body> <br>
  5. <%
  6. try {
  7. InputStream is = new FileInputStream("e:/tmp/file2.txt");
  8. OutputStream os = response.getOutputStream();
  9. byte[] readContent = new byte[1024];
  10. int readCount = 0;
  11. while (is.available() > 0) {
  12. readCount = is.read(readContent);
  13. os.write(readContent, 0, readCount);
  14. }
  15. is.close();
  16. //注这里一定要关闭,不然的话抛异常,异常请见下面,原因就是response.getWriter()
  17. //与response.getOutputStream()不能同时使用,如果在这里关闭了,前面与后面向
  18. //out对象里写的数据就不会刷新到客户端了,只有向response.getOutputStream()写的
  19. //数据会输出到客户端。
  20. os.close();
  21. } catch (Exception e) {
  22. e.printStackTrace();
  23. }
  24. %>
  25. </body>
  26. </html>

如里上面Jsp下载页面中的 os.close() 注释掉的话会抛如下异常:

exception

org.apache.jasper.JasperException: getOutputStream() has already been called for this response
org.apache.jasper.servlet.JspServletWrapper.handleJspException(JspServletWrapper.java:476)
org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:383)
org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:315)
org.apache.jasper.servlet.JspServlet.service(JspServlet.java:265)
javax.servlet.http.HttpServlet.service(HttpServlet.java:803)

root cause

java.lang.IllegalStateException: getOutputStream() has already been called for this response
org.apache.catalina.connector.Response.getWriter(Response.java:601)
org.apache.catalina.connector.ResponseFacade.getWriter(ResponseFacade.java:196)
org.apache.jasper.runtime.JspWriterImpl.initOut(JspWriterImpl.java:125)
org.apache.jasper.runtime.JspWriterImpl.flushBuffer(JspWriterImpl.java:118)
org.apache.jasper.runtime.PageContextImpl.release(PageContextImpl.java:185)
org.apache.jasper.runtime.JspFactoryImpl.internalReleasePageContext(JspFactoryImpl.java:116)
org.apache.jasper.runtime.JspFactoryImpl.releasePageContext(JspFactoryImpl.java:76)
org.apache.jsp.gb2312_jsp._jspService(gb2312_jsp.java:78)
org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:98)
javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:328)
org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:315)
org.apache.jasper.servlet.JspServlet.service(JspServlet.java:265)
javax.servlet.http.HttpServlet.service(HttpServlet.java:803)

以下是服务器经过编译生成的servlet类文件:

  1. package org.apache.jsp;
  2. import javax.servlet.*;
  3. import javax.servlet.http.*;
  4. import javax.servlet.jsp.*;
  5. import java.io.InputStream;
  6. import java.io.FileInputStream;
  7. import java.io.OutputStream;
  8. public final class gb2312_jsp extends org.apache.jasper.runtime.HttpJspBase
  9. implements org.apache.jasper.runtime.JspSourceDependent {
  10. private static java.util.List _jspx_dependants;
  11. public Object getDependants() {
  12. return _jspx_dependants;
  13. }
  14. public void _jspService(HttpServletRequest request, HttpServletResponse response)
  15. throws java.io.IOException, ServletException {
  16. JspFactory _jspxFactory = null;
  17. PageContext pageContext = null;
  18. HttpSession session = null;
  19. ServletContext application = null;
  20. ServletConfig config = null;
  21. JspWriter out = null;
  22. Object page = this;
  23. JspWriter _jspx_out = null;
  24. PageContext _jspx_page_context = null;
  25. try {
  26. _jspxFactory = JspFactory.getDefaultFactory();
  27. response.setContentType("text/html; charset=GB2312");
  28. pageContext = _jspxFactory.getPageContext(this, request, response,
  29. null, true, 8192, true);
  30. _jspx_page_context = pageContext;
  31. application = pageContext.getServletContext();
  32. config = pageContext.getServletConfig();
  33. session = pageContext.getSession();
  34. out = pageContext.getOut();
  35. _jspx_out = out;
  36. out.write("\r\n");
  37. out.write("\r\n");
  38. out.write("\r\n");
  39. out.write("<html>\r\n");
  40. out.write("\t<body> <br>\r\n");
  41. out.write("\t\t");
  42. try {
  43. InputStream is = new FileInputStream("e:/tmp/file2.txt");
  44. OutputStream os = response.getOutputStream();
  45. byte[] readContent = new byte[1024];
  46. int readCount = 0;
  47. while (is.available() > 0) {
  48. readCount = is.read(readContent);
  49. os.write(readContent, 0, readCount);
  50. }
  51. is.close();
  52. //注这里一定要关闭,不然的话抛异常,异常请见下面,原因就是response.getWriter()
  53. //与response.getOutputStream()不能同时使用,如果在这里关闭了,前面与后面向
  54. //out对象里写的数据就不会刷新到客户端了,只有向response.getOutputStream()写的
  55. //数据会输出到客户端。
  56. os.close();
  57. } catch (Exception e) {
  58. e.printStackTrace();
  59. }
  60. out.write("\r\n");
  61. out.write("\t</body>\r\n");
  62. out.write("</html>");
  63. } catch (Throwable t) {
  64. if (!(t instanceof SkipPageException)){
  65. out = _jspx_out;
  66. if (out != null && out.getBufferSize() != 0)
  67. out.clearBuffer();
  68. if (_jspx_page_context != null) _jspx_page_context.handlePageException(t);
  69. }
  70. } finally {
  71. if (_jspxFactory != null) _jspxFactory.releasePageContext(_jspx_page_context);
  72. }
  73. }
  74. }

最后是服务向客户端输出的码流如下:

HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Set-Cookie: JSESSIONID=328097D70C625E8A9279FF9472319A5D; Path=/HttpStream
Content-Type: text/html;charset=GB2312
Content-Length: 60
Date: Mon, 09 Nov 2009 13:19:22 GMT

这是测试文件的内容:
中a ~!@#$%^&*()_+{}|:\" <>?`-=[]\\;',./

原文:http://blog.csdn.net/a9529lty/article/details/7174265

Java Socket发送与接收HTTP消息简单实现的更多相关文章

  1. 2.技巧: 用 JAXM 发送和接收 SOAP 消息—Java API 使许多手工生成和发送消息方面必需的步骤自动化

    转自:https://www.cnblogs.com/chenying99/archive/2013/05/23/3094128.html 技巧: 用 JAXM 发送和接收 SOAP 消息—Java ...

  2. (七)发送、接收SOAP消息(以HttpClient方式)(2)

    一.为什么要用soap 原本我们使用web服务都是根据wsdl生成客户端(生成一堆java文件)然后再调用,本章节讲解如何用soap消息来替代这种方式. 二.SOAP消息格式 SOAP(简单对象访问协 ...

  3. java socket实现服务端,客户端简单网络通信。Chat

    之前写的实现简单网络通信的代码,有一些严重bug.后面详细写. 根据上次的代码,主要增加了用户注册,登录页面,以及实现了实时显示当前在登录状态的人数.并解决一些上次未发现的bug.(主要功能代码参见之 ...

  4. (六)发送、接收SOAP消息(1)

    一.为什么要用soap 原本我们使用web服务都是根据wsdl生成客户端(生成一堆java文件)然后再调用,本章节讲解如何用soap消息来替代这种方式. 二.SOAP消息格式 SOAP(简单对象访问协 ...

  5. Java邮件发送与接收原理

    一. 邮件开发涉及到的一些基本概念 1.1.邮件服务器和电子邮箱 要在Internet上提供电子邮件功能,必须有专门的电子邮件服务器.例如现在Internet很多提供邮件服务的厂商:sina.sohu ...

  6. socket发送和接收数据

    1)sendBuf(),sendText(),sendStream() 几乎所有的通信控件都会提供上面的3个方法.首先看看SendBuf(). function TCustomWinSocket.Se ...

  7. 如何使用C#和VB发送和接收MSMQ消息

    在这篇博客中,我们将就如何实现System.Messaging类发送和接收的XML消息发送从MSMQ队列,你可能会遇到接收的XML消息的一些问题. 我们将首先加入参考System.Messaging ...

  8. XMPP系列(四)---发送和接收文字消息,获取历史消息功能

    今天开始做到最主要的功能发送和接收消息.获取本地历史数据. 先上到目前为止的效果图:              首先是要在XMPPFramework.h中引入数据存储模块: //聊天记录模块的导入 # ...

  9. 解决Springboot整合ActiveMQ发送和接收topic消息的问题

    环境搭建 1.创建maven项目(jar) 2.pom.xml添加依赖 <parent> <groupId>org.springframework.boot</group ...

随机推荐

  1. Python-str函数

    elp on class str in module __builtin__: 关于__builtin__模块中str类的帮助信息: class str(basestring) |  str(obje ...

  2. gdb学习

    gdb学习 [参考资料] http://www.cnblogs.com/jiu0821/p/4483804.html 程序的运行状态有"运行"."暂停".&qu ...

  3. 结合php ob函数理解缓冲机制

    对于一个刚刚入门的php程序员来说,php缓冲区是几乎透明的.在他们心目中,一个echo print_r 函数,数据便会‘嗖’的一声飞到浏览器上,显示出来.我也一直如此单纯地认为. 其实,在技术的世界 ...

  4. web安全——简介

    简介 不对外提供服务是最安全的. 安全是基于信任.如果信任失败了,则没有安全.比如你给一个ip加白名单,结果这个ip对你发动了安全攻击. 在非常明确需要提供服务的时候才对外提供服务,即白名单.其他的全 ...

  5. 配置ipvsadm服务

    LVS的三种包转发方式      LVS提供了三种包转发方式:NAT(网络地址映射).IP Tunneling(IP隧道).Direct Routing(直接路由)     不同的转发模式决定了不同的 ...

  6. 每天一个linux命令(7):cp 命令

    cp 命令用来复制文件或者目录,是Linux系统中最常用的命令之一.一般情况下,shell会设置一个别名,在命令行下复制文件时,如果目标文件已经存在, 就会询问是否覆盖,不管你是否使用-i参数.但是如 ...

  7. 【The final】软件工程实践总结

    软件工程就这么告一段落了,竟然有那么一丢丢的舍不得-- 一.为拖延找的种种借口     [首先声明]以下纯粹是个人吐槽,仅作记录以便日后自己可以回顾一下往昔罢了,可以直接忽略,跳到第二大点:我的拖延之 ...

  8. psd做成HTML相关参考页面

    前端制作(美工)是怎么把PSD制作成页面的? 美工怎么做的我不清楚,因为我是做前端的,我就从前端这个角度说吧. 首先拿到PSD,先分析哪些是要导出为图片的,哪些是可以自己用代码完成的.将图片全部导出, ...

  9. Mybatis出现:无效的列类型: 1111 错误

    在使用Mybatis时,不同的xml配置文件,有的会提示:无效的列类型: 1111 比如这个sql: update base.sys_person t set t.rybh=#{rybh},t.xm= ...

  10. hdu3986 spfa+枚举

    这题让我第一次感受到了什么叫做在绝望中A题.这题我总共交了18次,TLE不知道几次,WA也不知道几次. 这题不能用dijkstra,用这个我一直超时(我没试过dij+优先队列优化,好像优先队列优化后可 ...