专业网站建设提供商北京商场购物中心排名
news/
2025/9/23 1:16:50/
文章来源:
专业网站建设提供商,北京商场购物中心排名,各网站的网络联盟,购物商城网站开发实验报告解读HTTP包#xff1a;[摘要]详细介绍HTTP包的格式、协议内容及相关的处理方法#xff0c;内容分3节#xff1a;1、超文本传输协议及HTTP包;2、Socket类与ServerSocket类;3、读取HTTP包。 一、超文本传输协议及HTTP包 HTTP协议用于在Internet上发送和接收消息。HTTP协议是一… 解读HTTP包[摘要]详细介绍HTTP包的格式、协议内容及相关的处理方法内容分3节1、超文本传输协议及HTTP包;2、Socket类与ServerSocket类;3、读取HTTP包。 一、超文本传输协议及HTTP包 HTTP协议用于在Internet上发送和接收消息。HTTP协议是一种请求-应答式的协议——客户端发送一个请求服务器返回该请求的应答所有的请求与应答都是HTTP包。HTTP协议使用可靠的TCP连接默认端口是80。HTTP的第一个版本是HTTP/0.9后来发展到了HTTP/1.0现在最新的版本是HTTP/1.1。HTTP/1.1由RFC 2616 定义。 在HTTP中Client/Server之间的会话总是由客户端通过建立连接和发送HTTP请求包初始化服务器不会主动联系客户端或要求与客户端建立连接。浏览器和服务器都可以随时中断连接例如在浏览网页时你可以随时点击停止按钮中断当前的文件下载过程关闭与Web服务器的HTTP连接。 1 HTTP请求包 HTTP请求包(GET、POST等请求方法)由三个部分构成分别是方法-URI-协议/版本请求头请求正文。下面是一个HTTP请求包(GET)的例子 GET /index.jsp HTTP/1.1 Accept-Language: zh-cn Connection: Keep-Alive Host: 192.168.0.106 Content-Length: 37 userNamenew_andypasswordnew_andy 请求包的第一行是方法-URI-协议/版本 GET就是请求方法根据HTTP标准HTTP请求可以使用多种请求方法。HTTP 1.1支持七种请求方法GET、POST、HEAD、OPTIONS、PUT、delete和TRACE等常用的为请求方法是GET和POST。 /index.jsp 表示URI。URI指定了要访问的网络资源。 HTTP/1.1是协议和协议的版本。 最后一行userNamenew_andy amp;passwordnew_andy为正文正文与HTTP头部有一个空行(\r\n)分隔。这里需要说明的一点其中Content- Length说明正文的长度有的正文长度没有在头部说明只是标明Transfer-Encoding: chunked。关于chunked类型的长度计算方法见RFC 1626。 请求包的头部还会包含许多有关客户端环境和请求正文的有用信息这里不再描述。 2 HTTP应答包 和HTTP请求包相似由三个部分构成分别是协议-状态代码-描述应答头应答正文。下面是一个HTTP应答的例子 HTTP/1.1 200 OK Server: Microsoft-IIS/4.0 Date: Mon, 3 Jan 2005 13:13:33 GMT Content-Type: text/html Last-Modified: Mon, 11 Jan 2004 13:23:42 GMT Content-Length: 90 html head title 解读HTTP包示例/title/headbody Hello WORLD! /body /html HTTP应答包的第一行类似于HTTP请求的第一行表示所用的协议是HTTP 1.1服务器处理请求的状态码200。 应答头也和请求头一样包含许多有用的信息例如服务器类型、日期时间、内容类型和长度等。应答的正文就是服务器返回的HTML页面。应答头和正文之间也用 CRLF分隔。 二、Socket类与ServerSocket类 在Java中通信端点由java.net.Socket类(客户端)或java.net.ServerSocket类(服务器端)表示。应用程序通过端点向网络发送或从网络读取数据。位于两台不同机器上的应用软件通过网络连接发送和接收字节流从而实现通信。要把HTTP包发送给另一个应用首先要知道对方的IP地址以及其通信端点的端口号。 Socket类代表的是客户端它是一个连接远程服务器应用时临时创建的端点。 ServerSocker类代表的是服务器端它启动后等待来自客户端的连接请求一旦接收到请求ServerSocket创建一个Socket实例来处理与该客户端的通信。对于服务器应用我们不知道客户端应用什么时候会试图连接服务器服务器必须一直处于等待连接的状态。 下面是ServerSocket提供了四个构造函数常用的构造函数的的一种形式为 public ServerSocket(int port, int backLog, InetAddress bindingAddress); 参数port指定服务器端监听客户端的端口 backlog为连接请求的最大队列长度一旦超越这个长度服务器端点开始拒绝客户端的连接请求。 bindingAddress是一个java.net.InetAddress的实例指定绑定IP地址。 创建好 ServerSocket实例之后调用它的accept方法要求它等待传入的连接请求。只有出现了连接请求时accept方法才会返回它的返回值是一个Socket类的实例。随后这个Socket对象就可以用来与客户端应用通信。 Socket类有许多构造函数常用的为 public Socket(String host, int port)。 参数是主机名称(IP地址或域名)和端口号。 参数host是远程机器的名字或IP地址port是远程应用的端口号。 成功创建了Socket类的实例之后我们就可以用它来发送和接收字节流形式的数据数据一般为HTTP包。 要发送字节流首先要调用 Socket类的getOutputStream方法获得一个java.io.OutputStream对象要从连接的另一端接收字节流首先要调用 Socket类的getInputStream方法获得一个java.io.InputStream对象。 下面的代码片断创建一个与本地HTTP服务器127.0.0.1代表本地主机的IP地址通信的Socket发送一个HTTP请求包准备接收服务器的应答。 Socket socket new Socket(127.0.0.1, 80); OutputStream os socket.getOutputStream(); InputStream ins socket.getInputStream(); StringBuffer sbnew StringBuffer(); sb.append(GET /index.jsp HTTP/1.1\r\n);//注意\r\n为回车换行 sb.append(Accept-Language: zh-cn\r\n); sb.append(Connection: Keep-Alive\r\n); sb.append(Host: 192.168.0.106\r\n); sb.append(Content-Length: 37\r\n); sb.append(\r\n); sb.append(userNamenew_andypasswordnew_andy\r\n); sb.append(\r\n); // 向Web服务器发送一个HTTP请求包 os.write(sb.toString().getBytes()); 服务器端的代码在大致结构为 while (!shutdown) { Socket socket null; try { socket serverSocket.accept(); //等待客户以送HTTP请求包 // 创建HTTP请求包处理线程 RequestThread request new RequestThread(socket); request.start(); if(shutdown) System.exit(0); } catch (Exception e) { e.printStackTrace(); } } RequestThread线程分析HTTP请求包跟根据请求包内容在服务端生成一个HTTP应答包。下一节说明怎样分析 HTTP包。 InputStream input socket.getInputStream(); //从此字节数据流获得HTTP请求包内容 OutputStream output socket.getOutputStream(); //向此字节流写入HTTP应答包内容 三、读取HTTP包 以下是一个读取HTTP包的类 SocketRequest。 public class SocketRequest { //从指定的Socket的InputStream中读取数据 private InputStream input; private String uri; private StringBuffer request new StringBuffer(); //用于保存所有内容 private int CONTENT_LENGTH 0; //实际包内容数据长 private boolean bePost false; private boolean beHttpResponse false; private boolean beChucked false; private boolean beGet false; private byte crlf13 (byte) 13; //\r private byte crlf10 (byte) 10; //\n public SocketRequest(InputStream input) { this.input input; } public SocketRequest(Socket socket) { this.input socket.getInputStream(); } public void ReadData() { //解析 获得InputStream的数据 ReadHeader(); //头部 if (beChucked) { //为Chucked int ChuckSize 0; while ((ChuckSize getChuckSize()) 0) { //多个Chucked readLenData(ChuckSize 2); //读取定长数据 } readLenData(2); //最后的2位 } if (CONTENT_LENGTH 0) { readLenData(CONTENT_LENGTH); //读取定长数据 } uri ; //parseUri(new String(request)); } private void readLenData(int size) { //读取定长数据 int readed 0; //已经读取数 try { int available 0; //input.available(); //可读数 if (available (size - readed)) { available size - readed; } while (readed size) { while (available 0) { //等到有数据可读 available input.available(); //可读数 } if (available (size - readed)) { available size - readed; //size-readed--剩余数 } if (available 2048) { available 2048; //size-readed--剩余数 } byte[] buffer new byte[available]; int reading input.read(buffer); request request.append(new String(buffer, 0, reading)); //byte数组相加 readed reading; //已读字符 } } catch (IOException e) { System.out.println(Read readLenData Error!); } } private void ReadHeader() { //读取头部 并获得大小 byte[] crlf new byte[1]; int crlfNum 0; //已经连接的回车换行数 crlfNum4为头部结束 try { while (input.read(crlf) ! -1) { //读取头部 if (crlf[0] crlf13 || crlf[0] crlf10) { crlfNum; } else { crlfNum 0; } //不是则清 request request.append(new String(crlf, 0, 1)); //byte数组相加 if (crlfNum 4) { break; } } } catch (IOException e) { System.out.println(Read Http Header Error!); return; } String tempStr (new String(request)).toUpperCase(); //这里我只处理了GET与POST方法 String strMethod tempStr.substring(0, 4); if (strMethod.equals(GET )) { //前 beGet true; } else if (strMethod.equals(POST)) { bePost true; getContentlen_Chucked(tempStr); } else { System.out.println( 不支持的HTTP包类型); } //其它的其它类型 暂不支持 } private void getContentlen_Chucked(String tempStr) { //获得长度 CONTENT-LENGTH 或 是否为CHUNKED型 String ss1 CONTENT-LENGTH:; String ss2 new String(TRANSFER-ENCODING: CHUNKED); int clIndex tempStr.indexOf(ss1); int chuckIndex tempStr.indexOf(ss2); //为CHUNKED型 byte requst[] tempStr.getBytes(); if (clIndex ! -1) { //从clIndex1起至\r\n StringBuffer sb new StringBuffer(); for (int i (clIndex 16); ; i) { if (requst[i] ! (byte) 13 requst[i] ! (byte) 10) { sb.append((char) requst[i]); } else { break; } } CONTENT_LENGTH Integer.parseInt(sb.toString()); //正式的HTML文件的大小 //System.out.println(CONTENT_LENGTH CONTENT_LENGTH); } if (chuckIndex ! -1) { beChucked true; } } private int getChuckSize() { //Chuck大小 byte[] crlf new byte[1]; StringBuffer sb1 new StringBuffer(); int crlfNum 0; //已经连接的回车换行数 crlfNum4为头部结束 try { while (input.read(crlf) ! -1) { //读取头部 if (crlf[0] crlf13 || crlf[0] crlf10) { crlfNum; } else { crlfNum 0; } //不是则清 sb1.append((char) crlf[0]); request request.append(new String(crlf, 0, 1)); //byte数组相加 if (crlfNum 2) { break; } } } catch (IOException e) { System.out.println(Read Http Package Error!); return 0; } return Integer.parseInt((sb1.toString()).trim(), 16); //16进控制 } //通过此来进行过滤是否为发至目标服务器的HTTP包 private String parseUri(String requestString) { int index1, index2; index1 requestString.indexOf( ); if (index1 ! -1) { index2 requestString.indexOf( , index1 1); if (index2 index1) { return requestString.substring(index1 1, index2); } } return null; } public String getData() { return request.toString(); } } 使用此类: SocketRequest request new SocketRequest(socket); //socket为ServerSocket.accept()返回的Socket实例 request.ReadData(); //读取数据 request.getData(); 为什么我要用这么大的力量去读取呢尤其是在因为Socket连接在发送数据时由于网络的原因经常会发生延迟现象可能在服务器端开始接收数据时可能只有部分数据可以从InputStream中获得在一些地方处理不当时可能只能获得不完整的数据或是错误的数据。 从 InputStream读取字节时有多种办法: 常用int read()与int read(byte[] b)。在用read(byte[])时程序员经常会犯错误因为在网络环境中读取的数据量不一定等于参数的大小。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/910975.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!