在前面,我们已经可以实现游览器和服务器之间的通讯了,但是由于这是一个单线程的程序,所以运行效率低下。现在我们来对程序进行改进,我们让服务器每接收到一个请求就创建一个新的线程来处理请求。
我们对上次代码进行改进。首先先创建一个类来实现Runnable接口实现多线程。
public class RequestHandler implements Runnable{
}
然后在这个类里面定义一个Socket成员属性,并且创建一个构造器来对Socket进行初始化
//定义一个socket对象
private Socket socket = null;
//在初始化对象时传入socket
public RequestHandler(Socket socket) {
this.socket = socket;
}
实现Runnable接口的run方法
@Override
public void run() {
//对请求进行处理
}
我们在这里最重要的是要先实现多线程,其它的实现后面再做。所以我们直接把上一次写的对响应处理的代码部分复制过来即可。然后进行一些简单异常处理。
现在我们和上次一样来创建一个类在8080端口进行循环监听
//得到ServerSocket,在8080端口进行监听
ServerSocket serverSocket = new ServerSocket(8080);
System.out.println("---------服务器启动成功----------");
while (!serverSocket.isClosed()) {
}
等待客服端的连接
//等待连接
Socket socket = serverSocket.accept();
如果有连接,那么我们就创建一个新线程进行处理
//创建一个线程来处理请求
RequestHandler requestHandler = new RequestHandler(socket);
new Thread(requestHandler).start();
完整代码如下
import com.clucky.myTomcat.thread.RequestHandler;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class MyTomcat02 {
public static void main(String[] args) {
try {
//得到ServerSocket,在8080端口进行监听
ServerSocket serverSocket = new ServerSocket(8080);
System.out.println("---------服务器启动成功----------");
while (!serverSocket.isClosed()) {
System.out.println("-------------------------------------------------");
System.out.println("等待连接");
//等待连接
Socket socket = serverSocket.accept();
System.out.println("连接成功");
//创建一个线程来处理请求
RequestHandler requestHandler = new RequestHandler(socket);
new Thread(requestHandler).start();
}
} catch (IOException e) {
System.out.println("服务器启动失败");
}
}
}
import java.io.*;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
public class RequestHandler implements Runnable{
//定义一个socket对象
private Socket socket = null;
//在初始化对象时传入socket
public RequestHandler(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
System.out.println(Thread.currentThread().getName()+"线程开启成功,开始处理数据");
//得到输入流
InputStream inputStream = socket.getInputStream();
//将字节输入流转为字符输入流。并将编码设置为utf-8
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(inputStream, StandardCharsets.UTF_8));
String line = null;
//循环读取
System.out.println("开始读取内容");
while ((line = bufferedReader.readLine()) != null) {
//如果为空就结束读取
if (line.length() == 0) break;
System.out.println(line);
}
System.out.println("读取内容结束");
//得到输出流
OutputStream outputStream = socket.getOutputStream();
//设置响应头
String responseHead = "HTTP/1.1 200\r\n" +
"Content-Type: text/html;charset=utf-8\r\n\r\n";
//设置响应体
String responseBody = "<h1>这是我自己写的Tomcat</h1>";
//http响应消息内容
String response = responseHead + responseBody;
//写回数据
outputStream.write(response.getBytes());
System.out.println("响应成功");
//关闭流
outputStream.close();
inputStream.close();
socket.close();
System.out.println("本次连接结束,正常关闭socket");
System.out.println("-------------------------------------------------\n");
} catch (IOException e) {
e.printStackTrace();
} finally {
//保证一定关闭socket
if (!socket.isClosed()){
try {
socket.close();
} catch (IOException e) {
System.out.println("socket关闭失败");
}
}
}
}
}
测试
我们开启服务器后像上次那样使用游览器(Firefox)进行访问。
第一次访问游览器显示为
控制台输出为
显示开启了一个线程,线程名称为Thread-0。
我们第二次访问,查看控制台输出
可以看见,线程名称为Thread-1,确实是一个新的线程,如果我们多次访问,那么就会开启多个线程。