当前位置:网站首页>手写一个简单的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 效果展示

边栏推荐
- [Code Hoof Set Novice Village 600 Questions] Merge two numbers without passing a character array
- A solution to the server encountered an internal error that prevented it from fulfilling this request [easy to understand]
- 【ACM】2022.7.31训练赛
- Qualcomm cDSP simple programming example (to query Qualcomm cDSP usage, signature), RK3588 npu usage query
- Fixed-length usage of nanopb string type based on RT1052 Aworks (27)
- How to get useragent
- 角色妆容的实现
- AI automatic code writing plugin Copilot (co-pilot)
- Redis综述篇:与面试官彻夜长谈Redis缓存、持久化、淘汰机制、哨兵、集群底层原理!...
- How to identify fake reptiles?
猜你喜欢

Federated Learning: Multi-source Knowledge Graph Embedding in Federated Scenarios

ReentrantLock原理(未完待续)

登录业务实现(单点登录+微信扫码+短信服务)

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
I don't know what to do with sync issues

The principle of ReentrantLock (to be continued)

Chapter Six

20. Support vector machine - knowledge of mathematical principles

架构实战营模块 8 作业
随机推荐
Go1.18 upgrade function - Fuzz test from scratch in Go language
sqlite3 simple operation
I don't know what to do with sync issues
嵌入式开发没有激情了,正常吗?
如何减少软件设计和实现之间鸿沟
Unity-LineRenderer显示一条线
数据分析(一)——matplotlib
The principle of ReentrantLock (to be continued)
Dry goods | 10 tips for MySQL add, delete, change query performance optimization
Student management system on the first day: complete login PyQt5 + MySQL5.8 exit the operation logic
Quick Start Tutorial for flyway
老牌音乐播放器 WinAmp 发布 5.9 RC1 版:迁移到 VS 2019 完全重建,兼容 Win11
spark reports an error OutOfMemory "recommended collection"
The latest masterpiece!Alibaba just released the interview reference guide (Taishan version), I just brushed it for 29 days
C#中引用类型的变量做为参数在方法调用时加不加 ref 关键字的不同之处
Golang must know the Go Mod command
Basic Grammar Introduction of Carbon Tutorial (Tutorial)
高通cDSP简单编程例子(实现查询高通cDSP使用率、签名),RK3588 npu使用率查询
iNeuOS industrial Internet operating system, equipment operation and maintenance business and "low-code" form development tools
One thing to say, is outsourcing company worth it?