使用Java编写最小Http服务器的设计要点

  设计一个仅仅返回一段字符串的最小http服务器有助于理解http协议。对于正规的java程序员,这个程序仅仅用于学习,没有实用价值。对于自动化工程师,小型化的http服务器有着重要的工程意义,因为我们通常不怎么喜欢为了一个简单的页面而去安装Tomcat。
  要设计这样一个服务器其实非常简单,只需要掌握一点细节。
  1、你需要选择一个监听端口,一般网页服务器使用80或8080,但这并不是必须的,可以指定其它未被使用的端口。比如我选择1234端口。用浏览器连接本机1234端口的方法很简单,就是使用这个url:http://localhost:1234
  2、我个人比较喜欢使用AIO来创建连接,而新手一般都是使用Server来建立连接。不管是AIO、NIO还是Server最终的效果都是一样的。总之这一步要打开TCP的监听线程。
  3、等待连接。注意Server和NIO的连接是阻塞的,AIO是非阻塞的。
  4、等待接收。Server字节流和未缓冲的字符流是非阻塞的,缓冲的字符流使用readLine读取时是阻塞的。NIO和AIO接收字节是阻塞的,但不是以流的方式。所以需要使用new String(bytes,encoding)来将字节转换成字符串
  5、正确的http服务器是需要分析收到的数据的,但是我们现在不需要。所以直接返回数据。一定要返回正确的报文头。http报文就是一段字符串,以”\r\n”分行,并以第一个空行区分报文头与正文。最小的报文头是这么写的“HTTP/1.0 200 OK\r\n”,加上一个空行和一个正文后变成”HTTP/1.0 200 OK\r\n\r\n正文”
  6、这一步很关键,就是要关闭输出。如果使用Server,需要将OutputStream关闭,如果使用NIO或AIO,需要将channel的输出关闭。记住不要直接关闭连接,否则会出异常。虽然网页能正常显示,但是过多的异常可能会导致JVM强制关闭。
  下面是我的主程序: 

public static void main(String[] args) {
        //这个是客户端,你们也可以删除这个线程,用浏览器来测试
        StaticThreadTools.execute(() -> {
                StaticThreadTools.sleep(1000);
                System.out.println(StaticHttpTools.sendPost("http://localhost:1234", "a=a"));
        });
        //打开AIO的服务器,也可以更换成NIO或者Server
        TCPSocketAIOServer server = new TCPSocketAIOServer(1234, 10000, -1);//形参的意思是“端口1234、缓冲区10000字节,阻塞方式读取”。这里没有给出子程序,所以你们不要直接用它来编译。
        //打开
        server.open();
        //http服务器主体
        doServer(server);
        server.close();
    }

    private static void doServer(TCPSocketAIOServer server) {
        for (;;) {
        //等待读取
            TCPSocketMessage msg = server.receive();
            //跳过空包(这种空包的情况是我的AIO工具类特有的,不要照抄)
            if (msg == null) {
                break;
            }
            if (msg.get() == null) {
                continue;
            }
            //建立一个线程来处理消息
            StaticThreadTools.execute(() -> {
                System.out.println(msg.getRemoteSocketAddress());
                //输出报文头
                TCPSocketMessage msg2 = new TCPSocketMessage();
                final String HEAD = StaticHttpTools.getHttpServerHead(HTTP_CONST.CONTENT_TYPE_HTML, "myServer");
                msg2.acceptString(HEAD);
                msg.reply(msg2);
                //输出正文(这个例子直接使用报文头来当正文)
                msg.reply(msg2);
                //关闭输出
                msg.closeOutput();
            });
        }
    }

关键点:
1、初学者不管收到什么,都返回一个”HTTP/1.0 200 OK\r\n\r\n”就对了。”HTTP/1.0 200 OK\r\n”和一个空行”\r\n”是必须的。然后在这个基础上添加其它的东西。等熟悉了http的流程后,再考虑错误码和属性之类的东西。
2、必须关闭输出流。在这一步flush是无效的,而直接关闭连接会出异常。因为没注意到这点,我浪费了一天的时间浏览器都没响应。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值