Swoole与Go系列教程之HTTP服务的应用

简介: PHP 曾是Web开发领域佼佼者,随着业务壮大,异步和高并发方面不足显现。Swoole 曾经尝试填补空白,但局限性也比较的明显。Go 语言的崛起,简洁语法和并发优势吸引大厂使用,吸引了大多数程序员的转型。

大家好,我是码农先森。

写在前面

PHP 曾是Web开发领域佼佼者,随着业务壮大,异步和高并发方面不足显现。Swoole 曾经尝试填补空白,但局限性也比较的明显。Go 语言的崛起,简洁语法和并发优势吸引大厂使用,吸引了大多数程序员的转型。疫情、战争、大环境的恶化等因素加剧了互联网行业内卷,PHP 程序员陷入了困境,因此转型 Go 语言是不二的选择。我从 PHP 转型Go,深知转型之难。因此致力于帮助其他 PHP 程序员转型,分享经验。困境时需抱团取暖,才能走过黎明前的黑暗。

HTTP 协议原理

HTTP 协议是一种用于传输超文本(如HTML)的应用层协议。它是Web通信的基础,负责在客户端和服务器之间传递请求和响应。HTTP 使用 TCP 作为传输协议,通常使用 80 端口进行通信。如下图所示 HTTP 协议在 TCP/IP 网络模型中是处于应用层,是 TCP/IP 协议的一个子集。

请在此添加图片描述
HTTP 协议撑起了互联网的大半江山,可以说没有 HTTP 协议就没有当下的互联网。作为一名 Web 程序的开发者,深入掌握和理解 HTTP 协议尤为重要。下面这张图是表示了 HTTP 的请求报文、响应报文格式,其实相对于其他的协议来说,HTTP 协议是比较简单了,同时也是最常用的。

请在此添加图片描述

原生 PHP 的实现

使用 PHP 的内置 HTTP 模块启动服务

php -S 内置服务器实际上是基于CLI(Command Line Interface)SAPI。当执行php -S命令时,PHP 会以命令行模式启动一个轻量级服务器,监听指定的IP地址和端口。但是,这种内置的服务器并不适合用于生产环境,它是为了便于开发和测试而提供的工具。如果是在生产环境上,建议部署 PHP-FPM,再通过 Nginx 做反向代理的方式实现。

1、代码文件 index.php

<?php

// 设置HTTP响应头,告知浏览器返回的是文本内容
header('Content-Type: text/plain');

// 输出 "Hello, World!" 作为响应
echo "Hello, World! For PHP Module";

2、启动

