通过socket相关接口和http的访问协议做一个简单的web服务器

对网络中的各种协议认识不足,所以学习下。在学习tomcat服务器的过程中,了解到它是基于一个简单的web服务器慢慢拓展到一个应用广泛的服务器的。

所以,这里做个简单的web服务器

  1. 创建一个简单的webserver类
package com.chl.webserver;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * 一个简单的web服务器( Tomcat )
 * @author chenhailong
 *
 */
public class WebServer {
	
	/**
	 * 可以存放一些测试应用程序的静态资源或servlet.是工作目录
	 */
	public static final String WEB_ROOT = 
			System.getProperty("user.dir") + File.separator + "webroot";
	
	//服务停止命令
	public static final String SHUTDOWN_COMMAND = "/SHUTDOWN";

	//控制服务状态
	private boolean shutdown = false;
	
	public static void main(String[] args) {

		
		WebServer ws = new WebServer();
		ws.await();
		
	}
	
	//socket服务端一直接收消息
	public void await() {
		ServerSocket serverSocket = null;
		int port = 8080;
		try {
			serverSocket = new ServerSocket(port,1,InetAddress.getByName("127.0.0.1"));
		}catch(IOException e) {
			e.printStackTrace();
			System.exit(1);
		}
		//循环等待请求
		while(!shutdown) {
		
			Socket socket = null;
			InputStream input = null;
			OutputStream output = null;
			
			try {
				//接收到请求之后,await方法从accept方法返回的socket实例中获取input、output对象
				socket = serverSocket.accept();
				input = socket.getInputStream();
				output = socket.getOutputStream();
				
				//创建一个Request对象并且调用parse方法解析HTTP请求的原始数据
				Request request = new Request(input);
				request.parse();
				
				//创建一个Response响应对象
				Response response = new Response(output);
				response.setRequest(request);
				response.sendStaticResource();
				
				//关闭socket
				socket.close();
				// 判断http请求的uri是不是一个shutdown命令。如果是,则shutdown会置为true,从而推出循环
				shutdown = request.getUri().equals(SHUTDOWN_COMMAND);
				
			}catch(Exception e) {
				e.printStackTrace();
				continue;
			}
			
		}
	}

}


  1. 创建一个简单的request请求类
package com.chl.webserver;

import java.io.IOException;
import java.io.InputStream;

public class Request {
	// 输入流
	private InputStream input;
	// 地址
	private String uri;

	public Request(InputStream input) {
		this.input = input;
	}
	
	public String getUri() {
		return uri;
	}

	//解析http请求中的原始数据。
	void parse() {
		 //Read a set of characters from the socket
		 StringBuffer request = new StringBuffer(2048);
		 int i ;
		 byte[] buffer = new byte[2048];
		 try {
			 i = input.read(buffer);
		 }catch(IOException e) {
			 e.printStackTrace();
			 i = -1;
		 }
		 for(int j = 0; j< i;j++) {
			 request.append((char)buffer[j]);
		 }
		 System.out.println(request.toString());
		 uri = parseUri(request.toString());
	 }

	//从 url中返回uri
	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;
	}
}


3.创建一个response响应类

package com.chl.webserver;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;

public class Response {
	
	private static final int BUFFER_SIZE = 1024;
	
	Request request;
	OutputStream output;
	
	//构造函数创建output对象
	public Response(OutputStream output) {
		this.output = output;
	}
	
	//传递request对象给reponse
	public void setRequest(Request request) {
		this.request = request;
	}
	
	// 输出一个静态资源
	public void sendStaticResource() throws IOException{
		byte[] bytes = new byte[BUFFER_SIZE];
		FileInputStream fis = null;
		try {
			File file = new File(WebServer.WEB_ROOT,request.getUri());
			if(file.exists()) {
				fis = new FileInputStream(file);
				int ch = fis.read(bytes,0,BUFFER_SIZE);
				while( ch != -1) {
					output.write(bytes,0,BUFFER_SIZE);
					ch = fis.read(bytes,0,BUFFER_SIZE);
				}
			}else { //如果不存在,则发送一个异常信息
				String errorMessage = "HTTP/1.1 404 File Not Found \r\n"+
					"Content-Type : text/html\r\n"+
					"Content-Length:23\r\n"+
					"\r\n"+
					"<h1>File Not Found</h1>";
				System.out.println(errorMessage);
				output.write(errorMessage.getBytes());
			}
			
			
		}catch(Exception e) {
			System.out.println(e.toString());
		}finally {
			if(fis != null)
				fis.close();
		}
	}
}

  1. 测试输入 http://127.0.0.1:8080/123

可以看到控制台输出以下信息


## 请求信息
GET /123 HTTP/1.1
Host: 127.0.0.1:8080
Connection: keep-alive
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9


## 响应信息
HTTP/1.1 404 File Not Found 
Content-Type : text/html
Content-Length:23

<h1>File Not Found</h1>

5.关闭服务 输入http://127.0.0.1:8080/SHUTDOWN

你查看后台,就发现服务已经关闭了。

注:这是一个简单的例子,由繁入简容易,由简入繁可是需要很多的尝试及验证才能证明它的能力。所以还是很佩服这些能写服务器、各种如dubbo协议、hession制定人,能力很强且创造力满满。我们这些造轮子的就明显相形见绌。

扩展:
了解RPC逻辑及SOCKET的使用请看这里

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值