网络编程之手写极简版HTTP服务器

  • Post author:
  • Post category:其他


写http服务器就得知道http协议,这个协议是基于 tcp/ip的,所以我们可以用 ServerSocket 写服务端

客户端就是浏览器,浏览器其实也是通过socket 连接客户端的,一般来说浏览器请求服务器资源的时候,都会带上 请求头信息

就像这样:

请求头里面包含了,请求地址,请求方法,客户端语言,浏览器信息,等等,服务端使用 socket.getInputStream 可以读取到

HTTP协议,所谓协议,就是按照一定的规则,进行数据交换,我们得按照 http协议的规定进行返回数据,浏览器才能正确解析我们返回的数据。

这里我们得注意下,空格 和换行,这个在 返回得头文件里面是必须得

现在来看看代码吧,极简版的,也没管封装啥的,就这样吧,有兴趣得同学可以自己研究下

服务端应该是不停运转得,请求也是并发执行得,所以得使用 多线程和 死循环

调用代码:

        ServerSocket server = new ServerSocket(80);
		long count = 0;
		while (true) {
			Socket socket = server.accept(); // 获取客户端连接
			System.out.println("第["+ (++count) +"]个客户端!ip为:" + socket.getInetAddress().getHostAddress() + " 访问时间: " + new SimpleDateFormat("YYYY-MM-dd HH:mm:ss").format(new Date()) );
			new Thread( new Server(socket) ).start();
		}

Server类:

/**
 * server
 * 
 * @author snow
 *
 */
public class Server implements Runnable {

	// 两个常量
	private static final String CRLF = "\r\n";
	private static final String BLANK = " ";

	private Socket server;
	private String path;
	
	public Server(Socket server) {
		this.server = server;
		System.out.println( "客户端:" + this.server.getInetAddress().getHostName() +" 的请求头文件为:" );
		System.out.println( getData() );
	}

	private String getData() {
		try {
			BufferedInputStream bis = new BufferedInputStream( this.server.getInputStream() );

			byte [] data = new byte[2048];
			int len = bis.read(data);
			String msg = new String(data,0,len);
			
			int start = msg.indexOf("/");
			int end = msg.indexOf("HTTP");
			
			this.path = msg.substring((start+1), end).trim();
			return msg;
		} catch (Exception e) {
			e.printStackTrace();
			return "";
		}
	}
	
	private void sendData() {
		try {
			BufferedOutputStream bos = new BufferedOutputStream(this.server.getOutputStream());
			
			String suffix = path.substring(path.lastIndexOf(".")+1);
			
			File file = new File(path);
			BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
			
			StringBuffer sb = new StringBuffer();
			// http 协议版本,状态码,描述
			sb.append("HTTP/1.1").append(BLANK).append(520).append(BLANK).append("love").append(CRLF);
			// 响应头
			sb.append("Server:Pkusoft Server/12.19.06.14").append(CRLF).append("Date:").append(new Date()).append(CRLF)
					;
			if( "jpg".equals(suffix)) {
				sb.append("Content-type:image/jpg").append(CRLF);
			}else if("png".equals(suffix)) {
				sb.append("Content-type:image/png").append(CRLF);
			}else if("gif".equals(suffix)) {
				sb.append("Content-type:image/gif").append(CRLF);
			}else if("html".equals(suffix)) {
				sb.append("Content-type:text/html").append(CRLF);
			}else if("css".equals(suffix)) {
				sb.append("Content-type:text/css").append(CRLF);
			}else if("js".equals(suffix)) {
				sb.append("Content-type:application/x-javascript").append(CRLF);
			}else {
				sb.append("Content-type:application/octet-stream").append(CRLF);
			}
			
			sb.append("Connection:keep-alive").append(CRLF);
			// 正文长度:内容
			sb.append("Content-Length:").append(file.length()).append(CRLF).append(CRLF);
			
			bos.write(sb.toString().getBytes());
			
			byte [] flush = new byte[1024*1024];
			int len = bis.read(flush);
//			while( (len=bis.read(flush)) != -1 ){
				bos.write(flush, 0, len);
				System.out.println( "读取成功!==>" + path );
//			}
			bos.flush();
		} catch (Exception e) {
			e.printStackTrace();
		}
		
	}

	@Override
	public void run() {
		sendData();
	}

}

运行效果:

打印请求头信息:

页面效果:



版权声明:本文为yali_aini原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。