手写服务器(二)

2 篇文章 0 订阅
2 篇文章 0 订阅

上一次我们分装了respon端,这次,我们要分析一下客户端的请求,提取一些有用的信息。比如,在客户端输入姓名,这个姓名的信息就存在HTTP协议的request端,我们如果想在服务器端增加一个功能:欢迎某某,这样就必须要分析request端的协议。

首先,我们写一个简单的HTML页面。新建一个文本文件,将后缀改成HTML,之后用Notepad打开,编辑

<html>
	<head>
		<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
		<title>欢迎来到LPL全明星投票</title>
		GET / HTTP/1.1
		Host: localhost:7777
		User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:63.0) Gecko/20100101 Firefox/63.0
		Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
		Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
		Accept-Encoding: gzip, deflate
		Connection: keep-alive
		pgrade-Insecure-Requests: 1
		
	</head>
	<body>
		<pre>
		method :请求方式 get/post
		action:请求的服务器路径
		</pre>
		<form method="get" action ="http://localhost:7777/index.html">
		姓名ID:<input type ="text" name="uname" id="name"/>
		Password:<input type="password" name="uname" id="name"/>
		<input type="submit" value="登陆"/><br/>
		EDG ClearLove:<input type="checkbox" name="fav" value="0"/>打野<br/>
		RNG MLXG:<input type="checkbox" name="fav" value="1"/>打野<br/>
		RNG UZI:<input type="checkbox" name="fav" value="2"/>ADC<br/>
		IG Rookie:<input type="checkbox" name="fav" value="3"/>中单<br/>
		THE SHY:<input type="checkbox" name="fav" value="4"/>上单<br/>
		</form>
		<p>段落</p>
	</body>
</html>

这是一个非常简单的HTML页面,

HTML不具体深究,这里只需要记住HTML的关键字是成对出现的,然后具体的用法可以去百度或者查书。这里只是举例。

可以看到具体协议是:GET /index.html?uname=jianghe&uname=123456 HTTP/1.1
Host: localhost:7777
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:63.0) Gecko/20100101 Firefox/63.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: keep-alive
Upgrade-Insecure-Requests: 1

get和post的区别在上一篇的博客中讲解过。

package MyServer02;

import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 * 特别说明 请求应该是request
 * 我拼写错了
 * 妈的
 * 
 *
 * 请求方式:get post
 * 请求url
 * 请求的参数
 * @author jh
 *
 */
public class Requst {
	//请求方式
	private String method;
	//请求资源
	private String url;
	//请求参数
	private Map<String,List<String>> parameterMapValues;
	//Accept-Encoding: gzip, deflate 一个请求的参数可能对应多个选项
	//内部
	public static final String CRLF="\r\n";
	private InputStream is;
	private String requestInfo;//public方便全局进行访问
	public Requst() {
		url="";
		method="";
		parameterMapValues=new HashMap<String,List<String>>();
		requestInfo="";
	}
	public Requst(String Info) {
		this();
		requestInfo=Info;
	}
	public Requst(Socket client) throws IOException{
		this(client.getInputStream());
	}
	public Requst(InputStream iStream) {
		 this();
		 this.is=iStream;
		 try {
			 byte[] data=new byte[20480];
			 int len=iStream.read(data);
			 if(len==-1) {
				 len=1;
			 }
			 requestInfo=new String(data, 0, len);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			return ;
		}
		//分析请求信息
		parseRequestInfo();//在构造器中调用函数,这里非常重要
	}
	//parse从语法上描述或分析(词句等)
	//params参数
	//
	public void parseRequestInfo() {
		if (requestInfo==null||requestInfo.equals("")) {
			System.out.print("nothing");
			return ;
		}
	
		String paramString ="";
		//获取请求方式
		String firstLine=requestInfo.substring(0,requestInfo.indexOf(CRLF));
		firstLine.trim();
		this.method=firstLine.substring(0,firstLine.indexOf("/")).trim();
		String strUrl=firstLine.substring(firstLine.indexOf("/"),firstLine.indexOf("HTTP"));
		if(this.method.equalsIgnoreCase("post")) {//忽略大小写,get 和post的区别就在于是否含有参数
			this.url=strUrl;
		}else if (this.method.equalsIgnoreCase("get")) {
			if(strUrl.contains("?")) {
				String[] strarray=strUrl.split("\\?");
				this.url=strarray[0];
				paramString=strarray[1];
			}else {
				this.url=strUrl;
			}
		}
		if(paramString.equals("")) {
			return ;
		}else {
			parseParams(paramString);
		}
		
	}
	//GET /index.html?uname=jianghe&uname=123456&fav=0&fav=1&fav=2 HTTP/1.1//这里面有参数
	//uname=jianghe&uname=123456&fav=0&fav=1&fav=2
	public void parseParams(String paramsString) {
		String paramsarr[]=paramsString.split("&");
		for(String temp:paramsarr) {
			String mapparams[]=temp.split("=");
			if(mapparams.length==1) {
				//这里是属于第二种情况,需要进行扩容,方便以后共同处理
				mapparams=Arrays.copyOf(mapparams, 2);
				mapparams[1]=null;
			}
			String key=mapparams[0].trim();
			String values= (null==mapparams[1])?null:mapparams[1];
			//String values= null==mapparams[1]?null:mapparams[1];
			if(!parameterMapValues.containsKey(key)) {
				parameterMapValues.put(key, new ArrayList<String>());
				
			}
			List<String> values_arr=parameterMapValues.get(key);
			values_arr.add(values);
			
		}
	}
	