MacBook-Pro:demo$ php -S 127.0.0.1:8080
[Sat Jul 22 10:30:42 2023] PHP 8.2.5 Development Server (http://127.0.0.1:8080) started

3、访问

MacBook-Pro:demo$ curl http://127.0.0.1:8080
Hello, World! For PHP Module

使用 Socket 的方式启动 HTTP 服务

Socket 是一种用于在网络中进行通信的编程接口。它允许程序在网络上通过 IP 地址和端口号与其他计算机建立连接,从而实现数据的传输和交换。 Socket 是一种低层次的网络编程接口,支持 TCP、UDP、IPv4、IPv6 协议,不能直接支持应用层协议,例如 HTTP 协议等。因此,这里通过使用 Socket 创建一个 TCP 服务器来处理 HTTP 请求。

1、代码文件 socket.php

<?php
$host = 'localhost';  // 如果需要,可以将此处更改为你服务器的IP地址
$port = 8080;         // 服务器监听的端口

$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
if ($socket === false) {
   
   
    echo "无法创建Socket: " . socket_strerror(socket_last_error()) . PHP_EOL;
    exit(1);
}

socket_bind($socket, $host, $port) or die('无法绑定到指定地址');

socket_listen($socket);
echo "服务器监听在 $host:$port..." . PHP_EOL;

while (true) {
   
   
    $client = socket_accept($socket);

    // 读取客户端的请求
    $request = socket_read($client, 4096);

    // 处理请求(为简单起见,我们只处理GET请求)
    if (preg_match("/GET (.*) HTTP\/1\.1/", $request, $matches)) {
   
   
        $uri = $matches[1];
        $response = "HTTP/1.1 200 SUCCESS\r\n\r\nHello World! For PHP Socket\r\n";
    }

    // 将响应发送给客户端
    socket_write($client, $response);

    // 关闭客户端连接
    socket_close($client);
}

2、启动

MacBook-Pro:demo$ php socket.php 
服务器监听在 localhost:8080...

3、访问

MacBook-Pro:demo$ curl http://127.0.0.1:8080
Hello World! For PHP Socket

Swoole 扩展的实现

Swoole 使用底层 C++ 实现,充分利用了异步非阻塞的网络模型,能够处理大量并发连接,极大地提高了 HTTP 服务的性能。通过事件循环和异步处理,避免了 PHP 单进程模型的瓶颈。

请在此添加图片描述
每一个用户的 HTTP 请求,将由 Master 进程分配到 Worker 进程进行处理,不阻塞主进程的执行;同时,每个 Worker 进程内部会将请求协程化,避免阻塞 worker 进程,这种模式极大的提高了服务的处理能力,如下图源代码中对应使用协程来实现发送数据。

请在此添加图片描述

1、代码文件 swoole_http.php

<?php
// 创建HTTP服务器对象,监听在0.0.0.0:8080端口
$http = new Swoole\Http\Server("0.0.0.0", 8080);

// 设置 Worker 数量
$http->set([
    'worker_num' => 3
]);

// 在启动事件中执行初始化设置
$http->on('start', function ($server) {
   
   
    echo "Swoole HTTP服务器已启动\n";
});

// 监听HTTP请求事件
$http->on('request', function ($request, $response) {
   
   
    // 处理请求
    $response->status(200);
    $response->end("Hello World! For Swoole HTTP\r\n");
});

// 启动HTTP服务器
$http->start();

2、启动

MacBook-Pro:demo$ php swoole_http.php 
Swoole HTTP服务器已启动

3、访问

MacBook-Pro:demo$ curl http://127.0.0.1:8080
Hello World! For Swoole HTTP

Go 语言的实现

Go 语言的轻量级线程Goroutine,能够快速处理大量并发请求。Goroutine 的创建和销毁非常快速,在单个物理线程上可以同时运行成千上万个 Goroutine。并且可以高效的利用多核 CPU,充分的使用物理资源。http.ListenAndServe 启动并监听一个 HTTP 服务,客户端与服务端建立连接后,服务端会交由一个 Goroutine 处理,下面这张图是对应 Go Http 模块源代码的处理逻辑。

请在此添加图片描述

1、代码文件 main.go

package main

import (
    "fmt"
    "net/http"
)

func main() {
   
   
    // 处理请求
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
   
   
        fmt.Fprintf(w, "Hello, World! For Go")
    })

    // 启动HTTP服务,监听在本地的8080端口
    err := http.ListenAndServe(":8080", nil)
    if err != nil {
   
   
        fmt.Println("Error starting server:", err)
    }
}

2、启动

MacBook-Pro:demo$ go run main.go

3、访问

MacBook-Pro:demo$ curl http://127.0.0.1:8080
Hello, World! For Go

总结

  1. 在 PHP 语言层面启动 HTTP 服务并不适合,通常需要结合 PHP-FPM、Nginx 等服务。
  2. Swoole 作为用 C++ 实现的扩展,弥补了 PHP 在异步通信及并发层面的不足,但是,在单进程的模式下无法高效的利用多核 CPU,不能充分的榨干物理资源。
  3. Go 语言是高并发领域的一支独秀,天然支持高并发,并且能够充分的利用物理资源。

欢迎关注、分享、点赞、收藏、在看,我是微信公众号「码农先森」作者。

