当前位置: 首页 > 编程日记 > 正文

Java Socket发送与接收HTTP消息简单实现

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

[java] view plaincopy
  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页面如下:

[java] view plaincopy
  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 responseorg.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 responseorg.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类文件:

[java] view plaincopy
  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

转载于:https://www.cnblogs.com/langtianya/p/4329081.html

相关文章:

微信小程序日期相减得出天数

微信小程序开发交流qq群 173683895 承接微信小程序开发。扫码加微信。 正文&#xff1a; // 日期结算 num_data: function (e) {var start_date new Date(this.data.start_date.replace(/-/g, "/"));var end_date new Date(this.data.end_date.replace(/-/g, &q…

es6 ... 添加属性_如何在10分钟内免费将HTTPS添加到您的网站,以及为什么您现在不止需要这样做......

es6 ... 添加属性by Ayo Isaiah通过Ayo Isaiah 如何在10分钟内免费将HTTPS添加到您的网站&#xff0c;以及为什么现在比以往更需要这样做 (How to add HTTPS to your website for free in 10 minutes, and why you need to do this now more than ever) Last week, Google ann…

程序员跳槽全攻略——读书笔记

有同学说&#xff0c;我技术很好啊&#xff0c;又会机器学习又会编译原理&#xff0c;凭什么那些写Javascript的薪水比我高一倍&#xff1f; 谁让你在一家建站公司上班呢。对一家做网站的公司而言&#xff0c;机器学习和编译原理是不能为它带来收益的&#xff0c;而Javascript写…

[转] Gradle: 此时不应有 Androidandroid-studiosdk oolslib\find_java.exe。解决方法

上述问题主要是java路径的问题&#xff0c;这里主要给出解决方案&#xff0c;至于为什么这么解决的&#xff0c;大家可以学学bat语言。想问的可以留言我。 dx.bat 根据安装目录&#xff0c;我的是D:\Program Files (x86)\Android\android-studio\sdk\build-tools\android-4.2.2…

微信小程序和微信小程序之间的跳转和传参示例代码附讲解

微信小程序开发交流qq群 173683895 承接微信小程序开发。扫码加微信。 正文&#xff1a; 一&#xff1a;微信小程序跳转 使用限制 需要用户触发跳转 从 2.3.0 版本开始&#xff0c;若用户未点击小程序页面任意位置&#xff0c;则开发者将无法调用此接口自动跳转至其他小…

电子界卡组构建2019_2018–2019年构建现代Android应用程序的路线图

电子界卡组构建2019Kriptofolio应用程序系列—简介 (Kriptofolio app series — Introduction) Welcome to this series of blog posts where I will be creating a modern Android app. I will use the best tools and practices available in the year 2018–2019. I am doin…

python操作mysql数据库实现增删改查

Python 标准数据库接口为 Python DB-API&#xff0c;Python DB-API为开发人员提供了数据库应用编程接口。 Python 数据库接口支持非常多的数据库&#xff0c;你可以选择适合你项目的数据库&#xff1a; GadFlymSQLMySQLPostgreSQLMicrosoft SQL Server 2000InformixInterbaseOr…

弹性布局,自动按比例居中

1. 让行类盒子及盒子的元素 自动按比例居中效果图 html <view classaaa><view classbbb>aaaaaaaaa</view><view classbbb>aaaaaaaaa</view><view classbbb>bb</view><view classbbb>aaaaaaaaa</view> </view> c…

Ubuntu 14.04系统托盘图标问题,skype托盘图标显示

Ubuntu 14.04系统托盘图标问题&#xff0c;skype托盘图标显示_瑞波支付_新浪博客 Ubuntu 14.04 取消了系统托盘白名单机制&#xff0c;导致使用传统系统托盘技术的程序无法显示出托盘图标,dconf-editor也无力解决这个问题 。Ubuntu Unity桌面目前使用的技术是indicator-applica…

以太坊去中心化_开发以太坊去中心化投票应用程序的指南