	public String[] getParameterarray(String name) {
		List<String> valuesarr=null;
		if((valuesarr=parameterMapValues.get(name))==null) {
			return null;
		}else {
			return valuesarr.toArray(new String[0]);//这里是转型之后的数组类型
		}
	}
	public String getParameter(String name) {//只返回第一个元素
		String[] valuesarray=getParameterarray(name);
		if(valuesarray==null) {
			return null;
		}else {
			return valuesarray[0];
		}
	}
	public void println() {
		System.out.println("Hello");
		for(String key:parameterMapValues.keySet()) {
			List<String> values=parameterMapValues.get(key);
			System.out.print(key+" ");
			for(String value:values) {
				System.out.println(value);
			}
		}
	}
	public String getMethod() {
		return method;
	}
	public String getUrl() {
		return url;
	}
	/*public static void main(String[] args) {
		String info="GET /index.html?uname=jianghe&uname=123456 HTTP/1.1\r\n" + 
				"Host: localhost:7777\r\n" + 
				"User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:63.0) Gecko/20100101 Firefox/63.0\r\n" + 
				"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*;q=0.8\r\n" + */
				/*"Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2\r\n" + 
				"Accept-Encoding: gzip, deflate\r\n" + 
				"Connection: keep-alive\r\n" + 
				"Upgrade-Insecure-Requests: 1";
		Requst requst=new Requst(info);//基本定位到是参数的map中没有参数
		requst.getParameter("uname");
		requst.println();
	}*/
}

分装完成,主要说明一下一个参数的请求可能对应多个选项,所以使用map<string,list<string>>进行封装。另外构造器中调用分析头信息的函数。

另外针对这个封装,改写服务器端的代码;

package MyServer02;

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;


public class Server01 {
	private ServerSocket serverSocket=null;
	
	public static void main(String[] args) {
		Server01 server01=new Server01();
		server01.start();
		server01.stop();
	}
	public void start() {
		try {
			serverSocket=new ServerSocket(7777);
			this.receive();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
	public void receive() {
		try {
			Socket client=serverSocket.accept();
			/*String meg=null;
			StringBuilder sbBuilder=new StringBuilder();
			BufferedReader bReader=new BufferedReader(new InputStreamReader(client.getInputStream()));
			while((meg=bReader.readLine()).length()>0) {
				sbBuilder.append(meg);
				sbBuilder.append("\r\n");
				if(meg==null) {
					break;
				}
			}
			String re=sbBuilder.toString().trim();
			
			System.out.println(re);
			CloseUtil.CloseAll(bReader);*/
			Response response=new Response(client);
			//response.show();
			Requst requst=new Requst(client.getInputStream());
			//Request requst=new Request(client.getInputStream());
			response.println("<html> <head><title>HTTP响应示例</title>");
			response.println("</head><body>");
			response.println("欢迎").println(requst.getParameter("uname")).println("归来");
			response.println("</body></html>");
			//requst.println();
			response.pushtoclient(200);//此处还有错误,就是状态代码不起任何作用
			//response.pushtoclient(404);*/
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			
		}
		
	}
	public void stop() {
		
	}

}

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值