一、背景
目前的HTTP服务器很多,只要是编程语言支持线程和网络通信,就能开发一个HTTP协议服务器。
市场上常用的是Tomcat、Ngnix、Httpd等技术。
二、本文目的
介绍使用Java语言来开发HTTP服务器的处理逻辑。
这是个人可以参考的HTTP服务器通用逻辑。
三、工作线程的执行逻辑如下
(一)Java.net.Socket的阻塞式处理
1、从accept()方法处获取Socket对象。
2、获取输入和输出流。
3、进入循环处理:
while(true){
3.1 判断是否关闭和失去连接,如果任意满足,退出循环。
// 3.2 调用setSoTimeout()方法设置读取超时。
socket.setSoTimeout(3000);
// 3.3 调用readRequest()方法读取请求,获得请求对象request。
// 3.4 调用doResponse(out, request)处理方法,把请求对象传入处理请求。
// 3.5 判断是否为长连接,否则退出循环
}
// 4、关闭套接字
socket.close()
(二)java.nio.channel.SocketChannel的非阻塞式处理
1、当Selector获取一个通道满足可连接要求。
2、处理可连接事件,注册可读取事件。
3、当满足可读取事件,开始处理读取事件:
while(True){
// 3.1循环读取请求
while(True){
// 3.1.1读取一次数据到缓冲里
int size = chnnel.read(buffer);
// 3.1.2如果size为0,退出循环。
// 说明当前没有数据可读
if(size== 0){
break;
}
// 3.1.3翻转,用来读取
buffer.flip();
// 3.1.4把缓存数据写入请求对象中,用来构造请求
request.addData(buffer);
// 3.1.5清除缓冲
buffer.clear();
}
// 3.2结束请求的数据,开始解析
// 是否需要判断请求是否读取完整?有没有到读取空行
request.end()
// 3.3开始处理响应,传入请求对象
doResponse(request);
// 3.4判断当前连接还存在,失去连接就退出循环
if(失去连接 || 已关闭){
break;
}
// 3.5判断是否为长连接,不是则退出循环
// 3.6设置读取超时时间,防止长时间保持
}
// 4、关闭该通道
// 5、从Selector中移除通道注册
三、注意
1、上述的一些Request和Response对象是自定义的,内部有一些读写方法和其他方法,按照HTTP协议的格式来处理。
2、readRequest和doResponse方法是用户自定义实现的,作用分别是读取请求,返回请求对象;作出响应。
3、其他的都是系统库提供的方法。
例如Socket的方法,InputStream和OutputStream提供的方法。
4、非阻塞读取请求时,不好判断是否把请求全部读取完成了,因为不会阻塞等待,没有数据读取会返回整型数字0。
5、一些变量都是假设定义的。
例如ByteBuffer类型的buffer变量,Socket的socket对象,SocketChannel的channel变量等等。
6、如果想改成一种Servlet容器,只需要用反射生成Servlet对象,生成官方的请求和响应类,传入后执行服务方法。