最近学习了Java NIO技术,觉得不能再去写一些Hello World的学习demo了,而且也不想再像学习IO时那样编写一个控制台(或者带界面)聊天室。我们是做WEB开发的,整天围着tomcat、nginx转,所以选择了一个新的方向,就是自己开发一个简单的Http服务器,在总结Java NIO的同时,也加深一下对http协议的理解。

项目实现了静态资源(html、css、js和图片)和简单动态资源的处理,可以实现监听端口、部署目录、资源过期的配置。涉及到了NIO缓冲区、通道和网络编程的核心知识点,还是比较基础的。

本文是这个系列文章的最后一篇,主要介绍HttpServer类,该类作用是:

  • 打开Selector和ServerSocketChannel,根据HttpServerConfig配置启动监听
  • 接收请求连接
  • 开启线程读取请求数据、处理请求

文章目录:

NIO开发Http服务器(1):项目下载、打包和部署

NIO开发Http服务器(2):项目结构

NIO开发Http服务器(3):核心配置和Request封装

NIO开发Http服务器(4):Response封装和响应

NIO开发Http服务器(5-完结):HttpServer服务器类

Github地址:

https://github.com/xuguofeng/http-server

1、启动监听

 selector = Selector.open();

 // 打开服务端socket通道
ServerSocketChannel ssc = ServerSocketChannel.open();
// 设置非阻塞
ssc.configureBlocking(false);
// 绑定本地端口
ssc.bind(new InetSocketAddress(config.getServerPort()));
// 把通道注册到Selector
ssc.register(selector, SelectionKey.OP_ACCEPT);

