java 编写简易的http服务器

想要写一个http服务器,首先得了解http协议。这里仅介绍一下相关的知识。

1、http协议

HTTP请求报文

在请求中,HTTP报文由方法、URI、HTTP版本、HTTP首部字段等部分构成。其中方法、URI、HTTP版本作为首行,然后每个HTTP首部字段为一行,以上内容简称为请求头,如下请求头:

GET /favicon.ico HTTP/1.1     //首行,GET为请求方法,favicon.ico为url链接,1.1版本号
Host: 172.30.67.185:8080      //以下为首部字段行
Connection: keep-alive
Accept: image/webp,image/apng,image/*,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8

注:请求报文一般由浏览器(客户端)向服务器发送

HTTP响应报文

在响应中,HTTP报文由HTTP版本、状态码、HTTP首部字段3部分构成,其中HTTP版本、状态码作为首行,然后每个HTTP首部字段为一行,以上内容简称为响应头,如下响应头:

HTTP/1.1 200 OK         //首行,1.1为版本号,200为状态码。以下行为首行字段
Content-Type:text/html;charset=utf-8

//空一行后,响应客户端的内容,后面会讲

注:请求报文一般由服务器向浏览器(客户端)发送

2、简单的http服务器

服务器启动程序

首先,编写一个服务器启动程序,我们监听了8080端口,然后得到socket对象,接着new SocketServer(s),然后启动线程。线程池简单看作启动线程的工具就行了(需要深入了解线程池的自行百度)。

public static void main(String[] args) {
	ServerSocket server=null;
    //线程池,简单来说,就是把线程start()改成ex.execute(),然后可以提高服务器性能
	ExecutorService ex=Executors.newFixedThreadPool(20);
	try {
        //建立服务器监听端口
		server=new ServerSocket(8080);
		while(true) {
			Socket s=server.accept();
            //然后把接收到socket传给SocketServer并执行该线程
			ex.execute(new SocketServer(s));
		}
	} catch (IOException e) {
		e.printStackTrace();
	}
}

接着,因为我们的SocketServer需要做的是做一个http服务器,所以重点来了!怎么接受浏览器(客户端)传来的请求呢?然后又怎么给浏览器(客户端)响应内容呢?

http服务器类

因为浏览器(客户端)的请求方法有GET、POST等,在这里,先写一个响应GET的请求。

思路:

1、打开socket对象的输入流,接收浏览器(客户端)的请求头

2、分析字段内容,判断请求方法、链接

3、打开socket对象的输出流,在输出流里写入响应头

4、空一行,写入响应内容。

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;

public class SocketServer implements Runnable{
    Socket s;
	//构造方法
	public SocketServer(Socket s) {
		this.s=s;
	}
	//线程
	public void run(){
		//输入输出流
		OutputStream os=null;
		InputStream in=null;
		try 
		{	//打开socket输入流,并转为BufferedReader流
			in=s.getInputStream();
			BufferedReader br=new BufferedReader(new InputStreamReader(in));

			//接收第一行,得到请求路径
			String requestHeader;
			requestHeader=br.readLine();
			int begin = requestHeader.indexOf("/")+1;
			int end = requestHeader.indexOf("HTTP/");
			String url="E:\\sublime文件\\Html文件\\第二天案例\\";
			url=url+requestHeader.substring(begin, end);  

            
			//打开socket对象的输出流,写入响应头
			os = s.getOutputStream();
			os.write("HTTP/1.1 200 OK\r\n".getBytes());
			os.write("Content-Type:text/html;charset=utf-8\r\n".getBytes());
			os.write("\r\n".getBytes());

			//空一行,写入响应内容。
			File f=new File(url);
			if(f.exists())    //判断请求的文件是否存在
			{
				FileInputStream fin=new FileInputStream(f);
				byte []b=new byte[1024];
				int len;
				while((len=fin.read(b))!=-1)
				{
					os.write(b,0,len);
				}
			}
			os.flush();
			//如果os流没有关闭的话,浏览器会以为内容还没传输完成,将一直显示不了内容
			os.close();
		
	}

}

实现过程非常简单,简单到没有判断浏览器(客户端)的请求方法,直接返回了一个请求路径的文件。

 

如有不对之处,直接指正,会做修改