Java Socket发送与接收HTTP消息简单实现
在上次Java Socket现实简单的HTTP服务我 们实现了简单的HTTP服务,它可以用来模拟HTTP服务,用它可以截获HTTP请求的原始码流,让我们很清楚的了解到我们向服务发的HTTP消息的结 构,对HTTP请求消息有个清晰的认识。这一节我想写了一个客户的程序,就是用来模拟浏览器,用来向服务器发送HTTP请求,最得要的是可以用它来显示服 务器发回来的HTTP响应消息的一般结构。
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.OutputStreamWriter;
- import java.net.InetAddress;
- import java.net.Socket;
- import java.net.UnknownHostException;
- import java.util.ArrayList;
- /**
- * 一个简单的HTTP客户端,发送HTTP请求,模拟浏览器
- * 可打印服务器发送过来的HTTP消息
- */
- public class SimpleHttpClient {
- private static String encoding = "GBK";
- public static void main(String[] args) {
- try {
- Socket s = new Socket(InetAddress.getLocalHost(), 8080);
- OutputStreamWriter osw = new OutputStreamWriter(s.getOutputStream());
- StringBuffer sb = new StringBuffer();
- sb.append("GET /HttpStream/gb2312.jsp HTTP/1.1\r\n");
- sb.append("Host: localhost:8088\r\n");
- sb.append("Connection: Keep-Alive\r\n");
- //注,这是关键的关键,忘了这里让我搞了半个小时。这里一定要一个回车换行,表示消息头完,不然服务器会等待
- sb.append("\r\n");
- osw.write(sb.toString());
- osw.flush();
- //--输出服务器传回的消息的头信息
- InputStream is = s.getInputStream();
- String line = null;
- int contentLength = 0;//服务器发送回来的消息长度
- // 读取所有服务器发送过来的请求参数头部信息
- do {
- line = readLine(is, 0);
- //如果有Content-Length消息头时取出
- if (line.startsWith("Content-Length")) {
- contentLength = Integer.parseInt(line.split(":")[1].trim());
- }
- //打印请求部信息
- System.out.print(line);
- //如果遇到了一个单独的回车换行,则表示请求头结束
- } while (!line.equals("\r\n"));
- //--输消息的体
- System.out.print(readLine(is, contentLength));
- //关闭流
- is.close();
- } catch (UnknownHostException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- /*
- * 这里我们自己模拟读取一行,因为如果使用API中的BufferedReader时,它是读取到一个回车换行后
- * 才返回,否则如果没有读取,则一直阻塞,直接服务器超时自动关闭为止,如果此时还使用BufferedReader
- * 来读时,因为读到最后一行时,最后一行后不会有回车换行符,所以就会等待。如果使用服务器发送回来的
- * 消息头里的Content-Length来截取消息体,这样就不会阻塞
- *
- * contentLe 参数 如果为0时,表示读头,读时我们还是一行一行的返回;如果不为0,表示读消息体,
- * 时我们根据消息体的长度来读完消息体后,客户端自动关闭流,这样不用先到服务器超时来关闭。
- */
- private static String readLine(InputStream is, int contentLe) throws IOException {
- ArrayList lineByteList = new ArrayList();
- byte readByte;
- int total = 0;
- if (contentLe != 0) {
- do {
- readByte = (byte) is.read();
- lineByteList.add(Byte.valueOf(readByte));
- total++;
- } while (total < contentLe);//消息体读还未读完
- } else {
- do {
- readByte = (byte) is.read();
- lineByteList.add(Byte.valueOf(readByte));
- } while (readByte != 10);
- }
- byte[] tmpByteArr = new byte[lineByteList.size()];
- for (int i = 0; i < lineByteList.size(); i++) {
- tmpByteArr[i] = ((Byte) lineByteList.get(i)).byteValue();
- }
- lineByteList.clear();
- return new String(tmpByteArr, encoding);
- }
- }
运行时访问一个页面打印如下:
HTTP/1.1 200 OK <html> |
下面来个文件下载的看怎么样?
请求的Jsp页面如下:
- <%@page import="java.io.InputStream" contentType="text/html; charset=GB2312"%>
- <%@page import="java.io.FileInputStream"%>
- <%@page import="java.io.OutputStream"%><html>
- <body> <br>
- <%
- try {
- InputStream is = new FileInputStream("e:/tmp/file2.txt");
- OutputStream os = response.getOutputStream();
- byte[] readContent = new byte[1024];
- int readCount = 0;
- while (is.available() > 0) {
- readCount = is.read(readContent);
- os.write(readContent, 0, readCount);
- }
- is.close();
- //注这里一定要关闭,不然的话抛异常,异常请见下面,原因就是response.getWriter()
- //与response.getOutputStream()不能同时使用,如果在这里关闭了,前面与后面向
- //out对象里写的数据就不会刷新到客户端了,只有向response.getOutputStream()写的
- //数据会输出到客户端。
- os.close();
- } catch (Exception e) {
- e.printStackTrace();
- }
- %>
- </body>
- </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类文件:
- package org.apache.jsp;
- import javax.servlet.*;
- import javax.servlet.http.*;
- import javax.servlet.jsp.*;
- import java.io.InputStream;
- import java.io.FileInputStream;
- import java.io.OutputStream;
- public final class gb2312_jsp extends org.apache.jasper.runtime.HttpJspBase
- implements org.apache.jasper.runtime.JspSourceDependent {
- private static java.util.List _jspx_dependants;
- public Object getDependants() {
- return _jspx_dependants;
- }
- public void _jspService(HttpServletRequest request, HttpServletResponse response)
- throws java.io.IOException, ServletException {
- JspFactory _jspxFactory = null;
- PageContext pageContext = null;
- HttpSession session = null;
- ServletContext application = null;
- ServletConfig config = null;
- JspWriter out = null;
- Object page = this;
- JspWriter _jspx_out = null;
- PageContext _jspx_page_context = null;
- try {
- _jspxFactory = JspFactory.getDefaultFactory();
- response.setContentType("text/html; charset=GB2312");
- pageContext = _jspxFactory.getPageContext(this, request, response,
- null, true, 8192, true);
- _jspx_page_context = pageContext;
- application = pageContext.getServletContext();
- config = pageContext.getServletConfig();
- session = pageContext.getSession();
- out = pageContext.getOut();
- _jspx_out = out;
- out.write("\r\n");
- out.write("\r\n");
- out.write("\r\n");
- out.write("<html>\r\n");
- out.write("\t<body> <br>\r\n");
- out.write("\t\t");
- try {
- InputStream is = new FileInputStream("e:/tmp/file2.txt");
- OutputStream os = response.getOutputStream();
- byte[] readContent = new byte[1024];
- int readCount = 0;
- while (is.available() > 0) {
- readCount = is.read(readContent);
- os.write(readContent, 0, readCount);
- }
- is.close();
- //注这里一定要关闭,不然的话抛异常,异常请见下面,原因就是response.getWriter()
- //与response.getOutputStream()不能同时使用,如果在这里关闭了,前面与后面向
- //out对象里写的数据就不会刷新到客户端了,只有向response.getOutputStream()写的
- //数据会输出到客户端。
- os.close();
- } catch (Exception e) {
- e.printStackTrace();
- }
- out.write("\r\n");
- out.write("\t</body>\r\n");
- out.write("</html>");
- } catch (Throwable t) {
- if (!(t instanceof SkipPageException)){
- out = _jspx_out;
- if (out != null && out.getBufferSize() != 0)
- out.clearBuffer();
- if (_jspx_page_context != null) _jspx_page_context.handlePageException(t);
- }
- } finally {
- if (_jspxFactory != null) _jspxFactory.releasePageContext(_jspx_page_context);
- }
- }
- }
最后是服务向客户端输出的码流如下:
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消息简单实现的更多相关文章
- 2.技巧: 用 JAXM 发送和接收 SOAP 消息—Java API 使许多手工生成和发送消息方面必需的步骤自动化
转自:https://www.cnblogs.com/chenying99/archive/2013/05/23/3094128.html 技巧: 用 JAXM 发送和接收 SOAP 消息—Java ...
- (七)发送、接收SOAP消息(以HttpClient方式)(2)
一.为什么要用soap 原本我们使用web服务都是根据wsdl生成客户端(生成一堆java文件)然后再调用,本章节讲解如何用soap消息来替代这种方式. 二.SOAP消息格式 SOAP(简单对象访问协 ...
- java socket实现服务端,客户端简单网络通信。Chat
之前写的实现简单网络通信的代码,有一些严重bug.后面详细写. 根据上次的代码,主要增加了用户注册,登录页面,以及实现了实时显示当前在登录状态的人数.并解决一些上次未发现的bug.(主要功能代码参见之 ...
- (六)发送、接收SOAP消息(1)
一.为什么要用soap 原本我们使用web服务都是根据wsdl生成客户端(生成一堆java文件)然后再调用,本章节讲解如何用soap消息来替代这种方式. 二.SOAP消息格式 SOAP(简单对象访问协 ...
- Java邮件发送与接收原理
一. 邮件开发涉及到的一些基本概念 1.1.邮件服务器和电子邮箱 要在Internet上提供电子邮件功能,必须有专门的电子邮件服务器.例如现在Internet很多提供邮件服务的厂商:sina.sohu ...
- socket发送和接收数据
1)sendBuf(),sendText(),sendStream() 几乎所有的通信控件都会提供上面的3个方法.首先看看SendBuf(). function TCustomWinSocket.Se ...
- 如何使用C#和VB发送和接收MSMQ消息
在这篇博客中,我们将就如何实现System.Messaging类发送和接收的XML消息发送从MSMQ队列,你可能会遇到接收的XML消息的一些问题. 我们将首先加入参考System.Messaging ...
- XMPP系列(四)---发送和接收文字消息,获取历史消息功能
今天开始做到最主要的功能发送和接收消息.获取本地历史数据. 先上到目前为止的效果图: 首先是要在XMPPFramework.h中引入数据存储模块: //聊天记录模块的导入 # ...
- 解决Springboot整合ActiveMQ发送和接收topic消息的问题
环境搭建 1.创建maven项目(jar) 2.pom.xml添加依赖 <parent> <groupId>org.springframework.boot</group ...
随机推荐
- OpenCV人脸检测demo--facedetect
&1 问题来源 在运行官网的facedetect这个demo的时候,总是不会出来result的图形,电脑右下角提示的错误是“显示器驱动程序已停止响应,而且已恢复 windows 8(R)”. ...
- VBA的一些使用心得
VBA的知识比较零散,因此开一贴记录一下使用VBA时的一些方法和心得.主要针对Excel,参考在这里 1. Collection Class 大部分情况下,Collection Class是比数组(A ...
- Java Concurrency in Practice 读书笔记 第二章
第二章的思维导图(代码迟点补上):
- Android调用基于.net的WebService
在实际开发项目中,有时候会为Android开发团队提供一些接口,一般是以asmx文件的方式来承载.而公布出去的数据一般上都是标准的json数据.但是在实际过程中,发现Android团队那边并不是通过将 ...
- iOS——数据安全性问题小结
在移动互联网快速发展的今天,iOS应用直接运行在用户的手机上,与运行在服务器后台服务相比,更有可能被黑客攻击. a.网络安全: 1.1 安全地传输用户密码 事先生成一对用于加密的公私钥,客户端登录的时 ...
- Python数据可视化编程实战——导入数据
1.从csv文件导入数据 原理:with语句打开文件并绑定到对象f.不必担心在操作完资源后去关闭数据文件,with的上下文管理器会帮助处理.然后,csv.reader()方法返回reader对象,通过 ...
- HTML上传文件写法
来源于:http://www.cnblogs.com/SkySoot/p/3525139.html html 表单上传文件 一般处理程序由于没有 apsx 页面的整个模型和控件的创建周期,而比较有效率 ...
- 在VS2012中编译WinXP兼容的程序
VS2012默认是不兼容Windows XP的,编译链接出来的程序只能在Windows Vista及以上版本的操作系统上运行.可是有时需要在Windows XP上运行,又不得不用VS2012(例如用了 ...
- c#创建ISS站点
private void CreateWebSite() { try { string installPath = "C:\\Program Files\\MyWeb"; stri ...
- BZOJ-1925 地精部落 烧脑DP+滚动数组
1925: [Sdoi2010]地精部落 Time Limit: 10 Sec Memory Limit: 64 MB Submit: 1053 Solved: 633 [Submit][Status ...