使用 Bash 构建 Web 服务器,第一部分 - 套接字遇见 netcat

2025-06-07

使用 Bash 构建 Web 服务器,第一部分 - 套接字

认识 netcat

您是否想过Web 服务器的底层工作原理?此外,您是否愿意磨练一下 Shell 脚本技能?

也许本指南适合您。

在整个指南中,我们将逐步构建一个仅使用bash的简单 Web 服务器,同时进一步讲解套接字、TCP、HTTP 等基本术语以及 Web 三要素:HTML、CSS 和 Javascript。

本指南可能有点太长,但为了便于理解,我们将把它分成几个较小的部分。

确保你拿起类 UNIX 终端,准备好你最喜欢的 shell(我使用 bash),喝杯咖啡,让我们开始这段旅程。


首先要做的事情

了解一些基础知识(例如 UNIX 标准流和管道)非常重要。除非您已经熟悉这些术语,否则请参阅我关于 UNIX 的系列文章

认识 netcat

netcat是一种用于操作网络套接字(如 UNIX、TCP 或 UDP)的计算机网络实用程序。

确保您的操作系统中有它并相应地安装它。

Socket 回顾

关于套接字,我们首先可以探索如何创建 UNIX 套接字,然后让两个不同的进程通过套接字相互通信。

UNIX 套接字有两种类型:流和数据报

流套接字在服务器和客户端之间建立连接,因为数据是以可靠的方式发送的。

数据报套接字不会创建连接,因为数据不是以可靠的方式发送的

在本指南中,我们将仅关注流套接字

UNIX 套接字

让我们打开一个终端并创建一个名为的套接字server.sock



$ nc -Uvl server.sock

Bound on server.sock
Listening on server.sock


Enter fullscreen mode Exit fullscreen mode

了解命令选项:

  • -U:指定它是一个 UNIX 套接字
  • -v:详细模式
  • -l:准备监听套接字连接

现在,在另一个终端中,让我们创建连接到现有的客户端server.sock



$ nc -Uv server.sock


Enter fullscreen mode Exit fullscreen mode

此时,请注意服务器的 STDOUT 中Connection received on server.sock刚刚出现了一条消息。这意味着客户端已连接,因此客户端和服务器都已准备好通过此连接交换消息。

尝试PING从客户端输入,然后转到服务器端输入PONG这就是客户端-服务器架构的工作原理!

标准流、重定向和管道

想一想nc(netcat)进程发生了什么:

  • STDIN 保持打开状态,直到您输入消息
  • 进程的 STDINnc被发送到套接字
  • 当任何其他消息到达套接字时,它将被发送到nc进程的 STDOUT

让我们假设这个基于 UNIX 管道的伪抽象:



# Server
$ {input} | nc -Ul server.sock | {output}

# Client
$ {input} | nc -U server.sock | {output}


Enter fullscreen mode Exit fullscreen mode

我们能从中学到什么?我们能够将消息传递给nc命令,然后将该消息发送到套接字。

它适用于客户端和服务器。让我们看看它在服务器端的具体表现:



$ echo PONG | nc -Uvl server.sock

Bound on server.sock
Listening on server.sock


Enter fullscreen mode Exit fullscreen mode

nc像其他 UNIX 命令一样,它从管道接收数据。它从 STDIN 获取数据并将其存储起来,以便发送到套接字。

但是,由于这个-l选项,服务器首先监听套接字中的消息。每当请求消息到达时,PONG都会发回响应消息。

我们来看看客户端:



$ echo PING | nc -Uv server.sock

PONG


Enter fullscreen mode Exit fullscreen mode

nc像其他 UNIX 命令一样,它从管道接收数据。它从 STDIN 获取数据并将其发送到套接字,因为它不像服务器那样监听。

它只是一个客户端:客户端连接到套接字,发送消息,然后完成其工作

PONG这就是为什么我们看到客户端连接后响应消息立即到达的原因。

关闭套接字

如果我们希望在客户端完成发送请求消息后立即关闭服务器套接字该怎么办?

该选项-N可以完成这项工作。请尝试在服务器端使用以下命令:



$ echo PONG | nc -UvlN server.sock


Enter fullscreen mode Exit fullscreen mode

上网

好的,但是当我们谈论 Web 服务器时,我们指的是服务器和客户端分别位于不同的机器上。这些机器必须连接到互联网,互联网是最标准、最公开、最去中心化的全球计算机网络。

由于进程分布在不同的计算机上,使用 UNIX 套接字是不可能的。Berkeley套接字 API正是为解决这个问题而创建的,它采用了更高级的网络协议,实现了与 UNIX 套接字相同的 API。

