手写一个 web 服务器!

用python写一个简单的web服务器 人生苦短,我用python简洁高效,这才是理想的语言啊分享一点python的学习经验-----如何用python写一个简单的web服务器首先,我们需要简单地了解一下网络通信协议,这里用白话介绍一下TCP和UDP这两种传输层的协议TCP:通信过程之中每次通信都会进行确认操作,确保报文的安全送达,相当于用对讲机说话,web服务器和客户端就是此采用此协议。UDP:通信之中不需要确认操作,只完成报文的单项... 阅读详情

点击上方“芋道源码”,选择“设为星标”

管她前浪,还是后浪?

能浪的浪,才是好浪!

每天 8:55 更新文章,每天掉亿点点头发...

源码精品专栏

 

前言

作为后端开发人员,在实际的工作中我们会非常高频地使用到web服务器。而tomcat作为web服务器领域中举足轻重的一个web框架,又是不能不学习和了解的。

tomcat其实是一个web框架,那么其内部是怎么实现的呢?如果不用tomcat我们能自己实现一个web服务器吗?

首先,tomcat内部的实现是非常复杂的,也有非常多的各类组件,我们在后续章节会深入地了解。其次,本章我们将自己实现一个web服务器的。

http协议简介

http是一种协议(超文本传输协议),允许web服务器和浏览器通过Internet来发送和接受数据,是一种请求/响应协议。http底层使用TCP来进行通信。目前,http已经迭代到了2.x版本,从最初的0.9、1.0、1.1到现在的2.x,每个迭代都加了很多功能。

在http中,始终都是客户端发起一个请求,服务器接受到请求之后,然后处理逻辑,处理完成之后再发送响应数据,客户端收到响应数据,然后请求结束。在这个过程中,客户端和服务器都可以对建立的连接进行中断操作。比如可以通过浏览器的停止按钮。

http协议-请求

一个http协议的请求包含三部分:

  1. 方法 URI 协议/版本

  2. 请求的头部

  3. 主体内容

举个例子:

POST /examples/default.jsp HTTP/1.1
Accept: text/plain; text/html
Accept-Language: en-gb
Connection: Keep-Alive
Host: localhost
User-Agent: Mozilla/4.0 (compatible; MSIE 4.01; Windows 98)
Content-Length: 33
Content-Type: application/x-www-form-urlencoded
Accept-Encoding: gzip, deflate

lastName=Franks&firstName=Michael

数据的第一行包括:方法、URI、协议和版本。在这个例子里,方法为POST,URI为/examples/default.jsp,协议为HTTP/1.1,协议版本号为1.1。他们之间通过空格来分离。

请求头部从第二行开始,使用英文冒号(:)来分离键和值。

请求头部和主体内容之间通过空行来分离,例子中的请求体为表单数据。

http协议-响应

类似于http协议的请求,响应也包含三个部分。

  1. 协议 状态 状态描述

  2. 响应的头部

  3. 主体内容

举个例子:

HTTP/1.1 200 OK
Server: Microsoft-IIS/4.0
Date: Mon, 5 Jan 2004 13:13:33 GMT
Content-Type: text/html
Last-Modified: Mon, 5 Jan 2004 13:13:12 GMT
Content-Length: 112

<html>
<head>
<title>HTTP Response Example</title> </head>
<body>
Welcome to Brainy Software
</body>
</html>

第一行,HTTP/1.1 200 OK表示协议、状态和状态描述。

之后表示响应头部。

响应头部和主体内容之间使用空行来分离。

Socket

Socket,又叫套接字,是网络连接的一个端点(end point)。套接字允许应用程序从网络中读取和写入数据。两个不同计算机的不同进程之间可以通过连接来发送和接受数据。A应用要向B应用发送数据,A应用需要知道B应用所在的IP地址和B应用开放的套接字端口。java里面使用java.net.Socket来表示一个套接字。

java.net.Socket最常用的一个构造方法为:public Socket(String host, int port);,host表示主机名或ip地址,port表示套接字端口。我们来看一个例子:

Socket socket = new Socket("127.0.0.1", "8080");
OutputStream os = socket.getOutputStream();
boolean autoflush = true;
PrintWriter out = new PrintWriter( socket.getOutputStream(), autoflush);
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputstream()));

