您的位置:首页 > 理论基础 > 计算机网络

http学习笔记(模拟http请求和响应过程)

2017-01-08 20:58 381 查看

HTTP请求消息

1、http请求报文格式解析:起始行+首部字段+主体

POST /api/feed/ HTTP/1.1 –起始行

Accept-Encoding: gzip –请求头

Content-Length: 225873

Content-Type: multipart/form-data; boundary=OCqxMF6-JxtxoMDHmoG5W5eY9MGRsTBp

Host: www.myhost.com

Connection: Keep-Alive

(以下请求正文)

–OCqxMF6-JxtxoMDHmoG5W5eY9MGRsTBp –分隔符

Content-Disposition: form-data; name=”lng” –参数

Content-Type: text/plain; charset=UTF-8 –(说明是文本)

Content-Transfer-Encoding: 8bit

–空行

116.361545 参数值

–OCqxMF6-JxtxoMDHmoG5W5eY9MGRsTBp

Content-Disposition: form-data; name=”lat”

Content-Type: text/plain; charset=UTF-8

Content-Transfer-Encoding: 8bit

39.979006

–OCqxMF6-JxtxoMDHmoG5W5eY9MGRsTBp

Content-Disposition: form-data; name=”images”; filename=”/storage/emulated/0/Camera/jdimage/1xh0e3yyfmpr2e35tdowbavrx.jpg”

Content-Type: application/octet-stream

Content-Transfer-Encoding: binary

这里是图片的二进制数据

–OCqxMF6-JxtxoMDHmoG5W5eY9MGRsTBp–

2、http响应报文格式解析

HTTP/1.1 200 OK

Date: Sun, 08 Jan 2017 08:24:23 GMT

Content-Type: text/html;charset=UTF-8

Content-Length: 908

resp{

errmsg=操作成功

errno=0

}

进入正题

1、模拟http服务器

package http;

import java.io.IOException;

import java.net.ServerSocket;

/**

* Created by 蓝师傅 on 2017/1/7.

*/

public class SimpleHttpServer extends Thread {

//端口号
public static final int HTTP_PORT = 8005;
ServerSocket mSocket = null;

public SimpleHttpServer(){
try {
mSocket = new ServerSocket(HTTP_PORT);
} catch (IOException e) {
throw new RuntimeException("服务器socket初始化失败");
}

}

@Override
public void run() {

//等待客户端连接
try {
while (true){

System.out.println("等待连接.....");
//这里会一直阻塞,知道有socket连接进来
//一旦客户端连接,拿到socket对象,交给DeliverThread 处理
new DeliverThread(mSocket.accept()).start();

}
} catch (Exception e) {
e.printStackTrace();
}
}


}

可以看到,SimpleHttpServer 是一个线程,run方法无限循环,被mSocket.accept() 阻塞,当有socket接入的时候会调用new DeliverThread(mSocket.accept()).start();,把请求交给DeliverThread 去处理,代码如下:

package http;

import java.io.BufferedReader;

import java.io.IOException;

import java.io.InputStreamReader;

import java.io.PrintStream;

import java.net.Socket;

import java.util.HashMap;

import java.util.Map;

/**

* Created by 蓝师傅 on 2017/1/7.

* 处理请求的线程

*/