以太坊去中心化by Timothy Ko蒂莫西高(Timothy Ko) 开发以太坊去中心化投票应用程序的指南 (A guide to developing an Ethereum decentralized voting application) After the entire cryptocurrency market passed 700 billion dollars in market cap, the cryptocurrency s…

Intellij IDEA的下载和使用(针对学生的免费使用计划)

一、下载和使用授权&#xff08;针对学生&#xff09; 1、下载 可以在Intellij IDEA官网上下载需要的版本。下载地址&#xff1a;https://www.jetbrains.com/idea/ 2、学生免费试用 首先&#xff0c;你得现有你们学校的官方邮箱账户&#xff0c;例如XXXYYY.edu.cn 其次&#xf…

LPC1768基本输入输出GPIO使用

LPC1788通用IO口的控制包含了一些基本的组件,比如设置推挽输出,开漏输出,上拉电阻等,我们今天来看看. 首先使用GPIO要打开GPIO的系统时钟 LPC_SC->PCONP | (1<<15);//gpio 时钟 然后需要选择我们选定引脚的功能,有些引脚有多个功能,通过寄存器可以从中选择一个 之后是…

微信小程序发红包功能实现,附效果图加讲解。

微信小程序开发交流qq群 173683895 承接微信小程序开发。扫码加微信。 需要做红包功能的可以找我&#xff0c;收费卖源码&#xff0c;也承接开发。此博文仅示例。 流程效果图&#xff1a; 图片1触发wx.sendBizRedPacket({})吊起图片2&#xff0c;点击开&#xff0c;出现图…

项目部署时网关怎么回事_使用Kubernetes部署聊天网关(或技术按预期运行时)...

项目部署时网关怎么回事by Richard Li理查德李(Richard Li) 使用Kubernetes部署聊天网关(或技术按预期运行时) (Using Kubernetes to deploy a chat gateway (or when technology works like it’s supposed to)) TL; DR (TL;DR) This is a story about what happens when clo…

如何用php实现分页效果

分页效果在网页中是常见的&#xff0c;可是怎样才能实现分页呢&#xff0c;今天做了两种方法来实现一下分页的效果 首先&#xff0c;我们需要准备在数据库里面准备一个表&#xff0c;并且插入数据&#xff0c;这些都是必需的前提工作了&#xff0c;不多说&#xff0c;如图所示&…

微信小程序在showToast中换行并且隐藏icon

微信小程序开发交流qq群 173683895 承接微信小程序开发。扫码加微信。 正文&#xff1a; 实现代码&#xff1a; 注释&#xff1a;真机才有效果&#xff0c;开发工具展示icon属性无效 var a 11\r\n3wx.showToast({title: a,icon:none,duration: 5000})

node aws 内存溢出_如何使用Node.js和AWS快速创建无服务器RESTful API

node aws 内存溢出by Mark Hopson马克霍普森(Mark Hopson) 如何使用Node.js和AWS快速创建无服务器RESTful API (How to quickly create a serverless RESTful API with Node.js and AWS) In this beginner’s guide, we’ll briefly describe the “Serverless” software arc…

java学习之匿名内部类与包装类

匿名内部类&#xff1a; 所谓匿名内部类&#xff0c;顾名思义指的就是定义在类内部的匿名类&#xff0c;现有的spring框架开发以及java图形界面都经常用到匿名内部类。 下面来看一个代码&#xff1a; interface A{public void fun() ; } class B implements A{public void fun(…

【微信小程序】登录功能实现及讲解(获取用户唯一标识)

微信小程序开发交流qq群 173683895 承接微信小程序开发。扫码加微信。 正文&#xff1a; 功能&#xff1a;登录实现并获取到用户唯一标识 官方文档地址&#xff1a;可以先看完我的文章再看官方地址 实现步骤&#xff1a;1.调用微信API wx.login()得到code 2.把得到的cod…

参考框架 系统 基准_带有基准的前端框架的真实比较(2018更新)