// send an HTTP request to the web server
out.println("GET /index.jsp HTTP/1.1");
out.println("Host: localhost:8080");
out.println("Connection: Close");
out.println();

// read the response
boolean loop = true;
StringBuffer sb = new StringBuffer(8096);
while (loop) {
    if (in.ready()) {
        int i=0;
        while (i != -1) {
            i = in.read();
            sb.append((char) i);
        }
        loop = false;
    }
    Thread.currentThread().sleep(50L);
}

这儿通过socket.getOutputStream()来发送数据,使用socket.getInputstream()来读取数据。

ServerSocket

Socket表示一个客户端套接字,任何时候如果你想发送或接受数据,都需要构造创建一个Socket。现在假如我们需要一个服务器端的应用程序,我们需要额外考虑更多的东西。因为服务器需要随时待命,它不清楚什么时候一个客户端会连接到它。在java里面,我们可以通过java.net.ServerSocket来表示一个服务器套接字。

ServerSocket和Socket不同,它需要等待来自客户端的连接。一旦有客户端和其建立了连接,ServerSocket需要创建一个Socket来和客户端进行通信。

ServerSocket有很多的构造方法,我们拿其中的一个来举例子。

public ServerSocket(int port, int backlog, InetAddress bindAddr) throws IOException;
new ServerSocket(8080, 1, InetAddress.getByName("127.0.0.1"));

参数如下:

  1. port 表示端口

  2. backlog 表示队列的长度

  3. bindAddr 表示地址

HttpServer

HttpServer表示一个服务器端入口,提供了一个main方法,并一直在8080端口等待,直到客户端建立一个连接。这时,服务器通过生成一个Socket来对此连接进行处理。

public class HttpServer {

  /** WEB_ROOT is the directory where our HTML and other files reside.
   *  For this package, WEB_ROOT is the "webroot" directory under the working
   *  directory.
   *  The working directory is the location in the file system
   *  from where the java command was invoked.
   */
  public static final String WEB_ROOT =
    System.getProperty("user.dir") + File.separator  + "webroot";

  // shutdown command
  private static final String SHUTDOWN_COMMAND = "/SHUTDOWN";

  // the shutdown command received
  private boolean shutdown = false;

  public static void main(String[] args) {
    HttpServer server = new HttpServer();
    server.await();
  }

  public void await() {
    ServerSocket serverSocket = null;
    int port = 8080;
    try {
      serverSocket =  new ServerSocket(port, 1, InetAddress.getByName("127.0.0.1"));
    }
    catch (IOException e) {
      e.printStackTrace();
      System.exit(1);
    }

    // Loop waiting for a request
    while (!shutdown) {
      Socket socket = null;
      InputStream input = null;
      OutputStream output = null;
      try {
        socket = serverSocket.accept();
        input = socket.getInputStream();
        output = socket.getOutputStream();

        // create Request object and parse
        Request request = new Request(input);
        request.parse();

        // create Response object
        Response response = new Response(output);
        response.setRequest(request);
        response.sendStaticResource();

        // Close the socket
        socket.close();

        //check if the previous URI is a shutdown command
        shutdown = request.getUri().equals(SHUTDOWN_COMMAND);
      }
      catch (Exception e) {
        e.printStackTrace();
        continue;
      }
    }
  }
}

Request对象主要完成几件事情:

  1. 解析请求数据

  2. 解析uri(请求数据第一行)

public class Request {

  private InputStream input;
  private String uri;

  public Request(InputStream input) {
    this.input = input;
  }

  public void parse() {
    // Read a set of characters from the socket
    StringBuffer request = new StringBuffer(2048);
    int i;
    byte[] buffer = new byte[2048];
    try {
      i = input.read(buffer);
    }
    catch (IOException e) {
      e.printStackTrace();
      i = -1;
    }
    for (int j=0; j<i; j++) {
      request.append((char) buffer[j]);
    }
    System.out.print(request.toString());
    uri = parseUri(request.toString());
  }

  private String parseUri(String requestString) {
    int index1, index2;
    index1 = requestString.indexOf(' ');
    if (index1 != -1) {
      index2 = requestString.indexOf(' ', index1 + 1);
      if (index2 > index1)
        return requestString.substring(index1 + 1, index2);
    }
    return null;
  }

  public String getUri() {
    return uri;
  }

}

Response主要是向客户端发送文件内容(如果请求的uri指向的文件存在)。

