一、目标

诸如tomcat等web服务器中间件简化了我们web的开发成本,但有时候我们或许并不需要这么一个完备的服务器,只是希望做一个简单地处理或者做特殊用途的服务器。

本文将提供一个HTTP的服务器示例,采用Java的ServerSocket进行编码。随着计算机硬件的提升,以及Java地不断优化,使用Java网络编程实现web服务器在实际性能上已经开始可以跟C进行竞争。

二、代码示例

以下代码分为两块:

1)HttpServer:主要包含一个ServerSocket,用于接收客户端请求。并通过线程池将请求从主线程剥离,分散到各个线程中去处理;

2)RequestHandler:实现了Runnable接口,将获取一个线程来处理各个请求;流的读取和响应遵循HTTP协议。

注意:编写Http服务器和一般的socket程序并没有太大不同,但是你需要遵循HTTP协议,这样对于采用HTTP协议的客户端或者其它服务器就可以直接进行HTTP请求来通讯。

HttpServer

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.*;

/**
 * Http服务器端示例,端口设置为8080,编码设置为UTF-8
 * @author lay
 * @date 2019-01-01
 */
public class HttpServer {
    private static final int port = 8080;

    /**
     * 启动HTTP服务器
     */
    public void start() throws IOException {
        // 初始化线程池
        ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 10, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<>());
        // 初始化服务器socket
        ServerSocket serverSocket = new ServerSocket(port);
        System.out.println("ServerSocket启动完成");
        while (true) {
            // 阻塞等待socket连接
            System.out.println("等待socket");
            Socket socket = serverSocket.accept();
            // 提交至线程池处理
            executor.submit(new RequestHandler(socket));
            System.out.println("提交线程池处理请求");
        }
    }

    public static void main(String[] args) {
        try {
            new HttpServer().start();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

RequestHandler

import java.io.*;
import java.net.Socket;

/**
 * 请求处理类
 * @author lay
 * @date 2019-01-01
 */
public class RequestHandler implements Runnable {
    /**
     * HTTP响应头
     */
    private static final String response = "http/1.1 200 ok";
    private static final String splitStr = "\r\n";

    private Socket         socket;
    private BufferedReader reader;
    private BufferedWriter writer;

    public RequestHandler(Socket socket) throws IOException {
        this.socket = socket;
        this.reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        this.writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
    }

    /**
     * 响应结果
     * @param content 响应内容
     * @throws IOException IO异常抛出
     */
    public void sendResponse(String content) throws IOException {
        writer.write(String.format("%s%s", response, splitStr));
        writer.write(splitStr);
        writer.write(content);
    }

    /**
     * 获得请求
     * @return 请求文本
     * @throws IOException IO异常抛出
     */
    public String getRequest() throws IOException {
        StringBuilder stringBuilder = new StringBuilder();
        String        line;
        while ((line = reader.readLine()) != null) {
            stringBuilder.append(line);
            stringBuilder.append(splitStr);
            // 空字符串
            if (line.isEmpty()) {
                break;
            }
        }
        System.out.println("request:\r\n" + stringBuilder);
        return stringBuilder.toString();
    }

    @Override
    public void run() {
        try {
            String request = getRequest();
            // 这里直接把请求数据响应回去
            sendResponse(request);
            writer.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                reader.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                writer.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

请求处理器这里直接将请求的HTTP内容返回回去了,如果你使用浏览器请求8080端口,你会看到如下内容:

不过浏览器会默认请求一个icon,所以针对一个URL地址会有两个请求

你可以在ico请求的时候返回一个二进制的ico文件流,它将显示在浏览器的tab上。

扩展点:

1)我们可以像tomcat一样去支持Java Servlet API

2)支持如GET、POST、PUT、DELETE等restful请求

3)将程序配置进行XML配置

4)增加管理界面

5)请求跟踪处理

6)缓存、非阻塞IO、通道来增加性能

