Java Socket发送与接收HTTP消息简单实现
来源:互联网 发布:网络电视可以上网页吗 编辑:程序博客网 时间:2024/05/29 15:11
在上次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);
- }
- }
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
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页面如下:
- <%@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>
<%@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 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类文件:
- 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);
- }
- }
- }
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 ~!@#$%^&*()_+{}|:\" <>?`-=[]\\;',./
- Java Socket发送与接收HTTP消息简单实现
- Java Socket发送与接收HTTP消息简单实现
- Java Socket发送与接收HTTP消息简单实现
- Java Socket发送与接收HTTP消息简单实现
- Java Socket发送与接收HTTP消息简单实现
- Java socket模拟发送和接收HTTP消息
- socket实现http发送接收-<草稿>
- Udp同一个socket接收与发送实现
- AsyncSocket(简单的实现与服务器的发送消息,接收消息)
- java socket实现文件的发送接收
- Java实现Socket发送和接收文件
- java kafka消息的发送与接收
- java activeMQ消息的发送与接收
- socket 发送与接收
- java 实现http协议发送接收数据
- Java Socket编程 消息接收和发送类
- C# socket 发送接收消息与发送接收文件 群发文件
- 使用Socket发送接收HTTP请求(JAVA)
- Android开发实例大全
- Spring 自定义注解实现操作日志记录功能
- RKP-1001 和CRS-0215故障处理
- 用sip协议做的,是用的开源doubango 开发过视频通信软件
- platform_get_resource函数源码分析
- Java Socket发送与接收HTTP消息简单实现
- 离开.9月
- 仿百度和google的搜索提示
- hdu~4166~Robot Navigation
- 系统什么时候发送SIGKILL信号
- const char*, char const*, char*const的区别
- 远程桌面双屏
- 基于Gearman的PHP封装类
- 我看phD