public class Response {

  private static final int BUFFER_SIZE = 1024;
  Request request;
  OutputStream output;

  public Response(OutputStream output) {
    this.output = output;
  }

  public void setRequest(Request request) {
    this.request = request;
  }

  public void sendStaticResource() throws IOException {
    byte[] bytes = new byte[BUFFER_SIZE];
    FileInputStream fis = null;
    try {
      File file = new File(HttpServer.WEB_ROOT, request.getUri());
      if (file.exists()) {
        fis = new FileInputStream(file);
        int ch = fis.read(bytes, 0, BUFFER_SIZE);
        while (ch!=-1) {
          output.write(bytes, 0, ch);
          ch = fis.read(bytes, 0, BUFFER_SIZE);
        }
      }
      else {
        // file not found
        String errorMessage = "HTTP/1.1 404 File Not Found\r\n" +
          "Content-Type: text/html\r\n" +
          "Content-Length: 23\r\n" +
          "\r\n" +
          "<h1>File Not Found</h1>";
        output.write(errorMessage.getBytes());
      }
    }
    catch (Exception e) {
      // thrown if cannot instantiate a File object
      System.out.println(e.toString() );
    }
    finally {
      if (fis!=null)
        fis.close();
    }
  }
}

总结

在看了上面的例子之后,我们惊奇地发现,在Java里面实现一个web服务器真容易,代码也非常简单和清晰!



欢迎加入我的知识星球,一起探讨架构,交流源码。加入方式,长按下方二维码噢:

已在知识星球更新源码解析如下:

最近更新《芋道 SpringBoot 2.X 入门》系列,已经 20 余篇,覆盖了 MyBatis、Redis、MongoDB、ES、分库分表、读写分离、SpringMVC、Webflux、权限、WebSocket、Dubbo、RabbitMQ、RocketMQ、Kafka、性能测试等等内容。

提供近 3W 行代码的 SpringBoot 示例,以及超 4W 行代码的电商微服务项目。

获取方式:点“在看”,关注公众号并回复 666 领取,更多内容陆续奉上。

兄弟,艿一口,点个赞!????

使用原生java手写一个简单web服务器 最近由于网络编程课程的结课,要求我们写一个大作业,要求使用socket,文件读写以及协议编程写一个项目。我就想着python的nio玩过,但还没怎么用java的nio写一个项目,于是灵机一动,花了将近两天,写了个简单的web服务器。代码方面没有导入其他包,而使用jdk自带工具包。下面看成果图 目录 成果截图 项目结构 实验原理 Connector HTTPRequest HTTPResponse Controller SessionFactory UserSet 成果... 阅读详情

相关推荐

C++ 手写一个WebServer

本文主要详解如何使用C++来实现一个Web服务器,深入详解web服务器原理

余识- 6297

手写简易的web服务器(理解BS架构和CS架构)

手写简易的web服务器(理解BS架构和CS架构)

小丁的博客 454

自己手写web服务器源码

自己手写的一个web服务器,实现了304,Cookie和Session。对于初学web服务器的很有帮助

手写Web服务器(一)

基于HTTP协议协议,使用Java完成Web服务器的编写, 实现网络实时聊天, 通过手写Web服务器, 加深了对于String字符串相关API, IO流, 异常处理, 多线程, 线程池, 反射, 注解, HTTP协议的理解

gtxy_2015的博客 663

手写 tomcat nio

手写 tomcat nio http://knight-black-bob.iteye.com/blog/2408450

webservice例子(纯手写,非转发)

这两天因工作需要,了解了一下webservice,并要搭建一个webservice项目框架. 初步选定 xfire+spring的方式, easy,非常的easy,不需要gen wsdl,而是在runtime自动生成的

手写一个简单的web服务器(B/S架构)

Web服务器是使用HTTP协议与客户端交换信息并为互联网客户提供服务。

IT_WEH_coder的博客 714

别再死磕公式了!用Python+NumPy手把手实现机器人逆运动学数值求解(附避坑指南)

本文详细介绍了如何使用Python和NumPy实现机器人逆运动学(Inverse Kinematics, IK)的数值求解方法,包括牛顿-拉弗森法、雅可比矩阵计算及奇异位形处理。通过实战代码和避坑指南,帮助开发者快速掌握现代机器人学中的核心算法,提升工程实践能力。

