当前位置:网站首页>手写一个简单的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 效果展示
边栏推荐
- Chapter Six
- Dry goods | 10 tips for MySQL add, delete, change query performance optimization
- 网易云信圈组上线实时互动频道,「破冰」弱关系社交
- LevelSequence source code analysis
- BM3 将链表中的节点每k个一组翻转
- A high-quality WordPress download site template theme developed abroad
- Douyin fetches video list based on keywords API
- One thing to say, is outsourcing company worth it?
- 10大主流3D建模技术
- BM3 flips the nodes in the linked list in groups of k
猜你喜欢
Daily practice——Randomly generate an integer between 1-100 and see how many times you can guess.Requirements: The number of guesses cannot exceed 7 times, and after each guess, it will prompt "bigger"
Realize serial port receiving data based on STM32 ring queue
20. Support vector machine - knowledge of mathematical principles
21. Support Vector Machine - Introduction to Kernel Functions
Go1.18 upgrade function - Fuzz test from scratch in Go language
Chapter Six
Document management and tools in the development process
Go mode tidy reports an error go warning “all” matched no packages
Bionic caterpillar robot source code
顺序表的实现
随机推荐
Unity-LineRenderer显示一条线
The old music player WinAmp released version 5.9 RC1: migrated to VS 2019, completely rebuilt, compatible with Win11
标段参数说明
Verilog implements a divide-by-9 with a duty cycle of 5/18
「SDOI2016」征途 题解
How to debug TestCafe
【公开课预告】:超分辨率技术在视频画质增强领域的研究与应用
Transfer Learning - Domain Adaptation
利用反射实现一个管理对象信息的简单框架
支付模块实现
NVIDIA has begun testing graphics products with AD106 and AD107 GPU cores
「SDOI2016」征途 题解
LevelSequence source code analysis
TypeScript 的组件
UserAgent resolution
Istio introduction
Embedded development has no passion, is it normal?
The difference between adding or not adding the ref keyword when a variable of reference type is used as a parameter in a method call in C#
cas and spin locks (is lightweight locks spin locks)
How to identify fake reptiles?