参考框架 系统 基准by Jacek Schae由Jacek Schae 带有基准的前端框架的真实比较(2018更新) (A Real-World Comparison of Front-End Frameworks with Benchmarks (2018 update)) This article is a refresh of A Real-World Comparison of Front-End Frameworks with Benchmar…

U盘重装MacOS-Sierra系统

Mac系统重新安装两种方法&#xff1a; 1、在线远程重装。 2、制作启动U盘进行重装。 理论上第一种比较简单&#xff0c;但是会比较耗时&#xff0c;实际操作中&#xff0c;由于网上下载的系统版本低于我现在MacOS的版本&#xff0c;导致无法安装&#xff0c;因此只能使用第二种…

this和that的区别和原理

微信小程序开发交流qq群 173683895 承接微信小程序开发。扫码加微信。 正文&#xff1a; 本篇博文纯属个人见解&#xff0c;如有不妥&#xff0c;可以留言批评指正&#xff0c;谢谢。 var that this; this指的是当前的对象。 that是一个临时的变量&#xff0c;用于保存当…

linu逻辑分区动态调整大小

linu逻辑分区动态调整大小 注意&#xff1a; 这个动态调整的方法是有丢数据风险的&#xff0c;要确保调整的源分区没有使用或者使用率很低。源分区中如果有重要的文件最好先备份在centos 6.5上操作过lvdisplay 查看已有的分区的大小 lvdisplay ,选择要操作的逻辑分区&#…

多个敏捷团队同时做一个项目_您说您的团队很敏捷……但是这个词可能并不代表您的想法。...

多个敏捷团队同时做一个项目by Mark Shead由马克希德(Mark Shead) Many things get called Agile — especially by people who are selling something. But the Agile Manifesto makes it clear that it isn’t a methodology. It isn’t a specific way of doing software d…

Python IDLE theme

#转自 http://www.2cto.com/os/201507/418532.html #win10python3.5.2 #保护视力 .idlerc 目录下新建名为 config-highlight.cfg 文件&#xff0c;并加入如下内容 [tango] definition-foreground #fce94ferror-foreground #fa8072string-background #2e3436keyword-foregrou…

【转帖】SQLServer登录连接失败(error:40-无法打开到SQLServer的连接)的解决方案...

在与SQLServer建立连接时出现与网络相关的或特定与实例的错误.未找到或无法访问服务器.请验证实例名称是否正确并且SQL SERVER已配置允许远程链接.(provide:命名管道提供程序,error:40 -无法打开到SQL Server的连接)(Microsoft SQL Server,错误:2) 我刚刚在登录连接SQL Server …

js时间戳转换成日期格式

//时间戳转日期格式function timestampToTime(timestamp) {var date new Date(timestamp * 1000); //时间戳为10位需*1000&#xff0c;时间戳为13位的话不需乘1000Y date.getFullYear() -;M (date.getMonth() 1 < 10 ? 0 (date.getMonth() 1) : date.getMonth() 1)…

30岁找不到工作很绝望_计算机为绝望的新编码员工作方式的快速指南

30岁找不到工作很绝望by Danielle Ormshaw丹妮尔欧姆肖(Danielle Ormshaw) 计算机为绝望的新编码员工作方式的快速指南 (The quick guide to the way computers work for desperate new coders) The sole purpose of your computer is to send and receive information in the…

纯css3代码写下拉菜单效果

1 <!DOCTYPE html>2 <html lang"en">3 <head>4 <meta charset"UTF-8">5 <meta name"viewport" content"widthdevice-width,initial-scale1;user-scaleno">6 <title>CSS3树形菜单</title…

webpack chunkFilename 非入口文件的命名规则 [转]

官网的文档只理解了filename是主入口的文件名&#xff0c;chunkFilename是非主入口的文件名 filename应该比较好理解&#xff0c;就是对应于entry里面生成出来的文件名。比如&#xff1a; {entry: {"index": "pages/index.jsx"},output: {filename: "…