【JavaWeb】一个简单的Web浏览服务程序

大家天天开心!!!!!

文章目录

  • 前言
  • 一、一个简单的Web浏览服务程序
  • 二、对以上代码的解释:
    • 1.ServerSocket和Socket的生动比喻:
    • 2.网络通信的"公司大楼"模型
    • 重点概念详解
    • 常见端口号及其用途
  • 三、BufferedReader 和 FileReader 的角色
  • 总结

前言

在我们学习TomCat和Servlet之前,**我们要知道Tomcat其实就相互于一个Java程序,但是这个Java程序可以处理来自浏览器的Http请求。**下面我们就自己来编写一个"服务器"来接收和相应浏览器或客户端发送的请求。


提示:以下是本篇文章正文内容,下面案例可供参考

一、一个简单的Web浏览服务程序

下面是源代码:

java 复制代码
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

public class MyTomcat {
    public static void main(String[] args) {
        try (ServerSocket serverSocket = new ServerSocket(9999)) {
            System.out.println("=====我的 web 服务在 9999 端口监听=====");

            while (!serverSocket.isClosed()) {
                try (Socket socket = serverSocket.accept();
                     OutputStream outputStream = socket.getOutputStream();
                     BufferedReader bufferedReader =
                             new BufferedReader(new FileReader("src/hello.html"))) {

                    // 发送HTTP响应头
                    String httpHeader = "HTTP/1.1 200 OK\r\n" +
                            "Content-Type: text/html; charset=utf-8\r\n" +
                            "\r\n";
                    outputStream.write(httpHeader.getBytes());

                    // 发送HTML内容
                    String line;
                    while ((line = bufferedReader.readLine()) != null) {
                        outputStream.write(line.getBytes());
                    }

                } catch (IOException e) {
                    System.out.println("处理客户端请求时出错: " + e.getMessage());
                }
            }
        } catch (IOException e) {
            System.out.println("启动服务器失败: " + e.getMessage());
            // 检查端口是否被占用[1,3](@ref)
            System.out.println("请确认9999端口没有被其他程序占用");
        }
    }
}

二、对以上代码的解释:

首先先说明我这个是模拟的普通Web服务程序,让我们来看看Web服务器如何与浏览器"对话"是如何进行的

1.ServerSocket 和 Socket 的生动比喻:

你可以把整个网络通信过程想象成一个​​客服中心​​的工作流程:

组件 比喻 职责
ServerSocket ​客服总机​ 它固定在公司的某个电话号码上(​​绑定端口​ ​,比如9999),只负责一件事:​​等待并接起打进来的电话​ ​(accept()方法)。它本身不处理具体业务。
Socket ​接通后的分机电话​ 当总机 (ServerSocket) 接起一个来电后,它会为这个通话​​创建一条专用的分机线路​ ​(一个新的Socket对象)。客服通过这部​​分机电话​ ​与客户进行​​双向的、具体的沟通​ ​(数据交换)。​​服务器端和客户端各有一部这样的"电话"​​。

所以,在我的代码中:

    1. ServerSocket serverSocket = new ServerSocket(9999);就像是:​​开通了公司的客服总机,号码是9999​​。
    1. Socket socket = serverSocket.accept();就像是:​​总机接线员拿起听筒,等待并接起一个客户的来电。一旦电话接通,你就得到了一条和这位客户专用的通话线路(socket)​​。
    1. 客户端(浏览器)通过输入 localhost:9999来连接,就相当于:​​客户拨打你公司的总机号码​

2.网络通信的"公司大楼"模型

概念 现实比喻 对应计算机概念
​公司大楼​ 一座有固定地址的办公楼 你的电脑(主机)
​公司地址​ 办公楼的具体街道门牌号 localhost127.0.0.1(本机地址)
​客服总机号码​ 公司对外公布的统一电话号码(如400-xxx) 端口号(如9999)
​客服总机 (ServerSocket)​ 前台的总机电话设备(绑定在公司号码上) ServerSocket serverSocket = new ServerSocket(9999);
​客户来电​ 外部客户拨打公司总机号码 浏览器访问 http://localhost:9999
​分机电话 (Socket)​ 总机转接给客服人员的专用分机 Socket socket = serverSocket.accept();
​客服沟通​ 客服通过分机与客户对话 通过 socket.getInputStream()/getOutputStream()读写数据

重点概念详解

  1. localhost127.0.0.1​:

    • • 它们就像你公司的​​两个别名​​,都指向同一栋大楼(你的电脑)。

    • localhost是域名,127.0.0.1是IP地址,效果完全一样。就像"环球金融中心"和"浦东新区世纪大道100号"都指同一栋楼。

  2. ​端口号(如9999)​​:

    • • 这相当于公司的​​分机号​​。一栋大楼(你的电脑)里可以有很多部门(应用程序),每个部门有自己专属的分机号(端口)。

    • • 常见端口:80(HTTP)、443(HTTPS)、3306(MySQL)... 你用的9999就像给测试部门临时开的分机。

  3. ServerSocket​:

    • • 它​​不是​ ​大楼本身,而是​​专门负责接听某个分机号(端口)的电话机​​。

    • • 当它 accept()时,就像前台拿起听筒:"您好,这里是9999号客服,请问有什么可以帮您?"

  4. Socket​:

    • • 这是​​接通后建立的专用通信通道​​。想象客服代表拿起分机:"王先生您好,我是您的专属客服小李,您的问题请讲..."

    • • 每个客户端连接都会创建一个新的 Socket对象(就像每个来电都转接给一个新的客服代表)。