二、socket编写简单BIO的HTTP服务器的更多相关文章

  1. ROS学习(十二)—— 编写简单的消息发布器和订阅器(C++)

    一.创建发布器节点 1 节点功能: 不断的在ROS网络中广播消息 2 创建节点 (1)打开工作空间目录 cd ~/catkin_ws/src/beginner_tutorials 创建一个发布器节点( ...

  2. 关于Socket编写简单聊天工具的总结(原创)

    这段时间再看socket编程,虽然现在是刚刚接触,但是还是忍不住想写一篇总结,来激励自己努力学习,写的不好的地方,还请大家指教啊! 下面针对一个简单的发送消息和文件的程序说说吧.   首先是服务器需要 ...

  3. socket编写简单回显server

    socket在公司代码中应用比较广,比如接口调用的IPCRPC机制,经常看到这样的代码,但是一直也没有动手写过. 在某个比较大的进程中创建一个子进程,由于父子进程复制会浪费内存,可以将创建进程的命令通 ...

  4. Linux 字符设备驱动开发基础(二)—— 编写简单 PWM 设备驱动【转】

    本文转载自:https://blog.csdn.net/zqixiao_09/article/details/50858776 版权声明:本文为博主原创文章,未经博主允许不得转载.    https: ...

  5. 小鸟初学Shell编程(二)编写简单的Shell脚本

    Shell脚本 编写Python.PHP脚本通常需要掌握语言的函数,那么Shell脚本则不需要,只需要掌握Linux命令就可以编写Shell脚本,因为Shell脚本就是由多个Linux命令组成,通过将 ...

  6. C#中使用Socket实现简单Web服务器

    上一篇博客中介绍了怎样使用socket访问web服务器.关键有两个: 熟悉Socket编程: 熟悉HTTP协议. 上一篇主要是通过socket来模拟浏览器向(任何)Web服务器发送(HTTP)请求,重 ...

  7. 运用socket实现简单的服务器客户端交互

    Socket解释: 网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket. Socket的英文原义是“孔”或“插座”.作为BSD UNIX的进程通信机制,取后一种意 ...

  8. java Socket实现简单在线聊天(二)

    接<java Socket实现简单在线聊天(一)>,在单客户端连接的基础上,这里第二步需要实现多客户端的连接,也就需要使用到线程.每当有一个新的客户端连接上来,服务端便需要新启动一个线程进 ...

  9. SLAM+语音机器人DIY系列:(二)ROS入门——5.编写简单的消息发布器和订阅器

    摘要 ROS机器人操作系统在机器人应用领域很流行,依托代码开源和模块间协作等特性,给机器人开发者带来了很大的方便.我们的机器人“miiboo”中的大部分程序也采用ROS进行开发,所以本文就重点对ROS ...

随机推荐

  1. Learning Rich Features from RGB-D Images for Object Detection and Segmentation论文笔记

    相关工作: 将R-CNN推广到RGB-D图像,引入一种新的编码方式来捕获图像中像素的地心姿态,并且这种新的编码方式比单纯使用深度通道有了明显的改进. 我们建议在每个像素上用三个通道编码深度图像:水平视 ...

  2. 水平居中和transform: translateY(-50%) 实现元素垂直居中效果

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  3. SpringMVC常用方法大全

    ---恢复内容开始--- web.xml: <?xml version="1.0" encoding="UTF-8"?> <web-app x ...

  4. java中数组的插入

    package com.hxzy.demo; import java.util.Arrays;import java.util.Scanner; public class Demo1 { public ...

  5. Mutation Observer

    MutationEvent Mutation Observer 变动观察器, 等待所有脚本任务完成后,才会运行(即异步触发方式) 把DOM变动记录封装成一个数组进行处理,而不是一条条个别处理DOM变动 ...

  6. Springboot接口简单实现生成MySQL插入语句

    Springboot接口简单实现调用接口生成MySQL插入语句 在实际测试中,有这样一个需求场景,比如:在性能压力测试中,可能需要我们事先插入数据库中一些相关联的数据. 我们在实际测试中,遇到问题,需 ...

  7. 3.3.1 Validations

    摘要: 出处:黑洞中的奇点 的博客 http://www.cnblogs.com/kelvin19840813/ 您的支持是对博主最大的鼓励,感谢您的认真阅读.本文版权归作者所有,欢迎转载,但请保留该 ...

  8. linux之getenv putenv setenv和unsetenv详解

    1.getenv函数 头文件:#include<stdlib.h> 函数原型: char * getenv(const char* name); 函数说明:getenv()用来取得参数na ...

  9. ConcurrentHashMap相关知识点

    ConcurrentHashMap涉及的知识点:HashMap,HashTable,UnSafe,CAS,数组+链表,Segment,ReentrantLock(非公平锁,公平锁),红黑树. 为什么要 ...

  10. 往word中插入美观的代码

    http://www.planetb.ca/syntax-highlight-word 选择需要的语言,然后Show Highlighted,复制跳转页面显示的代码至word即可