这类协议称为 TCP 或 UDP。本文将使用 TCP。

TCP套接字

TCP代表传输控制协议,位于网络OSI 模型的第四层。

OSI 模型

免责声明仅出于测试目的,我们将继续在同一台机器上使用客户端-服务器,但完全可以在本地使用 TCP。

创建 TCP 服务器:



$ echo PONG | nc -lvN 3000

Listening on 0.0.0.0 3000


Enter fullscreen mode Exit fullscreen mode
  • -l:监听TCP连接
  • -v:详细模式
  • -N:数据传输完成后强制关闭客户端连接

TCP 客户端:



$ echo PING | nc -v localhost 3000

Connection to localhost (127.0.0.1) 3000 port [tcp/*] succeeded!
PONG


Enter fullscreen mode Exit fullscreen mode

请注意,客户端连接到套接字后立即建立了连接。然后服务器立即将响应发送回PONG客户端。

但我们想通过互联网交换更复杂的信息,对吗?一种提供灵活性和安全性的信息。

你好,HTTP!

HTTP

HTTP是一种通过 TCP 传输多媒体和超文本的协议,是Web 的基础。

在探索 bash 中更复杂的 Web 服务器之前,让我们先看看如何直接在 bash 会话中使用创建单行HTTP 服务器。netcat

PONG我们可以使用 HTTP 协议约定发送更结构化的消息,而不是像我们在 TCP 上看到的那样响应简单的文本:



$ echo -e 'HTTP/1.1 200\r\nContent-Type: application/text\r\n\r\nPONG' | nc -lvN 3000

Listening on 0.0.0.0 3000


Enter fullscreen mode Exit fullscreen mode

理解HTTP响应消息:



HTTP/1.1 200       
Content-Type: application/text 

PONG 


Enter fullscreen mode Exit fullscreen mode
  • HTTP/1.1 200:HTTP 响应状态代码,本例中 200 表示成功
  • Content-Type: application/text:HTTP 响应标头。可以在同一个 HTTP 消息中发送多个标头,也可以不发送任何标头。
  • 空行:这是必需的,为了区分标题和剩余的响应主体
  • PONG:剩余响应主体的内容

相当简单且易于理解,是吧?

现在,让我们执行 HTTP 客户端:



$ echo -e 'GET / HTTP/1.1\r\n\r\n\r\nPING' | nc -vN localhost 3000

Connection to localhost (127.0.0.1) 3000 port [tcp/*] succeeded!
HTTP/1.1 200
Content-Type: application/text

PONG


Enter fullscreen mode Exit fullscreen mode

HTTP 消息虽然易于人类阅读,但计算机却难以读取。因此,不同的 HTTP 客户端必须了解其协议才能“解析”并显示消息主体。

我们以HTTP客户端为例,curl程序如下:



$ curl http://localhost:3000/ -d PING

PONG


Enter fullscreen mode Exit fullscreen mode

耶!

添加一些 HTML

HTML是一种标记语言,与 CSS 和 JS 一起使用时用于多媒体、结构化内容和动态网页。

现在,让我们将Content-TypeHTTP 标头更改为允许text/html,然后向消息添加一个简单的 HTML 标签:



$ echo -e 'HTTP/1.1 200\r\nContent-Type: text/html\r\n\r\n<h1>PONG</h1>' | nc -lvkN 3000

Listening on 0.0.0.0 3000


Enter fullscreen mode Exit fullscreen mode

对于客户来说:



$ curl http://localhost:3000/ 

<h1>PONG</h1>


Enter fullscreen mode Exit fullscreen mode

太棒了!不过,虽然能解析 HTTP 消息,却无法curl渲染响应体中的 HTML 内容?

不可以。curl不能那样做。

那么,我们来尝试使用另一个 HTTP 客户端。它以渲染 HTML 内容而闻名,而且我敢肯定你之前已经用过它了:没错,我说的就是 Web 浏览器

localhost:3000在您最喜欢的网络浏览器中打开...

PONG HTML

这就是为什么它被称为Web 浏览器,明白了吗?

总结

这是指南的第一部分,我们学习了如何操作该netcat工具,并在单行服务器中讲解了 TCP、HTTP 和少量 HTML 等一些概念。

在接下来的部分中,我们将继续探索基础知识,以便构建一个用 ShellScript 编写的完整 Web 服务器。

文章来源:https://dev.to/leandronsp/building-a-web-server-in-bash-part-i-sockets-2n8b
PREV
在 Assembly x86 上构建 Web 服务器,第一部分,简介
NEXT
带有 React 的 FullCalendar