public class DeliverThread extends Thread {

Socket mClientSocket;
//输入流
BufferedReader mInputStream;
//输出流
PrintStream mOutputStream;
//请求方法
String httpMethod;
//子路径
String subPath;
//分隔符
String boundary;
//请求参数
Map<String,String> mParams = new HashMap<String,String>();
//是否已经解析完header
boolean isParseHeader;

public DeliverThread(Socket socket){
mClientSocket = socket;
}
@Override
public void run() {

/**
* 处理请求
*/
try {
//获取输入流
mInputStream = new BufferedReader(new InputStreamReader(mClientSocket.getInputStream()));
//获取输出流
mOutputStream = new PrintStream(mClientSocket.getOutputStream());

//解析请求
parseRequest();
//返回response
handleResponse();

} catch (IOException e) {
e.printStackTrace();
}finally {
try {
mInputStream.close();
mOutputStream.close();
mClientSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}

}

/**
* 解析请求
*/
private void parseRequest() {
String line; //读一行数据

try {
int lineNum = 0;

while ((line = mInputStream.readLine())!= null){

//第一行是请求行
if(lineNum == 0){
parseRequestLine(line);
}
//是否是结束行
if(isEndLine(line)){
break;
}

//解析header参数
if(lineNum != 0 && !isParseHeader){
parseHeaders(line);
}

if(isParseHeader){
parseRequestParams(line);
}

lineNum ++;

}
} catch (Exception e) {
e.printStackTrace();
}

}

/**
* 解析请求正文参数
* @param line
*/
private void parseRequestParams(String line) throws IOException {
/**
*
-----------------------------7d77af5871cc4b             分隔符
Content-Disposition: form-data; name="last_server_md5"  参数名
空行
bdf244bde5deb41d0f24d5f2e13efcba                        参数值
-----------------------------7d77af5871cc4b
Content-Disposition: form-data; name="t"

Q=u%3D%25PQ%250df551a583a87f4e9%26src%3D360chrome%26t%3D1

-----------------------------7d77af5871cc4b--
空行结束
*/
if(line.equals("--"+boundary)){             // 分隔符开始
String key = mInputStream.readLine();   //参数名
mInputStream.readLine();                 //空行
String value = mInputStream.readLine();  //参数值
mParams.put(key,value);
System.out.println("解析参数,key="+key+",value="+value);

}

}

/**
* 解析请求头
* @param line
*/
private void parseHeaders(String line) {
//header以空行结束
if(line.equals("")){
//解析结束
isParseHeader = true;
System.out.println("解析到空行,解析header 结束》》》》");
return;
}else if(line.contains("boundary")){
boundary = parseSecondField(line);
System.out.println("解析到分隔符》》》》"+boundary);

}else{
//解析普通的header
parseHeaderParam(line);
}

}

/**
* 解析header参数
* @param line
*/
private void parseHeaderParam(String line) {
String[] keyValue = line.split(":");
mParams.put(keyValue[0].trim(),keyValue[1].trim());
System.out.println("解析header参数:key="+keyValue[0].trim()+",value = "+keyValue[1].trim());

}

/**
* 解析header 第二个参数,返回分隔符
* @param line
* @return
*/
private String parseSecondField(String line) {
//// TODO: 2017/1/8
//Content-Type: application/octet-stream
//Content-Type: application/octet-stream; boundary = abcdefg

String[] keyValue = line.split(";");
parseHeaderParam(keyValue[0]); // Content-Type: application/octet-stream
if(keyValue.length >1){
return  keyValue[1].split("=")[1];
}

return "";
}

/**
* 是否是结束行
* @param line
* @return
*/
private boolean isEndLine(String line) {
return line.equals("--"+boundary+"--");
}

/**
* 解析请求行
* @param line
*/
private void parseRequestLine(String line) {
// 请求方法 空行  url  空行  http版本 回车符,换行符
String[] tempString = line.split(" ");
httpMethod = tempString[0]; //
subPath = tempString[1]; //

System.out.println("请求方法:"+tempString[0]);
System.out.println("子路径:"+tempString[1]);
System.out.println("http版本:"+tempString[2]);

}

/**
* 响应:返回结果
*/
private void handleResponse() {

try {
sleep(1000);
mOutputStream.println("HTTP/1.1 200 OK");
mOutputStream.println("Content-Type: application.json");
mOut
4000
putStream.println("");
mOutputStream.println("{\"stCode\":\"success\"}");

} catch (InterruptedException e) {
e.printStackTrace();
}

}


}

然后呢,在main中调用 new SimpleHttpServer.start(); 即可启动服务器

看看客户端吧:

以post请求为例,客户端需要调用

HttpPost post = new HttpPost("127.0.0.1");
post.addParams("name", "lanshifu");
post.excute();
//发送post请求


HttpPost 的代码如下:

package http;

import java.io.BufferedReader;

import java.io.IOException;

import java.io.InputStreamReader;

import java.io.PrintStream;

import java.net.Socket;

import java.util.HashMap;

import java.util.Iterator;

import java.util.Map;

/**

* Created by 蓝师傅 on 2017/1/8.

*/

public class HttpPost {

String url = "127.0.0.1";
//请求参数
Map<String,String> mParams = new HashMap<String,String>();
Socket mSocket;

public HttpPost(String url) {
this.url = url;
}

public void addParams(String key,String value){
mParams.put(key,value);
}

public void excute(){
try {
mSocket = new Socket(this.url,SimpleHttpServer.HTTP_PORT);
PrintStream outPutStream = new PrintStream(mSocket.getOutputStream());
BufferedReader inputStream = new BufferedReader(new InputStreamReader(mSocket.getInputStream()));

String boundray ="分割符";

writeHeader(boundray,outPutStream);

writeParams(boundray,outPutStream);

waitResponse(inputStream);

} catch (IOException e) {
e.printStackTrace();
//创建连接失败
}

}

/**
* 构造header
* @param boundray
* @param outPutStream
*/
private void writeHeader(String boundray, PrintStream outPutStream) {
outPutStream.println("POST /pro1/empManage1.0/login.php HTTP/1.1");
outPutStream.println("Accept-Encoding: gzip, deflate, sdch");
outPutStream.println("Accept-Language: zh-CN,zh;q=0.8");
outPutStream.println("Content-Type: application/octet-stream; boundray="+boundray);
outPutStream.println();
}

/**
* 构造请求正文参数
* @param boundray
* @param outPutStream
*/
private void writeParams(String boundray, PrintStream outPutStream) {
System.out.println("writeParams调用》》》");

Iterator<String> iterator = mParams.keySet().iterator();
while (iterator.hasNext()){
String paramName = iterator.next();

outPutStream.println("--"+boundray);
outPutStream.println("Content-Dusposition:from-data; name="+paramName);
outPutStream.println();
outPutStream.println(mParams.get(paramName));

System.out.println("writeParams,paramName=:"+mParams.get(paramName));

}

//结束符
outPutStream.println("--"+boundray+"--");
System.out.println("writeParams调用结束》》》");

}

/**
* 等待响应
* @param inputStream
*/
private void waitResponse(BufferedReader inputStream) {
System.out.println("waitResponse调用结束》》》");

}


}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java http