一、目标

诸如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. 【OCP-12c】CUUG 071题库考试原题及答案解析(21)

    3.choose three View the Exhibit and examine the description of SALES and PROMOTIONS tables. You want ...

  2. 关于Tomcat控制台乱码解决办法___ 解决 IntelliJ IDEA Tomcat 控制台中文输出乱码问题

    Tomcat 控制台UTF-8乱码问题 1.修改cmd的编码格式 快捷键win+R打开运行程序,输入regedit打开注册表,找到以下路劲并且修改. [HKEY_LOCAL_MACHINE\SOFTW ...

  3. Java Web 学习与总结(一)Servlet基础

    配置环境:https://www.cnblogs.com/qq965921539/p/9821374.html 简介: Servlet是Sun公司提供的一种实现动态网页的解决方案,在制定J2EE时引入 ...

  4. CentOS6.5加域

    为减少错误已提前关掉了SELinux,防火墙. yum install  nss-pam-ldapd -y 第一步:更改主机名为linux.itxdm.me 第二步:更改setup内左边Winbind ...

  5. Haproxy搭建Web群集

    一.Haproxy与LVS LVS不支持正则处理,不能实现动静分离,对于大型网站,LVS的实施配置复杂,维护成本相对较高 Harpoxy是一款可提供高可用性,负载均衡.及基于TCP和HTTP应用的代理 ...

  6. Eureka客户端注册过程源码解析

    微服务中注册中心是其重要的组成部分,那么客户端是如何注册到注册中心的呢,下面我们进入源码查看. 客户端的注册标志是@EnableDiscoveryClient,我们点进入注解查看 注解介绍这是开启Di ...

  7. Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.******.seashell.bpc.query.query.service.FscBankPayCodeQueryService

    2019-03-19 16:22:14,945 WARN [main] (org.springframework.context.support.AbstractApplicationContext. ...

  8. Xcode升级到9.3之后pod问题

    最近新建了一个项目,然后在终端pod init的时候出现了问题,复制粘贴部分错误信息 MacBook-Pro:testDemo xywy$ pod init [in /Users/xywy/Deskt ...

  9. L07-Linux配置ssh免密远程登录

    本文配置可实现:集群服务器之间相互可以ssh免密登录.若只想从单一机器(如master)ssh免密登录其他机器(slave1.slave2),则只跟着操作到第二步即可. 建议先花两三分钟把全文看完再跟 ...

  10. 2019.04.11 第四次训练 【 2017 United Kingdom and Ireland Programming Contest】

    题目链接:  https://codeforces.com/gym/101606 A: ✅ B: C: ✅ D: ✅ https://blog.csdn.net/Cassie_zkq/article/ ...