端口是计算机网络中一个非常基础且重要的概念。它就像是计算机与外界通信的"门户"或"通道",用来区分一台计算机上不同的网络应用程序或服务

为了更具体地理解,这里有一个经典的比喻:

  • ​IP 地址​ ​:相当于​​一栋大楼的地址​​(如:上海市浦东新区张江高科技园区博云路2号)。它唯一标识了网络上的某一台设备(计算机、服务器等)

  • ​端口号​ ​:相当于这栋大楼里​​每个房间的门牌号​​(如:301室、302室)。它唯一标识了这台设备上运行的不同网络程序或服务

数据包通过IP地址找到目标计算机后,再通过端口号就能知道自己应该被哪个具体的应用程序(如浏览器、游戏、邮箱客户端)接收和处理,从而实现"多任务并行"和"精准投递"。

类别 端口号范围 用途 常见示例
​知名端口​ 0 - 1023 预留给最通用的网络服务,由国际组织IANA分配和管理。 ​80​​: HTTP (网页浏览) ​​443​ ​: HTTPS (加密网页浏览) ​​21​ ​: FTP (文件传输) ​​22​ ​: SSH (安全远程登录) ​​25​​: SMTP (发送邮件)
​注册端口​ 1024 - 49151 松散地绑定于一些服务,许多用户或企业程序可以注册使用这些端口。 ​3306​​: MySQL数据库 ​​3389​ ​: Windows远程桌面(RDP) ​​5432​​: PostgreSQL数据库

|---------------|---------------|-------------------------|----------------------------------------------|
| 动态/私有端口​​ | 49152 - 65535 | 通常由客户端程序临时使用,操作系统会动态分配。 | 当你用浏览器访问网站时,你的电脑就会用一个此范围内的端口去连接服务器的80或443端口。 |

常见端口号及其用途

了解一些常见端口号有助于你理解日常的网络活动和服务配置:

端口号 协议 用途简述
​20/21​ FTP ​文件传输协议​​(数据/控制)
​22​ SSH ​安全外壳协议​​,用于加密远程管理
​23​ Telnet ​远程登录协议​​(明文传输,不安全)
​53​ DNS ​域名系统​​,将域名解析为IP地址
​67/68​ DHCP ​动态主机配置协议​​,自动分配IP地址
​80​ HTTP ​超文本传输协议​​,用于网页浏览
​110​ POP3 ​邮局协议版本3​​,用于接收邮件
​143​ IMAP ​互联网消息访问协议​​,用于接收邮件
​443​ HTTPS ​安全超文本传输协议​​,加密的网页浏览
​3306​ MySQL ​MySQL数据库​​服务
​3389​ RDP ​远程桌面协议​​,用于Windows远程控制

三、BufferedReader 和 FileReader 的角色

java 复制代码
BufferedReader bufferedReader = new BufferedReader(new FileReader("src/hello.html"));

这行代码做了两件事,涉及到两个类,它们是一种经典的​​"装饰器模式"​​的应用:

  1. FileReader(文件读取器)​​:

    • • ​​它的角色是"基础工人"​​。它的任务很简单:负责打开文件,并按顺序一个字符一个字符地读取文件内容。

    • • ​​缺点​​:如果这个"工人"每读一个字符就要跑去文件那里一次(即频繁进行底层I/O操作),当文件很大时,效率会非常低。

  2. BufferedReader(缓冲读取器)​​:

    • • ​​它的角色是"高效的调度员"​ ​。它自己不直接读文件,而是​​站在 FileReader这个"工人"身边指挥它​​。

    • • ​​工作原理​ ​:它会让 FileReader​一次性多读一些内容​ ​(比如读取8KB的数据)到一个​​缓冲区​ ​(可以看作是一个"临时仓库")里。然后,当你调用 bufferedReader.readLine()时,它就不是慢吞吞地去文件里取,而是​​飞快地从"临时仓库"里把数据给你​​。

    • • ​​优点​ ​:通过​​减少直接访问文件(磁盘)的次数​​,大大提高了读取效率,尤其是在读取大文件时。

      它还提供了非常方便的 readLine()方法,可以直接读取一整行文本。

所以,new BufferedReader(new FileReader(...))这种套娃式的写法,意思就是:​​我想用一个高效的、带缓冲的读取器 (BufferedReader),来读取一个文件 (FileReader)​​。


总结

这就是一个简单的模拟的Web服务程序,大家可以自己试试模拟一下,了解浏览器和服务器是如何交互的,我会持续更新的,谢谢大家。

相关推荐
寻星探路2 小时前
【深度长文】万字攻克网络原理:从 HTTP 报文解构到 HTTPS 终极加密逻辑
java·开发语言·网络·python·http·ai·https
想用offer打牌3 小时前
MCP (Model Context Protocol) 技术理解 - 第二篇
后端·aigc·mcp
崔庆才丨静觅3 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
曹牧4 小时前
Spring Boot:如何测试Java Controller中的POST请求?
java·开发语言
passerby60614 小时前
完成前端时间处理的另一块版图
前端·github·web components
KYGALYX4 小时前
服务异步通信
开发语言·后端·微服务·ruby
掘了4 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅4 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅4 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
爬山算法5 小时前
Hibernate(90)如何在故障注入测试中使用Hibernate?
java·后端·hibernate