weixin_30687051的博客 129

gitlab是一个web服务器嘛_手写一个web服务器 !

前言 作为后端开发人员,在实际的工作中我们会非常高频地使用到web服务器。而tomcat作为web服务器领域中举足轻重的一个web框架,又是不能不学习和了解的。tomcat其实是一个web框架,那么其内部是怎么实现的呢?如果不用tomcat我们能自己实现一个web服务器吗?首先,tomcat内部的实现是非常复杂的,也有非常多的各类组件,我们在后续章节会深入地了解。其次,本章我们将自己实现...

weixin_28808633的博客 179

医院网络设计(完整文档+思科拓扑图)

大家好,我是小华学长,一名计算机领域的博主。经过多年的学习和实践,我积累了丰富的计算机知识和经验,在这里我想与大家分享我的学习心得和技巧,帮助你成为更好的程序员。作为一名计算机博主,我一直专注于编程、算法、软件开发等领域,在这些方面积累了大量的经验。我相信分享是一种双赢的方式,通过分享,我可以帮助他人提升技术水平,同时也能够得到学习交流的机会。在我的文章中,你将会看到我对于各种编程语言、开发工具以及常见问题的解析和分析。我会结合自己的实际项目经验,为你提供实用的解决方案和优化技巧。

qq1325513482的博客 2万+

MUSIC算法翻车?Toeplitz矩阵重构如何解决DOA估计中的相干信源难题

本文深入探讨了MUSIC算法在相干信源DOA估计中失效的根本原因,并详细介绍了基于Toeplitz矩阵重构的协方差矩阵修复技术。该方法通过凸优化恢复协方差矩阵的理想结构,有效解决了信号子空间秩亏损问题,从而显著提升了MUSIC算法在相干和多径场景下的分辨精度与稳健性。

a2b3c4d5e的博客 250

java socket服务器一直接受数据_手写一个web服务器 !

前言 作为后端开发人员,在实际的工作中我们会非常高频地使用到web服务器。而tomcat作为web服务器领域中举足轻重的一个web框架,又是不能不学习和了解的。tomcat其实是一个web框架,那么其内部是怎么实现的呢?如果不用tomcat我们能自己实现一个web服务器吗?首先,tomcat内部的实现是非常复杂的,也有非常多的各类组件,我们在后续章节会深入地了解。其次,本章我们将自己实现...

weixin_31884015的博客 648

飞塔CVE-2022-40684复现

admin 无密码直接回车(会提示修改密码)

G3et的博客 1148

手写一个最迷你的Web服务器

  相信大家对Tomcat服务器应该都很熟悉了,我们几乎每天都会用它,它的安装目录结构大致如下:      今天我们就仿照Tomcat服务器来手写一个最简单最迷你版的web服务器,仅供学习交流。   1. 在你windows系统盘的F盘下,创建一个文件夹webroot,用来存放前端代码。   2. 创建一个简单的Java项目,项目结构如下图:      3. 代码介...

qianfeng_dashuju的博客 1558

Modis数据处理工具:MRT百度网盘下载和手把手图文安装教程

如下图所示为MODIS Reprojection Tool(MRT)的软界面,看似简单,却是Modis遥感影像必不可少的处理工具,如投影变换等。本文以图文并茂的形式,详细讲解MRT软件在Windows10平台上的安装过程,并附MRT软件百度网盘下载地址。 Modis Tool主界面: 一、安装过程 1、安装Java运行环境 双击Java.exe,安装运行环境。默认的安装路径为C:\Program Files (x86)\Java\jre6\bin,后面需要用到这个路径。 等待...

智慧空间实验室 2625

深度学习-161-Dify工具之对比使用工作流和聊天流生成图表可视化的html文件

分别使用聊天流和工作流进行数据分析结果的可视化,生成html文件。聊天流可以配置带记忆,这样就可以多次交互优化结果。

qq_20466211的博客 1709

手写简单Web服务器

Web服务器的主要功能是和浏览器,下面是服务器运行的主要流程。服务器要做的事情就是上面的四个过程。

wr787806的博客 1175

SAP Joule for Developers 全景解析:从 ABAP 到 SAP Build 的一体化开发者 AI 能力

