自己动手实现HTTP协议

  HTTP协议时在应用层解析内容的,只需要按照它的报文格式封装和解析数据就可以了,具体的传输还是使用Socket。
  HTTP协议是在接收到数据之后才会用到,所以在nioServer的Handler就可以了,在修改后的HttpHandler中首先获取到请求的报文,并打印出啊来报文的头部,请求的方法类型、URL和HTTP版本,最后将接收到的请求豹纹信息封装到响应豹纹的主体中返回给客户端。这里的HttpHandler使用了单独的线程来执行,而且把SelectionKey中操作类型的选择也放在了httpHandler中。
代码如下

package com.us.edu.Server;

import java.io.IOException;
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;

public class HttpServer {
    public static void main(String[] args) throws Exception {
        // 创建ServerSocketChannel,监听8080端口
        ServerSocketChannel ssc = ServerSocketChannel.open();
        ssc.socket().bind(new InetSocketAddress(8888));
        // 设置为非阻塞模式
        ssc.configureBlocking(false);
        // 为ssc注册选择器
        Selector selector = Selector.open();
        ssc.register(selector, SelectionKey.OP_ACCEPT);
        System.out.println("accept......");
        while (true) {// 创建处理器,等待请求,每次等待阻塞3秒,超过三秒线程继续向下运行,如果传入0活着不传参数将一直阻塞
            if (selector.select(3000) == 0) {
                continue;
            }
            // 获取处理的selectionKey
            Iterator keyIter = keyIter = selector.selectedKeys().iterator();
            while (keyIter.hasNext()) {
                SelectionKey key = keyIter.next();
                // 启动新线程处理SelectionKey
                new Thread(new HttpHandler(key)).run();
                // 处理完后,从待处理的SelectionKey迭代器中一厨当前使用的key;
                keyIter.remove();
            }
        }

    }

    private static class HttpHandler implements Runnable {
        private int bufferSize = 1024;
        private String localCharset = "utf-8";
        private SelectionKey key;

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

        public void handleAccept() throws IOException {
            SocketChannel clientChannel = ((ServerSocketChannel) key.channel()).accept();
            clientChannel.configureBlocking(false);
            clientChannel.register(key.selector(), SelectionKey.OP_READ, ByteBuffer.allocate(bufferSize));
        }

        public void handleRead() throws IOException {
            // 获取channer
            SocketChannel sc = (SocketChannel) key.channel();
            // 获取buffer并重置
            ByteBuffer buffer = (ByteBuffer) key.attachment();
            buffer.clear();
            // 没有读到内容则关闭
            if (sc.read(buffer) == -1) {
                sc.close();
            } else {
                //接受请求数据
                buffer.flip();
                String receivedString = Charset.forName(localCharset).newDecoder().decode(buffer).toString();
                // 控制台打印请求报文头
                String[] requestMessage = receivedString.split("\r\n");
                for (String s : requestMessage) {
                    System.out.println(s);
                    //遇到空则说明报文头已经打完
                    if (s.isEmpty()) 
                        break;
                }
                    // 控制台打印首行信息
                    String[] firstLine = requestMessage[0].split(" ");
                    System.out.println();
                    System.out.println("Method:\t" + firstLine[0]);
                    System.out.println("url:\t" + firstLine[1]);
                    System.out.println("HTTP Version:\t" + firstLine[2]);
                    System.out.println();
                    // 返回客户端
                    StringBuilder sendString = new StringBuilder();
                    sendString.append("HTTP/1.1 200 OK\r\n");// 响应报文首行,200表示处理成功
                    sendString.append("Content-Type:text/html;charset=" + localCharset + "\r\n");
                    sendString.append("\r\n");// 报文头结束后加一个空行
                    sendString.append("显示报文");
                    sendString.append("接收到的请求报文是:
"
); for (String s : requestMessage) { sendString.append(s + "
"
); } sendString.append(""); buffer = ByteBuffer.wrap(sendString.toString().getBytes(localCharset)); sc.write(buffer); sc.close(); } } @Override public void run() { try { // 接收到连接请求时 if (key.isAcceptable()) { handleAccept(); } // 读数据 if (key.isReadable()) { handleRead(); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }

  运行程序后,在浏览器访问“localhost:8888“控制台会打印如下信息:
GET / HTTP/1.1
Host: localhost:8888
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:47.0) Gecko/20100101 Firefox/47.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Connection: keep-alive
Cache-Control: max-age=0

Method: GET
url: /
HTTP Version: HTTP/1.1

  浏览器会显示如下信息:
接收到的请求报文是:
GET / HTTP/1.1
Host: localhost:8888
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:47.0) Gecko/20100101 Firefox/47.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Connection: keep-alive
Cache-Control: max-age=0

到此一个简单的http协议已经实现了。

你可能感兴趣的:(2.1,Java基础,socket,http协议)