用到的相关知识: 网络编程 多线程 字节流 反射等。。。
因为只是写服务器端 要遵循tcp协议
1.建立与浏览器的连接,获取请求协议
,
2.返回响应协议在客户端
public class Server02 {
private ServerSocket serverSocket;
public static void main(String[] args) {
Server02 server = new Server02();
server.start();
}
//启动服务
public void start() {
try {
serverSocket = new ServerSocket(8888);
receive();
} catch (IOException e) {
e.printStackTrace();
System.out.println("服务器启动失败 ");
}
}
//接受连接处理
public void receive() {
try {
Socket client = serverSocket.accept();
System.out.println("一个客户端建立了连接.. ");
//获取请求协议
InputStream is =client.getInputStream();
byte[] datas = new byte[1024*1024];
int len = is.read(datas);
String requestInfo = new String(datas,0,len);
System.out.println(requestInfo);
StringBuilder content = new StringBuilder();
content.append("<html>");
content.append("<head>");
content.append("<title>");
content.append("服务器响应成功");
content.append("</title>");
content.append("</head>");
content.append("<body>");
content.append("shsxt server终于回来了...");
content.append("</body>");
content.append("</html>");
int size =content.toString().getBytes().length;//必须获取字节长度
StringBuilder responseInfo =new StringBuilder();
String blank= " ";
String CRLF = "\r\n";
//返回
//1.响应状态行 HTTP/1.1 200 ok
responseInfo.append("HTTP/1.1").append(blank);
responseInfo.append(200).append(blank);
responseInfo.append("ok").append(CRLF);
//2.响应头(最后一行存在空行):
/**
*
*/
responseInfo.append("Date:").append(new Date()).append(CRLF);
responseInfo.append("Server:").append("shsxt Server/0.0.1;charset=GBK").append(CRLF);
responseInfo.append("Content-type:text/html").append(CRLF);
responseInfo.append("Content-length:size").append(size).append(CRLF);
responseInfo.append(CRLF);
//3. 正文
responseInfo.append(content.toString());
//写出到客户端
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(client.getOutputStream()));
bw.write(responseInfo.toString());
bw.flush();
} catch (IOException e) {
e.printStackTrace();
System.out.println("客户端错误");
}
}
//停止服务
public void stop() {
}
}
3.目标:封装响应信息
- 1.内容可以动态添加
- 2.关注状态码 拼接好相应的协议信息
- `package com.sxt.server;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.util.Date;
public class Response {
private BufferedWriter bw;
// 正文
private StringBuilder content;
// 协议头(状态行 请求头 回车)信息
private StringBuilder headInfo;
private int len;// 正文的字节数
private final String BLANK = " ";
private final String CRLF = "\r\n";
private Response() {
content = new StringBuilder();
headInfo = new StringBuilder();
len = 0;
}
public Response(Socket client) {
this();
try {
bw = new BufferedWriter(new OutputStreamWriter(client.getOutputStream()));
} catch (IOException e) {
e.printStackTrace();
headInfo=null;
}
}
public Response(OutputStream os) {
this();
bw = new BufferedWriter(new OutputStreamWriter(os));
}
// 动态添加内容
public Response print(String info) {
content.append(info);
len += info.getBytes().length;
return this;
}
// 动态添加内容
public Response println(String info) {
content.append(info).append(CRLF);
len += (info + CRLF).getBytes().length;
return this;
}
//推送响应信息
public void pushBrowser(int code) throws IOException {
if(null==headInfo) {
code= 505;
}
createHeadInfo(code);
bw.append(headInfo);
bw.append(content);
bw.flush();
}
// 构建头信息
private void createHeadInfo(int code) {
// 1.响应状态行 HTTP/1.1 200 ok
headInfo.append("HTTP/1.1").append(BLANK);
headInfo.append(code).append(BLANK);
switch (code) {
case 200:
headInfo.append("ok").append(CRLF);
break;
case 404:
headInfo.append("NOT FOUND").append(CRLF);
break;
case 500:
headInfo.append("SERVER ERROR").append(CRLF);
break;
}
// 2.响应头(最后一行存在空行):
headInfo.append("Date:").append(new Date()).append(CRLF);
headInfo.append("Server:").append("shsxt Server/0.0.1;charset=GBK").append(CRLF);
headInfo.append("Content-type:text/html").append(CRLF);
headInfo.append("Content-length:size").append(len).append(CRLF);
headInfo.append(CRLF);
}
}
`
package com.sxt.server;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Date;
import sun.misc.Cleaner;
/**
- 目标:封装响应信息
- 1.内容可以动态添加
- 2.关注状态码 拼接好相应的协议信息
- @author Administrator
*/
public class Server03 {
private ServerSocket serverSocket;
public static void main(String[] args) {
Server03 server = new Server03();
server.start();
}
//启动服务
public void start() {
try {
serverSocket = new ServerSocket(8888);
receive();
} catch (IOException e) {
e.printStackTrace();
System.out.println("服务器启动失败 ");
}
}
//接受连接处理
public void receive() {
try {
Socket client = serverSocket.accept();
System.out.println("一个客户端建立了连接.. ");
//获取请求协议
InputStream is =client.getInputStream();
byte[] datas = new byte[1024*1024];
int len = is.read(datas);
String requestInfo = new String(datas,0,len);
System.out.println(requestInfo);
Response response =new Response(client);
//关注了内容
response.print("<html>");
response.print("<head>");
response.print("<title>");
response.print("服务器响应成功");
response.print("</title>");
response.print("</head>");
response.print("<body>");
response.print("shsxt server终于回来了...");
response.print("</body>");
response.print("</html>");
//关注了状态码
response.pushBrowser(200);
} catch (IOException e) {
e.printStackTrace();
System.out.println("客户端错误");
}
}
//停止服务
public void stop() {
}
}
4.目标:封装请求信息
package com.sxt.server;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
/**
* 封装请求协议:获取method uri以及请求参数
*
* @author Administrator
*
*/
public class Request1 {
// 协议信息
private String requestInfo;
// 请求方式
private String method;
// 请求url
private String url;
// 请求参数
private String queryStr;
private final String CRLF = "\r\n";
public Request1(Socket client) throws IOException {
this(client.getInputStream());
}
public Request1(InputStream is) {
byte[] datas = new byte[1024 * 1024];
int len;
try {
len = is.read(datas);
this.requestInfo = new String(datas, 0, len);
System.out.println(requestInfo);
} catch (IOException e) {
e.printStackTrace();
return;
}
// 分解字符串
parseRequestInfo();
}
//.indexOf("/") 第一次出现“/“的位置
private void parseRequestInfo() {
System.out.println("---分解---");
System.out.println("1--获取请求方式:开头到第一个/--");
this.method = this.requestInfo.substring(0,this.requestInfo.indexOf("/")).toLowerCase();
this.method=this.method.trim();
System.out.println("2--获取请求url:第一个/到 HTTP/ --");
System.out.println("可能包含请求参数?前面的为url");
//1.获取/的位置
int startldx = this.requestInfo.indexOf("/")+1;
//2.获取http/的位置
int endldx = this.requestInfo.indexOf("HTTP/");
//3.分割字符串
this.url=this.requestInfo.substring(startldx,endldx);
//4.获取?的位置
int queryldx = this.url.indexOf("?");
if(queryldx>=0) {//表示存在请求参数
String[] urlArray = this.url.split("\\?");
this.url=urlArray[0];
queryStr = urlArray[1];
}
System.out.println("--3.获取请求参数:如果GET已经获取,如果POST可能在请求体中--");
if(method.equals("post")) {
String qStr = this.requestInfo.substring( this.requestInfo.lastIndexOf(CRLF)).trim();
if(null==queryStr) {
queryStr=qStr;
}else{
queryStr+="&"+qStr;
}
}
queryStr=null==queryStr?"":queryStr;
System.out.println(method+"-->"+url+"-->"+queryStr);
}
}
package com.sxt.server;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Date;
import sun.misc.Cleaner;
/**
* 目标:封装请求信息
*
*
* @author Administrator
*
*/
public class Server04 {
private ServerSocket serverSocket;
public static void main(String[] args) {
Server04 server = new Server04();
server.start();
}
//启动服务
public void start() {
try {
serverSocket = new ServerSocket(8888);
receive();
} catch (IOException e) {
e.printStackTrace();
System.out.println("服务器启动失败 ");
}
}
//接受连接处理
public void receive() {
try {
Socket client = serverSocket.accept();
System.out.println("一个客户端建立了连接.. ");
//获取请求协议
Request1 request = new Request1(client);
Response response =new Response(client);
//关注了内容
response.print("<html>");
response.print("<head>");
response.print("<title>");
response.print("服务器响应成功");
response.print("</title>");
response.print("</head>");
response.print("<body>");
response.print("shsxt server终于回来了...");
response.print("</body>");
response.print("</html>");
//关注了状态码
response.pushBrowser(200);
} catch (IOException e) {
e.printStackTrace();
System.out.println("客户端错误");
}
}
//停止服务
public void stop() {
}
}
5.封装请求信息中的参数且转成map
package com.sxt.server;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 封装请求协议:封装请求参数为map
*
* @author Administrator
*
*/
public class Request2 {
// 协议信息
private String requestInfo;
// 请求方式
private String method;
// 请求url
private String url;
// 请求参数
private String queryStr;
//存储参数
private Map<String,List<String>> parameterMap;
private final String CRLF = "\r\n";
public Request2(Socket client) throws IOException {
this(client.getInputStream());
}
public Request2(InputStream is) {
parameterMap = new HashMap<>();
byte[] datas = new byte[1024 * 1024];
int len;
try {
len = is.read(datas);
this.requestInfo = new String(datas, 0, len);
System.out.println(requestInfo);
} catch (IOException e) {
e.printStackTrace();
return;
}
// 分解字符串
parseRequestInfo();
}
//.indexOf("/") 第一次出现“/“的位置
private void parseRequestInfo() {
System.out.println("---分解---");
System.out.println("1--获取请求方式:开头到第一个/--");
this.method = this.requestInfo.substring(0,this.requestInfo.indexOf("/")).toLowerCase();
this.method=this.method.trim();
System.out.println("2--获取请求url:第一个/到 HTTP/ --");
System.out.println("可能包含请求参数?前面的为url");
//1.获取/的位置
int startldx = this.requestInfo.indexOf("/")+1;
//2.获取http/的位置
int endldx = this.requestInfo.indexOf("HTTP/");
//3.分割字符串
this.url=this.requestInfo.substring(startldx,endldx);
//4.获取?的位置
int queryldx = this.url.indexOf("?");
if(queryldx>=0) {//表示存在请求参数
String[] urlArray = this.url.split("\\?");
this.url=urlArray[0];
queryStr = urlArray[1];
}
System.out.println("--3.获取请求参数:如果GET已经获取,如果POST可能在请求体中--");
if(method.equals("post")) {
String qStr = this.requestInfo.substring( this.requestInfo.lastIndexOf(CRLF)).trim();
if(null==queryStr) {
queryStr=qStr;
}else{
queryStr+="&"+qStr;
}
}
queryStr=null==queryStr?"":queryStr;
System.out.println(method+"-->"+url+"-->"+queryStr);
//转成mapfav=1&fav=2&uname=sd*pwd=123
cinvertMap();
}
//处理请求参数为map
private void cinvertMap() {
//1.分割字符串
String[] keyValues = this.queryStr.split("&");
for (String queryStr : keyValues) {
//2.再次分割字符串 =
String[] kv = queryStr.split("=");
kv=Arrays.copyOf(kv,2);
//获取key和value
String key = kv[0];
String value = kv[1]==null?null:decode(kv[1], "utf-8");
//存储到map中
if(!parameterMap.containsKey(key)) {//第一次
parameterMap.put(key, new ArrayList<String>());
}
parameterMap.get(key).add(value);
}
}
//处理中文
private String decode(String value,String enc) {
try {
return java.net.URLDecoder.decode(value,enc);
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
/**
* 通过name获取对应的多个值
* @param key
* @return
*/
public String[] getParameterValues(String key) {
List<String> values = this.parameterMap.get(key);
if(null==values || values.size()<1) {
return null;
}
return values.toArray(new String[0]);
}
/**
* 通过name获取对应的一个值
* @param key
* @return
*/
public String getParameter(String key) {
String[] values=getParameterValues(key);
return values==null?null:values[0];
}
/**
* @return the method
*/
public String getMethod() {
return method;
}
/**
* @return the url
*/
public String getUrl() {
return url;
}
/**
* @return the queryStr
*/
public String getQueryStr() {
return queryStr;
}
}
package com.sxt.server;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Date;
import sun.misc.Cleaner;
/**
* 目标:封装请求信息中的参数转成map
*
*
* @author Administrator
*
*/
public class Server05 {
private ServerSocket serverSocket;
public static void main(String[] args) {
Server05 server = new Server05();
server.start();
}
//启动服务
public void start() {
try {
serverSocket = new ServerSocket(8888);
receive();
} catch (IOException e) {
e.printStackTrace();
System.out.println("服务器启动失败 ");
}
}
//接受连接处理
public void receive() {
try {
Socket client = serverSocket.accept();
System.out.println("一个客户端建立了连接.. ");
//获取请求协议
Request2 request2 = new Request2(client);
Response response =new Response(client);
//关注了内容
response.print("<html>");
response.print("<head>");
response.print("<title>");
response.print("服务器响应成功");
response.print("</title>");
response.print("</head>");
response.print("<body>");
response.print("shsxt server终于回来了..."+request2.getParameter("uname"));
response.print("</body>");
response.print("</html>");
//关注了状态码
response.pushBrowser(200);
} catch (IOException e) {
e.printStackTrace();
System.out.println("客户端错误");
}
}
//停止服务
public void stop() {
}
}
6.加入了servlet 解耦了代码
package com.sxt.server;
/**
* 服务器小脚本接口
* @author Administrator
*
*/
public interface Servlet {
void service(Request request,Response response);
}
package com.sxt.server;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Date;
import sun.misc.Cleaner;
/**
* 目标:加入了servlet 解耦了代码
*
*
* @author Administrator
*
*/
public class Server06 {
private ServerSocket serverSocket;
public static void main(String[] args) {
Server06 server = new Server06();
server.start();
}
// 启动服务
public void start() {
try {
serverSocket = new ServerSocket(8888);
receive();
} catch (IOException e) {
e.printStackTrace();
System.out.println("服务器启动失败 ");
}
}
// 接受连接处理
public void receive() {
try {
Socket client = serverSocket.accept();
System.out.println("一个客户端建立了连接.. ");
// 获取请求协议
Request request = new Request(client);
// 获取响应协议
Response response = new Response(client);
Servlet servlet =null;
if(request.getUrl().equals("login")) {
servlet = new LoginServlet();
}else if(request.getUrl().equals("reg")) {
servlet = new RegServlet();
}else {
//首页
}
servlet.service(request, response);
// 关注了状态码
response.pushBrowser(200);
} catch (IOException e) {
e.printStackTrace();
System.out.println("客户端错误");
}
}
// 停止服务
public void stop() {
}
}
7.整合配置文件 反射完成
package com.sxt.server;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
/**
* sax解析 反射获取servlet
* @author Administrator
*
*/
public class WebApp {
private static WebContext webContext;
static {
try {
// sax解析
// 1.获取解析工厂
SAXParserFactory factory = SAXParserFactory.newInstance();
// 2.从解析工厂获取解析器
SAXParser parse = factory.newSAXParser();
// 3.编写处理器
// 4.加载文档Document注册处理器
WebHandler handler = new WebHandler();
// 5.解析
parse.parse(Thread.currentThread().getContextClassLoader().getResourceAsStream("web.xml"),
handler);
//获取数据;
webContext = new WebContext(handler.getEntitys(), handler.getMappings());
} catch (Exception e) {
System.out.println("解析配置文件错误 ");
}
}
/**
* 通过url获取配置文件对应的servlet
* @param url
* @return
*/
public static Servlet getServletFromUrl(String url) {
//假设输入了/login
String name = webContext.getClz("/"+url);
Class clz;
try {
clz = Class.forName(name);
Servlet servlet = (Servlet) clz.getConstructor().newInstance();
return servlet;
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
}
package com.sxt.server;
/**
* 封装成map集合 方便取数据 url-pattern得到servlet-name 通过servlet-name 得到servlet-class
*/
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class WebContext {
private List<Entity> entitys = null;
private List<Mapping> mappings = null;
//key->servlet-name value-->servlet-class
private Map<String,String> entityMap = new HashMap<String,String>();
//key-->url-pattern value-->servlet-name
private Map<String,String> mappingMap = new HashMap<String,String>();
public WebContext(List<Entity> entitys, List<Mapping> mappings) {
this.entitys = entitys;
this.mappings = mappings;
//将entity 的List转成了对应的map
for (Entity entity : entitys) {
entityMap.put(entity.getName(), entity.getClz());
}
for (Mapping mapping : mappings) {
for (String pattern : mapping.getPatterns()) {
mappingMap.put(pattern, mapping.getName());
}
}
}
/**
* 通过url的路径找到了对应的class
* @param pattern
* @return
*/
public String getClz(String pattern) {
String name = mappingMap.get(pattern);
return entityMap.get(name);
}
}
package com.sxt.server;
import java.util.ArrayList;
import java.util.List;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
/**
* 处理器 得到xml里的 属性
* @author Administrator
*
*/
public class WebHandler extends DefaultHandler {
private List<Entity> entitys;
private List<Mapping> mappings;
private Entity entity;
private Mapping mapping;
private String tag;// 存储操作标签
private boolean isMapping = false;;
@Override
public void startDocument() throws SAXException {
entitys = new ArrayList<Entity>();
mappings = new ArrayList<Mapping>();
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
if (null != qName) {
tag = qName;// 存储标签名
if (tag.equals("servlet")) {
entity = new Entity();
isMapping=false;
} else if (tag.equals("servlet-mapping")) {
mapping = new Mapping();
isMapping=true;
}
}
}
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
String contents = new String(ch, start, length).trim();
if (null != tag) {// 处理了空的问题
if(isMapping) {//操作servlet-mapping
if (tag.equals("servlet-name")) {
mapping.setName(contents);
} else if (tag.equals("url-pattern")) {
mapping.addPattern(contents);
}
}else {//操作servlet
if (tag.equals("servlet-name")) {
entity.setName(contents);
} else if (tag.equals("servlet-class")) {
entity.setClz(contents);
}
}
}
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
if (null != qName) {
if (qName.equals("servlet")) {
entitys.add(entity);
}else if (qName.equals("servlet-mapping")) {
mappings.add(mapping);
}
tag = null;// tag丢弃了
}
}
@Override
public void endDocument() throws SAXException {
}
/**
* @return the entitys
*/
public List<Entity> getEntitys() {
return entitys;
}
/**
* @return the mappings
*/
public List<Mapping> getMappings() {
return mappings;
}
}
package com.sxt.server;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Date;
import sun.misc.Cleaner;
/**
* 目标:整合配置文件
*
*
* @author Administrator
*
*/
public class Server07 {
private ServerSocket serverSocket;
public static void main(String[] args) {
Server07 server = new Server07();
server.start();
}
// 启动服务
public void start() {
try {
serverSocket = new ServerSocket(8888);
receive();
} catch (IOException e) {
e.printStackTrace();
System.out.println("服务器启动失败 ");
}
}
// 接受连接处理
public void receive() {
try {
Socket client = serverSocket.accept();
System.out.println("一个客户端建立了连接.. ");
// 获取请求协议
Request request = new Request(client);
// 获取响应协议
Response response = new Response(client);
Servlet servlet = WebApp.getServletFromUrl(request.getUrl());
if (null != servlet) {
servlet.service(request, response);
// 关注了状态码
response.pushBrowser(200);
} else {
// 错误页面
response.pushBrowser(404);
}
} catch (IOException e) {
e.printStackTrace();
System.out.println("客户端错误");
}
}
// 停止服务
public void stop() {
}
}
//8.多线程处理 加入分发器
package com.sxt.server;
import java.io.IOException;
import java.net.Socket;
/**
* 分发器
* @author Administrator
*
*/
public class Dispatcher1 implements Runnable {
private Socket client;
private Request request;
private Response response;
public Dispatcher1(Socket client) {
this.client = client;
try {
// 获取请求协议
// 获取响应协议
request = new Request(client);
response = new Response(client);
} catch (IOException e) {
e.printStackTrace();
this.release();
}
}
@Override
public void run() {
try {
//通过反射得到servlet
Servlet servlet = WebApp.getServletFromUrl(request.getUrl());
if (null != servlet) {
servlet.service(request, response);
// 关注了状态码
response.pushBrowser(200);
} else {
// 错误页面
response.pushBrowser(404);
}
}catch (Exception e) {
try {
response.pushBrowser(500);
} catch (IOException e1) {
e1.printStackTrace();
}
}
release();//短链接 用完释放
}
//释放资源
private void release() {
try {
client.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
package com.sxt.server;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Date;
import sun.misc.Cleaner;
/**
* 目标:多线程处理 加入分发器
*
*
* @author Administrator
*
*/
public class Server08 {
private ServerSocket serverSocket;
private boolean isRunning;
public static void main(String[] args) {
Server08 server = new Server08();
server.start();
}
// 启动服务
public void start() {
try {
serverSocket = new ServerSocket(8888);
isRunning = true;
receive();
} catch (IOException e) {
e.printStackTrace();
System.out.println("服务器启动失败 ");
}
}
// 接受连接处理
public void receive() {
while (true) {
try {
Socket client = serverSocket.accept();
System.out.println("一个客户端建立了连接.. ");
// 多线程处理
new Thread(new Dispatcher(client)).start();
} catch (IOException e) {
e.printStackTrace();
System.out.println("客户端错误");
}
}
}
// 停止服务
public void stop() {
isRunning = false;
try {
this.serverSocket.close();
System.out.println("服务器停止了");
} catch (IOException e) {
e.printStackTrace();
}
}
}
```这样就自己手写了webser服务器