相关文章
|
5月前
|
消息中间件 缓存 NoSQL
Redis各类数据结构详细介绍及其在Go语言Gin框架下实践应用
这只是利用Go语言和Gin框架与Redis交互最基础部分展示;根据具体业务需求可能需要更复杂查询、事务处理或订阅发布功能实现更多高级特性应用场景。
369 86
|
7月前
|
Java Shell Maven
【Azure Container App】构建Java应用镜像时候遇无法编译错误:ERROR [build 10/10] RUN ./mvnw.cmd dependency:go-offline -B -Dproduction package
在部署Java应用到Azure Container App时,构建镜像过程中出现错误:“./mvnw.cmd: No such file or directory”。尽管项目根目录包含mvnw和mvnw.cmd文件,但依然报错。问题出现在Dockerfile构建阶段执行`./mvnw dependency:go-offline`命令时,系统提示找不到可执行文件。经过排查,确认是mvnw文件内容异常所致。最终通过重新生成mvnw文件解决该问题,镜像成功构建。
342 1
|
7月前
|
网络协议 安全 API
WebSocket、Socket、TCP 和 HTTP 的差别与应用场景
WebSocket、Socket、TCP 和 HTTP 是网络通信中的四大“使者”,各具特色:HTTP 适合短时请求,TCP 稳定可靠,Socket 灵活定制,WebSocket 实现实时双向通信。本文用通俗语言解析它们的区别与应用场景,助你为项目选择最合适的通信方式。
2710 3
|
7月前
|
人工智能 Go
GO语言之泛型应用
本文介绍了Go语言中泛型的使用,包括为何引入泛型、泛型语法详解以及如何自定义约束。通过实例展示了泛型在简化代码、提高复用性方面的优势,并演示了泛型在slice、指针、map等数据类型中的应用。
208 1
|
6月前
|
数据采集 JSON Go
Go语言实战案例:实现HTTP客户端请求并解析响应
本文是 Go 网络与并发实战系列的第 2 篇,详细介绍如何使用 Go 构建 HTTP 客户端,涵盖请求发送、响应解析、错误处理、Header 与 Body 提取等流程,并通过实战代码演示如何并发请求多个 URL,适合希望掌握 Go 网络编程基础的开发者。
|
7月前
|
JSON 前端开发 Go
Go语言实战:创建一个简单的 HTTP 服务器
本篇是《Go语言101实战》系列之一,讲解如何使用Go构建基础HTTP服务器。涵盖Go语言并发优势、HTTP服务搭建、路由处理、日志记录及测试方法,助你掌握高性能Web服务开发核心技能。
|
8月前
|
JSON 编解码 API
Go语言网络编程:使用 net/http 构建 RESTful API
本章介绍如何使用 Go 语言的 `net/http` 标准库构建 RESTful API。内容涵盖 RESTful API 的基本概念及规范,包括 GET、POST、PUT 和 DELETE 方法的实现。通过定义用户数据结构和模拟数据库,逐步实现获取用户列表、创建用户、更新用户、删除用户的 HTTP 路由处理函数。同时提供辅助函数用于路径参数解析,并展示如何设置路由器启动服务。最后通过 curl 或 Postman 测试接口功能。章节总结了路由分发、JSON 编解码、方法区分、并发安全管理和路径参数解析等关键点,为更复杂需求推荐第三方框架如 Gin、Echo 和 Chi。
|
7月前
|
Go
如何在Go语言的HTTP请求中设置使用代理服务器
当使用特定的代理时,在某些情况下可能需要认证信息,认证信息可以在代理URL中提供,格式通常是:
533 0
|
7月前
|
存储 监控 算法
公司员工泄密防护体系中跳表数据结构及其 Go 语言算法的应用研究
在数字化办公中,企业面临员工泄密风险。本文探讨使用跳表(Skip List)数据结构优化泄密防护系统,提升敏感数据监测效率。跳表以其高效的动态数据处理能力,为企业信息安全管理提供了可靠技术支持。
166 0
|
7月前
|
Web App开发 缓存 数据安全/隐私保护
Django全栈实战:HTTP状态码与业务状态码的分层设计与实战应用
HTTP状态码是服务器响应请求的3位数字代码,分为1xx(信息)、2xx(成功)、3xx(重定向)、4xx(客户端错误)、5xx(服务器错误)。业务状态码则用于描述具体业务逻辑结果,常在响应体中返回。二者在前后端交互中有不同用途和处理方式。本文还介绍了如何在Django项目中设计并使用业务状态码。
612 0

热门文章

最新文章