接上一篇文章:java自建服务器
封装分发器_实现多线程
思路:
一个服务器,可能有多个客户端向其提交访问请求,所以这个服务器需要一直处于待机状态,每一个客户端请求和服务器响应都可能是不同的,所以我们创建一个类:Dispatcher类
开始修改
Server类的receive方法里,使用
Request req=new Request(client.getInputStream());获取请求
使用Response rep=new Response(client.getOutputStream());去获取响应,我们在Dispatcher类内将请求和响应的获取和发送进行封装
所以,我们也会对原有的Server类的receive方法做出一些改动
原来的start()方法和receive()方法
//启动服务的方法 -- port是指端口
public void start(int port){
try {
//启动服务
server = new ServerSocket(port);
//检测是否有客户机发送请求
this.receive();//调用接收信息的方法
} catch (IOException e) {
e.printStackTrace();
}
}
//接收服务
private void receive() {
try {
//监听
Socket client = server.accept();
//获取用户的请求 封装请求信息
Request req=new Request(client.getInputStream());
req.show();
/**做出响应*/
//调用封装后的响应方法
Response rep=new Response(client.getOutputStream());
//调用webApp类的servlet对象
Servlet servlet=WebApp.getServlet(req.getUrl());
int code=200;
if (servlet==null) {
code=404;
}
//调用Servlet中的服务的方法
try {
servlet.service(req, rep);
} catch (Exception e) {
e.printStackTrace();
}
rep.pushToClient(code);
IOCloseUtil.closeAll(client);
} catch (IOException e) {
e.printStackTrace();
}
}
封装一个分发器,去创建一个多线程类:
package bjsxt.server;
import bjsxt.servlet.Servlet;
import bjsxt.util.IOCloseUtil;
import java.io.IOException;
import java.net.Socket;
/**
* 一个请求和一个响应就是一个Dispatcher
* 为其添加多线程的操作能力,添加Runnable接口
*
* 在Server类内,使用 Request req=new Request(client.getInputStream());获取请求
* 使用Response rep=new Response(client.getOutputStream());获取响应
*/
public class Dispatcher implements Runnable{
private Request req;
private Response rep;
private Socket client;
private int code = 200;//状态码
//构造方法初始化属性
public Dispatcher(Socket client){
//将局部变量的值赋给成员变量
this.client = client;
try {
req = new Request(this.client.getInputStream());
rep = new Response(this.client.getOutputStream());
} catch (IOException e) {
code=500;
return;
}
}
@Override
public void run() {
System.out.println("输出url:"+req.getUrl());
//根据不同的url创建指定的Servlet对象
Servlet servlet = WebApp.getServlet(req.getUrl());
if (servlet==null){
this.code=404;
}else{
//调用相应的Servlet中的service方法
try {
servlet.service(req,rep);
} catch (Exception e) {
this.code=500;
}
}
//将响应结果推送到客户机的浏览器
rep.pushToClient(code);
IOCloseUtil.closeAll(client);
}
}
在Server内创建一个boolean类型的变量
private boolean isShutDown = false;//默认没有出错
修改start方法和receive方法:
对start方法启动服务时出现异常时如何处理进行修改
在receive方法内:
创建多线程对象
完善关闭服务器的方法stop()
//启动服务的方法 -- port是指端口
public void start(int port){
try {
//启动服务
server = new ServerSocket(port);
//检测是否有客户机发送请求
this.receive();//调用接收信息的方法
} catch (IOException e) {
isShutDown=true; //出现错误时,isShutDown为true
}
}
//接收服务
private void receive() {
try {
while (!isShutDown){//使用循环时刻监听是否有客户级的浏览器发送请求,在没有出现错误的情况下循环
//监听
Socket client = server.accept();
//创建线程类的对象
Dispatcher dis = new Dispatcher(client);
//创建代理类并启动线程
new Thread(dis).start();
}
} catch (IOException e) {
//在使用请求与相应时出现错误
this.stop();//将服务器关闭
}
}
//关闭服务器的方法 -- 这里的IOCloseUtil方法来自bjsxt.util包下
public void stop(){
isShutDown=true;
IOCloseUtil.closeAll(server);
}
Server类最后修改结果:
package bjsxt.server;
import bjsxt.util.IOCloseUtil;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
/**
* 服务器,用于启动和停止服务
*/
public class Server {
private ServerSocket server;
private boolean isShutDown = false;//默认没有出错
public static void main(String[] args) {
Server server = new Server();
server.start();
}
public void start(){
this.start(9999);
}
//启动服务的方法 -- port是指端口
public void start(int port){
try {
//启动服务
server = new ServerSocket(port);
//检测是否有客户机发送请求
this.receive();//调用接收信息的方法
} catch (IOException e) {
isShutDown=true; //出现错误时,isShutDown为true
}
}
//接收服务
private void receive() {
try {
while (!isShutDown){ //使用循环时刻监听是否有客户级的浏览器发送请求,在没有出现错误的情况下循环
//监听
Socket client = server.accept();
//创建线程类的对象
Dispatcher dis = new Dispatcher(client);
//创建代理类并启动线程
new Thread(dis).start();
}
} catch (IOException e) {
//在使用请求与相应时出现错误
this.stop();//将服务器关闭
}
}
//关闭服务器的方法
public void stop(){
isShutDown=true;
IOCloseUtil.closeAll(server);
}
}
实现效果
当我们启动Server服务器类后,在浏览器第一次输入用户名和密码之后,自建服务器不会关闭,会一直运行
进行整合
本次整合,是将两个博文进行结合,对自建服务器的项目进行的一个整合
输出时多出一个/favicon.ico路径
关于这个路径为什么会出现,我们可以参考这个博文的解说
https://www.cnblogs.com/LoveJenny/archive/2012/05/22/2512683.html
下面,我们开始解决这个问题
原因分析
因为这个图标没有在XML内进行配置,没有对应的Servlet,所以就出现了一个空指针异常
开始解决
配置XML
<?xml version="1.0" encoding="UTF-8" ?>
<web-app>
<!--
这里是以前的xml设置
-->
<!-- 解决无法解析请求到的资源路径/favicon.ico报的空指针异常的问题 -->
<servlet>
<servlet-name>favicon</servlet-name>
<servlet-class>bjsxt.servlet.faviconServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>favicon</servlet-name>
<url-pattern>/favicon.ico</url-pattern>
</servlet-mapping>
</web-app>
在bjsxt.servlet包下,添加一个faviconServlet类:
package bjsxt.servlet;
import bjsxt.server.Request;
import bjsxt.server.Response;
public class faviconServlet extends Servlet{
@Override
public void doGet(Request req, Response rep) throws Exception {
}
@Override
public void doPost(Request req, Response rep) throws Exception {
}
}
再次提交运行,异常被解决
至此,我们的服务器整合结束