SAP Joule for Developers是一套内嵌于SAP开发工具的设计时AI能力,专为提升SAP开发者效率而设计。它支持自然语言生成应用与自动化流程,帮助理解优化代码,并嵌入单元测试和质量保障功能。Joule深度集成ABAP开发环境,同时服务于Java、JavaScript和低代码开发,覆盖CAP数据模型、UI5/Fiori生成、ABAP代码补全与重构等场景。通过斜杠命令和上下文操作,开发者可在不改变现有平台的前提下,显著提升开发效率和质量。典型案例包括快速构建CAP应用和ABAP Cloud迁移

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 498

手写webserver服务器

手写webserver服务器 文章目录手写webserver服务器前言一、web server执行流程二、代码实现1. Server2.Dispartcher3.Request4.WebApp5.WebContext6.WebHandler7.Entity8.Mapping9.Servlet10.Response11.ResponseResolver12.CloseUtil效果展示总结 前言 webserver 服务器是网络通信必不可少的工具,手写web服务器有助于我们理解网络通信和tomcat这类服务器的

我不会java的博客 1109

基于 ESP32 的智能环境监测与远程报警系统

本系统基于 ESP32 实现了环境数据的采集、远程传输、报警通知功能,硬件成本低、接线简单、代码可直接运行。用户可根据实际需求调整传感器类型(如替换为 PM2.5 传感器、土壤湿度传感器)和功能扩展,适合嵌入式 IoT 入门学习和实际场景应用。通过多轮迭代(如优化低功耗、增加 APP 控制),可进一步提升系统的实用性和稳定性。

weixin_42300449的博客 1025

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

手写Http服务器

你写的一个Html页面,丢到服务器,启动一个Web服务(Tomcat/Nginx),然后大家就可以访问了,为什么? HTTP http是一个简单的请求-响应协议,它通常运行在TCP之上。它指定了客户端可能发送给服务器什么样的消息以及得到什么样的响应。请求和响应消息的头以ASCII码形式给出;而消息内容则具有一个类似MIME的格式。这个简单模型是早期Web成功的有功之臣,因为它使开发和部署非常地直截了当。 HTTP允许Web服务器和浏览器通过网络发送和接收数据,是一种基于【请求-响应】的协议。 说白了HT

程序员小潘 9000

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

web服务器_手写一个web服务器

前言作为后端开发人员,在实际的工作中我们会非常高频地使用到web服务器。而tomcat作为web服务器领域中举足轻重的一个web框架,又是不能不学习和了解的。tomcat其实是一个web框架,那么其内部是怎么实现的呢?如果不用tomcat我们能自己实现一个web服务器吗?首先,tomcat内部的实现是非常复杂的,也有非常多的各类组件,我们在后续章节会深入地了解。其次,本章我们将自己实现一个web服...

weixin_39643189的博客 90

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

手写简易WEB服务器

手写简易WEB服务器 今天我们来写一个类似于Tomcat的简易服务器。可供大家深入理解一下tomcat的工作原理,本文仅供新手参考,请各位大神指正! 首先我们要准备的知识是:   Socket编程   HTML   HTTP协议   服务器编写   反射   XML解析 有了上面的知识,我们可以开始写我们的代码了~~ 1、首先我们要应用Socket编程写一个简单的服务端用来接收服务器端发来的请...

MrLQD 466

手写一个Tomcat服务器

作为java开发者,都知道Tomcat是一个家户喻晓的Web服务器。手写一个Tomcat对我们理解Tomcat的工作原理,还有servlet的执行流程有很大的帮助,下面是我手写一个简要版Tomcat的总结和收获! 首先,先还原Tomcat的本质: 相信大家之前在开发的时候,虽然已经能上手开发web程序,但是对于Servlet的执行流程以及项目还会存在很多疑问,下面是我总结的我之前的疑问也给出相应...

yechengchao的博客 2051

Python小姿势 - 如何用Python实现一个简单的Web服务器

《100天精通Python》专栏,最详细的Python入门到精通教程;理论篇基础知识讲解构建体系框架、实践篇Python黑科技学以致用。https://blog.youkuaiyun.com/weixin_39032019/category_12263598.html

独木不成林,单弦不成音。 3517
上一篇: 为什么阿里云要做流批一体?
下一篇: 推荐 5 款好用的 REST API 工具
公众号-芋道源码
博客等级 码龄10年 1636粉丝 377原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值