当前位置:网站首页>手写一个简单的web服务器(B/S架构)
手写一个简单的web服务器(B/S架构)
2022-07-31 22:22:00 【IT_WEH_coder】
涉及Web服务器的相关技术
IO流、Socket网络编程、HTTP协议、文件、多线程(同时处理多个浏览器的请求)、List集合
1 web应用服务器运行原理:
连接过程:Web服务器与其浏览器之间建立的连接,判定两者之间是否连接成功;若用户可以找到并打开虚拟文件套接字,说明Web服务器与其浏览器之间成功建立了连接。
请求过程:Web浏览器利用socket文件向其服务器发出各种请求。
获取请求资源的地址
根据是静态资源还是动态资源做出相应的处理
响应过程:在请求过程中发出的请求通过使用HTTP协议传输到Web服务器,然后执行任务处理。
关闭连接:响应过程完成后,Web服务器与其浏览器断开连接的过程。
2 代码展示
(1)Main类
package com.weh;
import com.weh.httpserver.MyHttpServer;
public class Main {
// 开启多线程
public static void main(String[] args) {
new Thread(new MyHttpServer()).start();
}
}
(2)MyHttpServer类
package com.weh.httpserver;
import com.weh.response.MyResponse;
import com.weh.request.MyRequest;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
/* * 1.通过Runnable接口的实现类,来开启线程 * 2.创建并开启服务器 * 3.实现服务端与客户端进行连接通信 * */
public class MyHttpServer implements Runnable{
public static final int port = 8080; //服务器端口号
public static final String WEB_ROOT=System.getProperty("user.dir")+
File.separator+ "webapps"; //服务器的当前文件目录路径
@Override
public void run() {
ServerSocket serverSocket=null;
Socket socket;
InputStream input=null;
OutputStream output=null;
try {
System.out.println("Web服务器已开启");
serverSocket = new ServerSocket(port); //传入端口号并创建服务器
} catch (Exception e) {
System.exit(0);
}
//服务端与客户端浏览器进行通信
while(true){
try {
socket=serverSocket.accept();//请求
input=socket.getInputStream();//获取客户端发过来信息
output=socket.getOutputStream();
MyRequest request=new MyRequest(input); //数据处理
request.parse();
MyResponse response=new MyResponse(output);
response.setMyRequest(request);
response.sendStaticResource();//发送
} catch (Exception e) {
e.printStackTrace();
continue;
}finally {
// 释放资源
release(input,output);
}
}
}
// 释放资源
public void release(InputStream inputStream,OutputStream outputStream){
try {
if(inputStream != null) {
inputStream.close();
}
if(outputStream != null){
outputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
(3)MyRequest类
package com.weh.request;
import java.io.InputStream;
/* * 自定义MyRequest类 * 1.主要处理客户端发过来的信息进行处理并输出 * 2.获取客户端切换到哪个文件的名称 * */
public class MyRequest {
private InputStream input;
private String uri;
public MyRequest(InputStream input){
this.input=input;
}
// 输出客户端发过来的信息
public void parse(){
StringBuffer request=new StringBuffer(2048);
int len;
byte[] buffer=new byte[2048];
try {
len=input.read(buffer);
} catch (Exception e) {
len=-1;
}
for(int j=0;j<len;j++){
request.append((char)buffer[j]);
}
System.out.print(request.toString());
parseUri(request.toString());
}
// 获取切换后的文件名
public void parseUri(String srt){
int index1,index2;
index1=srt.indexOf(" ");
if(index1!=-1){
index2=srt.indexOf(" ",index1+1);
if(index2>index1){
setUri(srt.substring(index1+1,index2));
}
}
}
public void setUri(String uri) {
this.uri = uri;
}
public String getUri(){
return this.uri;
}
}
(4)MyResponse类
package com.weh.response;
import com.weh.httpserver.MyHttpServer;
import com.weh.request.MyRequest;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.List;
/* * 自定义MyResponse类 * 1.向Socket的输出流中写请求给浏览器作出响应的结果 * 2.获取当前目录下的所有文件并创建文件类型的数组 * 3.数据的读取及转发 * */
public class MyResponse {
private static final int BUFFER_SIZE=1024;
MyRequest request;
OutputStream output;
FileInputStream fis=null;
PrintWriter printWriter =null;
public MyResponse(OutputStream output){
this.output=output;
}
public void setMyRequest(MyRequest request){
this.request=request;
}
public void sendStaticResource()throws IOException{
byte[] bytes=new byte[BUFFER_SIZE];
try {
printWriter = new PrintWriter(output); //创建缓冲字符输出流
File file=new File(MyHttpServer.WEB_ROOT+request.getUri());
if(file.exists()){
//判断文件目录是否存在
//向Socket的输出流中写请求给浏览器作出响应的结果
printWriter.println("HTTP/1.1 200 OK");
printWriter.println("Content-Type:text/html;charset=UTF-8");
printWriter.println();
// 判断文件是否为普通文件
if(file.isFile()){
fis=new FileInputStream(file.getPath()); //创建文件字节输入流
fis.read(bytes); //读取直接流
printWriter.write(new String(bytes));
// 判断文件是否为文件目录
}else if(file.isDirectory()){
List<File> list= Arrays.asList(new File(file.getPath()).listFiles());//获取当前目录下的所有文件并创建文件类型的数组
for(File filename : list){
//数组遍历
if(filename.getName().indexOf(".htm")>0) {
//判断是否含有.htm的字符的文件
printWriter.write("<li>");
printWriter.write("<a style='text-decoration:blink;' href='" +
"./" + filename.getName() + "'>"
+ filename.getName() + "</a>");
printWriter.write("</li>");
}
}
}
// 若该文件不存在,则输出信息 File Not Found
}else{
printWriter.println("HTTP/1.1 404 File Not Found");
printWriter.println("Content-Type:text/html;charset=UTF-8");
printWriter.println("Content-Length:23");
printWriter.println();
printWriter.write("<h1>File Not Found</h1>");
}
printWriter.flush();//不返回任何值,只用于刷新流
} catch (Exception e) {
e.printStackTrace();
}finally{
if(printWriter!=null){
printWriter.close();
}
if(output!=null){
output.close();
}
if(fis!=null){
fis.close();
}
}
}
}
3项目的结构设计
4 效果展示
边栏推荐
猜你喜欢
How to reduce the gap between software design and implementation
Pytest初体验
TestCafeSummary
Collation of knowledge points in Ningbo University NBU IT project management final exam
The article you worked so hard to write may not be your original
Golang - from entry to abandonment
Financial profitability and solvency indicators
Architecture Battalion Module 8 Homework
Summary of the classic drawing method of histogram
Flink_CDC construction and simple use
随机推荐
Dry goods | 10 tips for MySQL add, delete, change query performance optimization
Document management and tools in the development process
focus on!Haitai Fangyuan joins the "Personal Information Protection Self-discipline Convention"
不知道该怎么办的同步问题
The old music player WinAmp released version 5.9 RC1: migrated to VS 2019, completely rebuilt, compatible with Win11
了解下C# 匿名方法
20. Support vector machine - knowledge of mathematical principles
Count characters in UTF-8 string function
The principle of ReentrantLock (to be continued)
linux view redis version command (linux view mysql version number)
Go mode tidy reports an error go warning “all” matched no packages
Memblaze发布首款基于长存颗粒的企业级SSD,背后有何新价值?
Pytest first experience
TestCafeSummary
基于RT1052 Aworks nanopb string 类型固定长度使用方式(二十七)
标段参数说明
【Yugong Series】July 2022 Go Teaching Course 025-Recursive Function
Pytorch lstm time series prediction problem stepping on the pit "recommended collection"
Transfer Learning - Domain Adaptation
Basic Grammar Introduction of Carbon Tutorial (Tutorial)