2、轮询

 while (true) {

     int s = selector.select();
// 如果没有就绪的通道直接跳过
if (s <= 0) {
continue;
}
// 获取已经就绪的通道的SelectionKey的集合
Iterator<SelectionKey> i = selector.selectedKeys().iterator(); while (i.hasNext()) { // 获取当前遍历到的SelectionKey
SelectionKey sk = i.next(); // 可连接状态
if (sk.isValid() && sk.isAcceptable()) { } else if (sk.isValid() && sk.isReadable()) {// 可读取状态 }
i.remove();
}
}

3、接收和读取请求数据

接收请求

 ServerSocketChannel server = (ServerSocketChannel) sk.channel();
SocketChannel clientChannel;
try {
// 获取客户端channel
clientChannel = server.accept();
// 设置非阻塞
clientChannel.configureBlocking(false);
// 把通道注册到Selector
clientChannel.register(selector, SelectionKey.OP_READ);
} catch (Exception e) {
}

读取数据

 // 获取通道
SocketChannel sChannel = (SocketChannel) sk.channel();
if (socketChannels.get(sChannel.hashCode()) == null) {
socketChannels.put(sChannel.hashCode(), sChannel);
tp.execute(new RequestHandler(sk));
}

4、请求处理

这是这个类的核心内容,使用RequestHandler处理请求

具体实现如下:

  • 从输入通道读取数据,根据配置的解码字符集进行解码
  • 创建Request对象
  • 尝试根据uri获取动态请求处理类,如果是动态请求,就实例化Servlet对象,调用service方法处理请求
  • 输出响应
  • 最后关闭客户端输出通道
 SocketChannel sChannel = null;
try {
// 获取通道
sChannel = (SocketChannel) sk.channel();
// 声明保存客户端请求数据的缓冲区
ByteBuffer buf = ByteBuffer.allocate(8192);
// 读取数据并解析为字符串
String requestBody = null;
int len = 0;
if ((len = sChannel.read(buf)) > 0) {
buf.flip();
requestBody = new String(buf.array(), 0, len);
buf.clear();
}
if (requestBody == null) {
return;
} // 请求解码
requestBody = URLDecoder.decode(requestBody, config.getRequestCharset()); // 创建请求对象
Request req = new HttpRequest(requestBody); // 关闭输入
sChannel.shutdownInput(); // 根据uri获取处理请求的Servlet类型
Class<? extends Servlet> servletClass = config.getServlet(req.getRequestURI()); // 创建响应对象
Response resp = null; // 动态请求
if (servletClass != null) {
try {
Servlet servlet = servletClass.newInstance();
resp = new HttpResponse(sChannel);
servlet.service(req, resp);
resp.setResponseCode(ResponseUtil.RESPONSE_CODE_200);
} catch (Exception e) {
resp.setResponseCode(ResponseUtil.RESPONSE_CODE_500);
}
} else {
// 静态请求
resp = new HttpResponse(req, sChannel);
} // 测试,添加cookie
if (req.getCookies().isEmpty()) {
Cookie c = new Cookie("sessionId", UUID.randomUUID().toString(), 60000);
resp.addCookie(c);
Cookie c2 = new Cookie("sessionId2", UUID.randomUUID().toString(), 60000);
resp.addCookie(c2);
} // 输出响应
resp.response(); } catch (IOException e) {
} finally {
// 关闭通道
try {
sChannel.finishConnect();
sChannel.close();
socketChannels.remove(sChannel.hashCode());
} catch (IOException e) {
}
}

5、Servlet接口

处理动态请求的接口,实现类需要在service方法中编写业务处理的程序

 public interface Servlet {

     void service(Request request, Response response) throws Exception;
}

然后在server.properties文件配置

NIO开发Http服务器(5-完结):HttpServer服务器类的更多相关文章

  1. NIO开发Http服务器(4):Response封装和响应

    最近学习了Java NIO技术,觉得不能再去写一些Hello World的学习demo了,而且也不想再像学习IO时那样编写一个控制台(或者带界面)聊天室.我们是做WEB开发的,整天围着tomcat.n ...

  2. NIO开发Http服务器(3):核心配置和Request封装

    最近学习了Java NIO技术,觉得不能再去写一些Hello World的学习demo了,而且也不想再像学习IO时那样编写一个控制台(或者带界面)聊天室.我们是做WEB开发的,整天围着tomcat.n ...

  3. NIO开发Http服务器(2):项目结构

    最近学习了Java NIO技术,觉得不能再去写一些Hello World的学习demo了,而且也不想再像学习IO时那样编写一个控制台(或者带界面)聊天室.我们是做WEB开发的,整天围着tomcat.n ...

  4. NIO开发Http服务器(1):项目下载、打包和部署

    最近学习了Java NIO技术,觉得不能再去写一些Hello World的学习demo了,而且也不想再像学习IO时那样编写一个控制台(或者带界面)聊天室.我们是做WEB开发的,整天围着tomcat.n ...

  5. 开发环境运行正常,发布服务器后提示HTTP 错误 403.14 - Forbidden

    一.发布服务器后报错 今天在项目发布中遇到一件奇怪的事,开发完成的项目,发布到服务器上时 1. 发布到A服务器,一切正常 2. 发布到B服务器,提示403服务器错误 在同事电脑上重新打包发布代码,并发 ...

  6. 微信公众平台消息接口开发(2)你的服务器没有正确响应Token验证的解决方法

    你的服务器没有正确响应Token验证,请阅读消息接口使用指南 微信 微信公众平台开发模式 平台 消息 接口 启用 URL Token作者:http://txw1958.cnblogs.com/ 本系统 ...

  7. bladex开发自己的服务不推送服务器的方法

    一:问题 使用代码生成器 生成的代码,运行后,需要推送至服务器才可以进行调试,每次推送,启动服务至少半个小时以上,相当浪费时间,如何可以让开发的服务不推送至服务器能调试呢? 二:尝试解决 直接开发机运 ...

  8. java微信开发(wechat4j)——access_token中控服务器实现

    access_token是与微信服务器交互过程中的一个凭证,每次客户服务器主动与微信服务器通信都需要带上access_token以确认自己的身份.wechat4j内部封装了对access_token的 ...

  9. JAVAEE 和项目开发(第六课:服务器的安装和目录介绍和闪退解决办法)

    课程介绍: 在学习了 HTTP 协议后,我们对浏览器和服务器的交互流程以及规范有了一定程度的认知,并也有了自己的理解.但是不少同学对服务器的概念还是有些模糊的,那么本节课就针对服务器进行介绍,我们一起 ...

随机推荐

  1. 第08组 Alpha冲刺(2/4)

    队名 八组评分了吗 组长博客 小李的博客 作业博客 作业链接 组员1李昕晖(组长) 过去两天完成了哪些任务 文字/口头描述 11月17日了解各个小组的进度与难以攻破的地方,与隔壁第七组组长讨论进度发展 ...

  2. 在linux上安装运行安卓系统

    一. 环境 Ubuntu 二. 安装QEMU $sudo apt-get install qemu qemu-kvm libvirt-bin 三. 创建虚拟硬盘文件,将安卓安装在此虚拟硬盘上 $qem ...

  3. SNF快速开发平台2019-角色、权限、账户的概念理解-非常全的理论讲解权限控制

    组织模型   资源模型  操作模型 谁能够执行哪些操作    执行资源的范围 资源概念资源就是想要的到的最终物质,我们可以给每一个资源定义一个权限,也可以给某一类资源定义一个权限 权限概念权限是对资源 ...

  4. jQuery-webcam使用

    基本页面 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta ...

  5. C# Selenium操作指南,关闭黑色CMD窗口/禁用图片/隐藏浏览器等

    引用部分:1. 2. 配置部分: ChromeDriverService driverService = ChromeDriverService.CreateDefaultService(); dri ...

  6. js session失效退出iframe

    // 代码加入登陆页面中 if( window.top != window.self ){ window.top.location = window.location.href; }

  7. Vue基础知识学习笔记

    一.环境搭建1.安装nodejs ((https://nodejs.org/en/)2.安装脚手架 npm install --global vue-cli /cnmp install --globa ...

  8. Operation之算数&聚合操作符

    toArray 该操作符先把一个序列转成一个数组, 并作为一个单一的事件发送, 然后结束 Observable.of(1,2,3,4) .toArray() .subscribe(onNext: { ...

  9. 关于aardio修改注册表默认键值的问题(转)

    今天用aardio做注册表练习  遇到一个问题.  就是不知道怎么用aardio修改已存在的默认的注册表键的值.. 导出注册信息看了一下 默认的和普通的键值不太一样  形式是  @="要写入 ...

  10. EasyNVR摄像机网页无插件直播方案H5前端构建之:区分页面是自跳转页面还是分享页面

    背景分析 EasyNVR整套方案的架构中,涉及到前端设备(摄像机IPC.硬盘录像机NVR.编码器等).流媒体服务端(EasyNVR).客户端终端设备(PC.浏览器.Android.iOS.微信). 在 ...