Java Socket实现http协议

HTTP协议报文结构

HTTP 协议是应用层协议,HTTP协议报文分为请求报文和响应报文两种类型,两者都包含三部分:首行、头部、主体。

  • HTTP 请求报文

    • 请求行:GET / HTTP/1.1
      表示请求的方法(请求类型)、路径、协议版本

    • 请求头:Connection: keep-alive

    • 请求体:GET的请求体为空

  • HTTP 响应报文

    • 响应行:HTTP/1.1 200

    • 响应头:content-type: text/html; charset=utf-8

    • 响应体:主体内容

  • Socket实现HTTP协议:

package it.yus.socket;

import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.util.Iterator;
import java.util.concurrent.Executor;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
 * 
 * 描述:
 * @author yusong
 * @since 1.8
 */
public class HttpServer {

	public static void main(String[] args) throws Exception {
		// 创建 ServerSocketChannel
		ServerSocketChannel serverChannel = ServerSocketChannel.open();
		serverChannel.bind(new InetSocketAddress(8080));
		// 配置为非阻塞
		serverChannel.configureBlocking(false);
		// 注册选择器
		Selector selector = Selector.open();
		serverChannel.register(selector, SelectionKey.OP_ACCEPT);
		// 创建线程池
		Executor ex = new ThreadPoolExecutor(8, 8, 500, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
		// 创建处理器
		while (true) {
			// 每次等待0.5秒,0.5秒后返回的就绪通道为0则继续阻塞
			if (selector.select(500) == 0) {
				continue;
			}
			// 获取待处理的seletionKey
			Iterator<SelectionKey> it = selector.selectedKeys().iterator();
			while (it.hasNext()) {
				SelectionKey key = it.next();
				HttpHandler httpHandler = new HttpHandler(key);
				ex.execute(httpHandler);
			}
		}
	}

	// 处理请求
	private static class HttpHandler implements Runnable {
		// TCP包长度
		private int bufferSize = 1024;
		// 编码字符集
		private String charset = "UTF-8";
		// 注册的事件
		private SelectionKey key;

		public HttpHandler(SelectionKey key) {
			this.key = key;
		}

		// 处理ServerSocketChannel接受请求
		public void handleAccept() throws Exception {
			ServerSocketChannel serverChannel = (ServerSocketChannel) key.channel();
			// 接收的客户端的连接
			SocketChannel channel = serverChannel.accept();
			channel.configureBlocking(false);
			// 注册到选择器
			channel.register(key.selector(), SelectionKey.OP_READ,
					ByteBuffer.allocate(bufferSize));
		}

		// socketChannel 读取数据
		public void handleRead() throws Exception {
			// 获取channel
			SocketChannel channel = (SocketChannel) key.channel();
			// 获取Buffer并重置
			ByteBuffer buffer = (ByteBuffer) key.attachment();
			buffer.clear();
			// 从通道获取内容
			if (channel.read(buffer) == -1) {
				channel.close();
			} else {
				// 接受请求数据
				buffer.flip();
				String reciveMsg = Charset.forName(charset).newDecoder().decode(buffer).toString();
				String[] requestContent = reciveMsg.split("\r\n");
				for (String line : requestContent) {
					System.out.println(line);
					if (line.isEmpty()) {
						break;
					}
				}

				// 返回客户端
				StringBuilder sendMsg = new StringBuilder();
				sendMsg.append("HTTP/1.1 200 OK\r\n");// 响应行
				// 响应头
				sendMsg.append("cache-control: private;\r\n")
				  	   .append("content-type: text/html; charset=utf-8\r\n")
					   .append("\r\n")
				// 响应体
					    .append("<!DOCTYPE html><html lang=\"zh-cn\">")
					    .append("<head><meta charset=\"utf-8\"/><title>测试HttpServer</title></head>")
					    .append("<body><h3>服务端接收到的请求报文</h3>");
				for (String line : requestContent) {
					sendMsg.append(line+"</br>");
					if (line.isEmpty()) {
						break;
					}
				}
				sendMsg.append("</body>");
				buffer = ByteBuffer.wrap(sendMsg.toString().getBytes(charset));
				// 发送
				channel.write(buffer);
				channel.close();
			}
		}

		@Override
		public void run() {
			try {
				if (key.isAcceptable()) {
					handleAccept();
				}
				if (key.isReadable()) {
					handleRead();
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}

	}
}

  • 控制台及浏览器打印结果:

转载于:https://my.oschina.net/u/3917923/blog/2877759

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值