<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>网络 on Coder_Studio</title>
        <link>https://iamxurulin.github.io/tags/%E7%BD%91%E7%BB%9C/</link>
        <description>Recent content in 网络 on Coder_Studio</description>
        <generator>Hugo -- gohugo.io</generator>
        <language>zh-cn</language>
        <copyright>iamxurulin</copyright>
        <lastBuildDate>Sun, 23 Aug 2026 17:21:42 +0000</lastBuildDate><atom:link href="https://iamxurulin.github.io/tags/%E7%BD%91%E7%BB%9C/index.xml" rel="self" type="application/rss+xml" /><item>
        <title>GoCloud - 基于 WebSocket 的实时聊天应用</title>
        <link>https://iamxurulin.github.io/p/gocloud-%E5%9F%BA%E4%BA%8E-websocket-%E7%9A%84%E5%AE%9E%E6%97%B6%E8%81%8A%E5%A4%A9%E5%BA%94%E7%94%A8/</link>
        <pubDate>Wed, 03 Jun 2026 17:16:55 +0000</pubDate>
        
        <guid>https://iamxurulin.github.io/p/gocloud-%E5%9F%BA%E4%BA%8E-websocket-%E7%9A%84%E5%AE%9E%E6%97%B6%E8%81%8A%E5%A4%A9%E5%BA%94%E7%94%A8/</guid>
        <description>&lt;p&gt;一个使用 Go 语言开发的多房间实时聊天应用，支持用户注册/登录、房间切换、聊天历史记录等功能。&lt;/p&gt;
&lt;h2 id=&#34;-项目演示&#34;&gt;📸 项目演示
&lt;/h2&gt;&lt;h3 id=&#34;登录界面&#34;&gt;登录界面
&lt;/h3&gt;&lt;p&gt;&lt;img src=&#34;https://iamxurulin.github.io/images/49acb30caf1343ad948ae103c64df538-c397c623.jpeg&#34;
	
	
	
	loading=&#34;lazy&#34;
	
		alt=&#34;在这里插入图片描述&#34;
	
	
&gt;&lt;/p&gt;
&lt;h3 id=&#34;多人实时聊天&#34;&gt;多人实时聊天
&lt;/h3&gt;&lt;p&gt;&lt;img src=&#34;https://iamxurulin.github.io/images/b4f6172460af4664b53b82988d71cd30-7424d7f6.jpeg&#34;
	
	
	
	loading=&#34;lazy&#34;
	
		alt=&#34;在这里插入图片描述&#34;
	
	
&gt;
&lt;img src=&#34;https://iamxurulin.github.io/images/cc5205adaad34c56a96a37bb5a6e7cfb-ebb9afac.jpeg&#34;
	
	
	
	loading=&#34;lazy&#34;
	
		alt=&#34;在这里插入图片描述&#34;
	
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;-功能特点&#34;&gt;✨ 功能特点
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;✅ &lt;strong&gt;用户注册/登录&lt;/strong&gt; - 支持用户名和密码注册，密码安全存储&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;多房间聊天&lt;/strong&gt; - 支持切换不同的聊天房间&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;实时消息&lt;/strong&gt; - 基于 WebSocket 的实时消息推送&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;在线用户列表&lt;/strong&gt; - 显示当前房间的在线用户&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;聊天历史记录&lt;/strong&gt; - 使用 SQLite 持久化存储聊天记录&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;系统通知&lt;/strong&gt; - 用户加入/离开房间的系统提示&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;登录状态保持&lt;/strong&gt; - 刷新页面后自动保持登录状态&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;密码验证&lt;/strong&gt; - 用户名和密码长度限制&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;精美的 UI 设计&lt;/strong&gt; - 渐变色主题，流畅的交互体验&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;-技术栈&#34;&gt;🛠️ 技术栈
&lt;/h2&gt;&lt;h3 id=&#34;后端&#34;&gt;后端
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Go 语言&lt;/strong&gt; - 高性能的服务端编程语言&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Gin 框架&lt;/strong&gt; - 轻量级的 HTTP Web 框架&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Gorilla WebSocket&lt;/strong&gt; - WebSocket 通信库&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SQLite&lt;/strong&gt; - 轻量级关系型数据库&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;modernc.org/sqlite&lt;/strong&gt; - SQLite 驱动（纯 Go 实现，无需 CGO）&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;前端&#34;&gt;前端
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;HTML5 + CSS3&lt;/strong&gt; - 现代网页标准&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Vanilla JavaScript&lt;/strong&gt; - 原生 JS，无需框架&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;LocalStorage&lt;/strong&gt; - 浏览器本地状态存储&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;-项目结构&#34;&gt;📁 项目结构
&lt;/h2&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt; 1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 4
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 5
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 6
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 7
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 8
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 9
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;10
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;11
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;12
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;13
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;14
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;15
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;16
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;17
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;18
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;19
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;20
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;GoCloud/
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;├── cmd/
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│   └── server/
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│       └── main.go              # 主程序入口，包含前端页面
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;├── internal/
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│   ├── chat/
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│   │   ├── types.go             # 数据结构定义
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│   │   ├── hub.go               # 核心逻辑：房间管理、消息广播
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│   │   └── client.go            # WebSocket 客户端处理
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│   ├── handler/
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│   │   └── websocket.go         # HTTP API 处理器
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│   └── database/
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│       ├── database.go          # 数据库初始化
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│       ├── user.go              # 用户数据库操作
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│       ├── room.go              # 房间数据库操作
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│       └── message.go           # 消息数据库操作
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;├── go.mod                       # Go 模块文件
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;├── go.sum                       # 依赖锁定文件
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;├── chat.db                      # SQLite 数据库文件（运行时生成）
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;└── README.md                    # 项目说明文档
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id=&#34;-快速开始&#34;&gt;🚀 快速开始
&lt;/h2&gt;&lt;h3 id=&#34;前置要求&#34;&gt;前置要求
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;Go 1.16 或更高版本&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;安装依赖&#34;&gt;安装依赖
&lt;/h3&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;go mod download
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id=&#34;运行项目&#34;&gt;运行项目
&lt;/h3&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;go run cmd/server/main.go
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;服务器将在 &lt;code&gt;http://localhost:8080&lt;/code&gt; 启动。&lt;/p&gt;
&lt;h3 id=&#34;使用说明&#34;&gt;使用说明
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;打开浏览器访问 &lt;code&gt;http://localhost:8080&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;点击「注册」创建新账号&lt;/li&gt;
&lt;li&gt;输入用户名（3-20字符）和密码（6-20字符）&lt;/li&gt;
&lt;li&gt;登录后进入聊天界面&lt;/li&gt;
&lt;li&gt;在左侧选择不同的聊天房间&lt;/li&gt;
&lt;li&gt;在底部输入框输入消息并发送&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;-数据库设计&#34;&gt;🗄️ 数据库设计
&lt;/h2&gt;&lt;h3 id=&#34;users-表&#34;&gt;users 表
&lt;/h3&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;字段&lt;/th&gt;
					&lt;th&gt;类型&lt;/th&gt;
					&lt;th&gt;说明&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;id&lt;/td&gt;
					&lt;td&gt;TEXT&lt;/td&gt;
					&lt;td&gt;用户ID（UUID）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;username&lt;/td&gt;
					&lt;td&gt;TEXT&lt;/td&gt;
					&lt;td&gt;用户名（唯一）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;password&lt;/td&gt;
					&lt;td&gt;TEXT&lt;/td&gt;
					&lt;td&gt;密码（哈希存储）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;created_at&lt;/td&gt;
					&lt;td&gt;DATETIME&lt;/td&gt;
					&lt;td&gt;创建时间&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;rooms-表&#34;&gt;rooms 表
&lt;/h3&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;字段&lt;/th&gt;
					&lt;th&gt;类型&lt;/th&gt;
					&lt;th&gt;说明&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;id&lt;/td&gt;
					&lt;td&gt;TEXT&lt;/td&gt;
					&lt;td&gt;房间ID&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;name&lt;/td&gt;
					&lt;td&gt;TEXT&lt;/td&gt;
					&lt;td&gt;房间名称&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;description&lt;/td&gt;
					&lt;td&gt;TEXT&lt;/td&gt;
					&lt;td&gt;房间描述&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;created_at&lt;/td&gt;
					&lt;td&gt;DATETIME&lt;/td&gt;
					&lt;td&gt;创建时间&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;messages-表&#34;&gt;messages 表
&lt;/h3&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;字段&lt;/th&gt;
					&lt;th&gt;类型&lt;/th&gt;
					&lt;th&gt;说明&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;id&lt;/td&gt;
					&lt;td&gt;INTEGER&lt;/td&gt;
					&lt;td&gt;消息ID（自增）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;room_id&lt;/td&gt;
					&lt;td&gt;TEXT&lt;/td&gt;
					&lt;td&gt;房间ID&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;user_id&lt;/td&gt;
					&lt;td&gt;TEXT&lt;/td&gt;
					&lt;td&gt;用户ID&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;username&lt;/td&gt;
					&lt;td&gt;TEXT&lt;/td&gt;
					&lt;td&gt;用户名&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;type&lt;/td&gt;
					&lt;td&gt;TEXT&lt;/td&gt;
					&lt;td&gt;消息类型（message/system）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;content&lt;/td&gt;
					&lt;td&gt;TEXT&lt;/td&gt;
					&lt;td&gt;消息内容&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;time&lt;/td&gt;
					&lt;td&gt;TEXT&lt;/td&gt;
					&lt;td&gt;时间戳&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;created_at&lt;/td&gt;
					&lt;td&gt;DATETIME&lt;/td&gt;
					&lt;td&gt;创建时间&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&#34;-websocket-消息格式&#34;&gt;📡 WebSocket 消息格式
&lt;/h2&gt;&lt;h3 id=&#34;消息类型&#34;&gt;消息类型
&lt;/h3&gt;&lt;h4 id=&#34;1-用户加入房间&#34;&gt;1. 用户加入房间
&lt;/h4&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;4
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;5
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;6
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;7
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;8
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;#34;type&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;join&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;#34;roomId&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;general&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;#34;fromId&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;user-uuid&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;#34;fromName&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;username&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;#34;content&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;加入了房间&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;#34;time&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;2026-06-03T16:00:00Z&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h4 id=&#34;2-用户离开房间&#34;&gt;2. 用户离开房间
&lt;/h4&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;4
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;5
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;6
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;7
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;8
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;#34;type&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;leave&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;#34;roomId&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;general&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;#34;fromId&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;user-uuid&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;#34;fromName&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;username&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;#34;content&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;离开了房间&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;#34;time&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;2026-06-03T16:00:00Z&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h4 id=&#34;3-普通消息&#34;&gt;3. 普通消息
&lt;/h4&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;4
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;5
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;6
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;7
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;8
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;#34;type&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;message&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;#34;roomId&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;general&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;#34;fromId&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;user-uuid&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;#34;fromName&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;username&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;#34;content&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Hello, World!&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;#34;time&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;2026-06-03T16:00:00Z&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h4 id=&#34;4-在线用户列表&#34;&gt;4. 在线用户列表
&lt;/h4&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;4
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;#34;type&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;users&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;#34;roomId&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;general&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;#34;users&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;user1&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;user2&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;user3&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h4 id=&#34;5-切换房间&#34;&gt;5. 切换房间
&lt;/h4&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;#34;type&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;change_room&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;#34;roomId&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;tech&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id=&#34;-http-api&#34;&gt;🔌 HTTP API
&lt;/h2&gt;&lt;h3 id=&#34;1-用户注册&#34;&gt;1. 用户注册
&lt;/h3&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt; 1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 4
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 5
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 6
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 7
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 8
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 9
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;10
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;11
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;12
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;13
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;14
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;15
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;16
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;POST /api/register
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Content-Type: application/json
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &amp;#34;username&amp;#34;: &amp;#34;testuser&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &amp;#34;password&amp;#34;: &amp;#34;123456&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;响应:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &amp;#34;success&amp;#34;: true,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &amp;#34;user&amp;#34;: {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &amp;#34;id&amp;#34;: &amp;#34;user-uuid&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &amp;#34;username&amp;#34;: &amp;#34;testuser&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id=&#34;2-用户登录&#34;&gt;2. 用户登录
&lt;/h3&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt; 1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 4
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 5
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 6
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 7
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 8
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 9
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;10
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;11
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;12
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;13
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;14
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;15
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;16
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;POST /api/login
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Content-Type: application/json
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &amp;#34;username&amp;#34;: &amp;#34;testuser&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &amp;#34;password&amp;#34;: &amp;#34;123456&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;响应:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &amp;#34;success&amp;#34;: true,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &amp;#34;user&amp;#34;: {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &amp;#34;id&amp;#34;: &amp;#34;user-uuid&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &amp;#34;username&amp;#34;: &amp;#34;testuser&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id=&#34;3-获取房间列表&#34;&gt;3. 获取房间列表
&lt;/h3&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt; 1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 4
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 5
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 6
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 7
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 8
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 9
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;10
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;11
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;12
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;13
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;14
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;15
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;16
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;17
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;18
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;19
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;20
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;21
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;22
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;23
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;GET /api/rooms
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;响应:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &amp;#34;success&amp;#34;: true,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &amp;#34;rooms&amp;#34;: [
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &amp;#34;id&amp;#34;: &amp;#34;general&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &amp;#34;name&amp;#34;: &amp;#34;大厅&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &amp;#34;description&amp;#34;: &amp;#34;欢迎来到大厅，大家可以在这里畅聊！&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    },
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &amp;#34;id&amp;#34;: &amp;#34;tech&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &amp;#34;name&amp;#34;: &amp;#34;技术交流&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &amp;#34;description&amp;#34;: &amp;#34;讨论技术问题、分享经验&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    },
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &amp;#34;id&amp;#34;: &amp;#34;game&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &amp;#34;name&amp;#34;: &amp;#34;游戏频道&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &amp;#34;description&amp;#34;: &amp;#34;一起聊游戏，找队友&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  ]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id=&#34;4-websocket-连接&#34;&gt;4. WebSocket 连接
&lt;/h3&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;GET /ws?userId={userId}&amp;amp;username={username}&amp;amp;roomId={roomId}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id=&#34;-核心实现&#34;&gt;💡 核心实现
&lt;/h2&gt;&lt;h3 id=&#34;hub-模式&#34;&gt;Hub 模式
&lt;/h3&gt;&lt;p&gt;使用经典的 Hub 模式管理 WebSocket 连接：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Hub&lt;/strong&gt;：中心管理器，负责管理所有房间和客户端&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Room&lt;/strong&gt;：房间，包含在线客户端和房间信息&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Client&lt;/strong&gt;：客户端连接，处理单个用户的 WebSocket 通信&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;消息广播流程&#34;&gt;消息广播流程
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;客户端发送消息到 Hub 的 Broadcast channel&lt;/li&gt;
&lt;li&gt;Hub 根据消息的 RoomID 找到对应房间&lt;/li&gt;
&lt;li&gt;Hub 将消息发送给房间内的所有客户端&lt;/li&gt;
&lt;li&gt;同时将消息保存到 SQLite 数据库&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;数据持久化&#34;&gt;数据持久化
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;使用 SQLite 数据库存储用户、房间和消息&lt;/li&gt;
&lt;li&gt;用户加入房间时从数据库加载历史消息&lt;/li&gt;
&lt;li&gt;新消息实时保存到数据库&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;-开发历程&#34;&gt;📝 开发历程
&lt;/h2&gt;&lt;h3 id=&#34;主要问题解决&#34;&gt;主要问题解决
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;在线用户列表不同步&lt;/strong&gt; - 修复了用户列表的广播逻辑，确保所有客户端都能收到更新&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;消息显示不一致&lt;/strong&gt; - 调整消息发送顺序，优先发送用户列表，确保消息顺序正确&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;刷新页面状态丢失&lt;/strong&gt; - 使用 LocalStorage 保存登录状态和房间信息&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;数据不持久化&lt;/strong&gt; - 集成 SQLite 数据库，实现用户和消息的永久存储&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;WebSocket 消息拼接问题&lt;/strong&gt; - 修复 WritePump 消息发送逻辑，每条消息单独发送&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;优化改进&#34;&gt;优化改进
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;调整消息发送顺序，优先发送用户列表&lt;/li&gt;
&lt;li&gt;添加更完善的错误处理和日志记录&lt;/li&gt;
&lt;li&gt;实现房间状态的保存和恢复&lt;/li&gt;
&lt;li&gt;优化 UI 设计，使用渐变色主题&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;-未来优化方向&#34;&gt;🔮 未来优化方向
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled=&#34;&#34; type=&#34;checkbox&#34;&gt; 添加头像支持&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&#34;&#34; type=&#34;checkbox&#34;&gt; 支持私聊功能&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&#34;&#34; type=&#34;checkbox&#34;&gt; 添加消息已读状态&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&#34;&#34; type=&#34;checkbox&#34;&gt; 支持图片/文件发送&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&#34;&#34; type=&#34;checkbox&#34;&gt; 添加消息搜索功能&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&#34;&#34; type=&#34;checkbox&#34;&gt; 实现用户权限管理&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&#34;&#34; type=&#34;checkbox&#34;&gt; 添加房间创建/删除功能&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&#34;&#34; type=&#34;checkbox&#34;&gt; 支持消息撤回&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&#34;&#34; type=&#34;checkbox&#34;&gt; 添加表情支持&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&#34;&#34; type=&#34;checkbox&#34;&gt; 实现消息推送通知&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;注意&lt;/strong&gt;：这是一个学习项目，用于演示 Go 语言 WebSocket 开发。生产环境使用时请加强安全措施。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;完整源码：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;a class=&#34;link&#34; href=&#34;https://github.com/iamxurulin/xu-AI-Zero&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;源码&lt;/a&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;如果觉得这个项目对你有帮助，欢迎点赞 👍、收藏 ⭐、关注 👀！&lt;/p&gt;
</description>
        </item>
        <item>
        <title>一文吃透TCP三次握手与四次挥手</title>
        <link>https://iamxurulin.github.io/p/%E4%B8%80%E6%96%87%E5%90%83%E9%80%8Ftcp%E4%B8%89%E6%AC%A1%E6%8F%A1%E6%89%8B%E4%B8%8E%E5%9B%9B%E6%AC%A1%E6%8C%A5%E6%89%8B/</link>
        <pubDate>Fri, 10 Apr 2026 20:10:09 +0000</pubDate>
        
        <guid>https://iamxurulin.github.io/p/%E4%B8%80%E6%96%87%E5%90%83%E9%80%8Ftcp%E4%B8%89%E6%AC%A1%E6%8F%A1%E6%89%8B%E4%B8%8E%E5%9B%9B%E6%AC%A1%E6%8C%A5%E6%89%8B/</guid>
        <description>&lt;p&gt;TCP的三次握手和四次挥手，说实话，即使背了很多很多遍，还是容易搞忘。&lt;/p&gt;
&lt;p&gt;本文，就用最直白的话梳理一下，强化记忆。&lt;/p&gt;
&lt;p&gt;首先，TCP是面向连接、保证可靠的传输层协议，和“发出去就不管”的UDP完全不一样。&lt;/p&gt;
&lt;p&gt;所以，它在正式传数据前，必须先建立可靠的连接，这就是&lt;strong&gt;三次握手&lt;/strong&gt;；&lt;/p&gt;
&lt;p&gt;数据传完要安全断开、不能丢数据，这就是&lt;strong&gt;四次挥手&lt;/strong&gt;。&lt;/p&gt;
&lt;h2 id=&#34;三次握手&#34;&gt;三次握手
&lt;/h2&gt;&lt;p&gt;TCP 三次握手的目标，是让客户端与服务端互相确认双方的收发能力正常、同步双方的初始化序列号，最终建立一条可靠的 TCP 连接。&lt;/p&gt;
&lt;h3 id=&#34;第一次握手&#34;&gt;第一次握手
&lt;/h3&gt;&lt;p&gt;客户端向服务端发送一个 同步标志位（SYN=1）的同步报文，报文中携带了自己随机生成的初始化序列号。&lt;/p&gt;
&lt;p&gt;发送完成后，客户端进入&lt;strong&gt;同步已发送&lt;/strong&gt;（SYN_SENT）状态。&lt;/p&gt;
&lt;h3 id=&#34;第二次握手&#34;&gt;第二次握手
&lt;/h3&gt;&lt;p&gt;服务端收到客户端的同步请求后，会回复一个&lt;strong&gt;同步标志位&lt;/strong&gt;（SYN=1）和&lt;strong&gt;确认标志位&lt;/strong&gt;（ACK=1）都置1的同步确认报文。&lt;/p&gt;
&lt;p&gt;这个报文里，确认号是客户端的初始化序列号 + 1，同时也会携带服务端自己随机生成的初始化序列号。&lt;/p&gt;
&lt;p&gt;发送完成后，服务端进入&lt;strong&gt;同步已收到&lt;/strong&gt;（SYN_RCVD）状态。&lt;/p&gt;
&lt;h3 id=&#34;第三次握手&#34;&gt;第三次握手
&lt;/h3&gt;&lt;p&gt;客户端收到服务端的同步确认报文后，会回复一个&lt;strong&gt;确认标志位&lt;/strong&gt;（ACK=1）的确认报文，其中确认号是服务端的初始化序列号 + 1。&lt;/p&gt;
&lt;p&gt;发送完成后，客户端直接进入&lt;strong&gt;连接已建立&lt;/strong&gt;（ESTABLISHED）状态；&lt;/p&gt;
&lt;p&gt;服务端收到这个确认报文后，也会同步进入&lt;strong&gt;连接已建立&lt;/strong&gt;状态。&lt;/p&gt;
&lt;p&gt;到这里，TCP连接就正式建立完成，双方可以开始正常传输业务数据了。&lt;/p&gt;
&lt;h3 id=&#34;为什么是三次握手不是两次&#34;&gt;为什么是三次握手，不是两次？
&lt;/h3&gt;&lt;p&gt;两次握手只能保证客户端确认服务端的收发能力正常，服务端却没法确认客户端的接收能力是正常的。&lt;/p&gt;
&lt;p&gt;官话那么多，举个例子好理解一点：&lt;/p&gt;
&lt;p&gt;如果客户端发的&lt;strong&gt;同步标志位&lt;/strong&gt;（SYN=1）报文在网络里滞留了，客户端自己都放弃了，但是，这个报文在滞留结束后，还是来到了服务端。&lt;/p&gt;
&lt;p&gt;这种情况，如果是两次握手，服务端收到后就会直接建立连接，一直等着客户端发数据，但是，客户端根本就不认这个连接，也不会发数据，这样就白白浪费了服务端的资源。&lt;/p&gt;
&lt;p&gt;而如果是三次握手，服务端收到滞留的SYN报文、回复SYN+ACK后，客户端根本不会回复第三次ACK，服务端收不到最终确认，就不会建立无效连接，完美规避了资源浪费的问题。&lt;/p&gt;
&lt;h2 id=&#34;四次挥手&#34;&gt;四次挥手
&lt;/h2&gt;&lt;p&gt;四次挥手的本质，是TCP&lt;strong&gt;全双工连接&lt;/strong&gt;的&lt;strong&gt;双向关闭&lt;/strong&gt;过程。&lt;/p&gt;
&lt;p&gt;因为TCP连接是全双工的，双方都能独立发送和接收数据，所以，断开的时候，必须保证双方的数据都完全传输完毕后，再安全断开连接，不能单方面说断就断。&lt;/p&gt;
&lt;h3 id=&#34;第一次挥手&#34;&gt;第一次挥手
&lt;/h3&gt;&lt;p&gt;客户端发送一个&lt;strong&gt;结束标志位&lt;/strong&gt;（FIN=1）的结束包，告诉服务端：&lt;/p&gt;
&lt;p&gt;我的业务数据已经全部发完了，之后不会再发送数据了。&lt;/p&gt;
&lt;p&gt;发送完成后，客户端进入&lt;strong&gt;结束等待1&lt;/strong&gt;（FIN_WAIT_1）状态。&lt;/p&gt;
&lt;h3 id=&#34;第二次挥手&#34;&gt;第二次挥手
&lt;/h3&gt;&lt;p&gt;服务端收到客户端的结束包后，立刻回复一个&lt;strong&gt;确认标志位&lt;/strong&gt;（ACK=1）的确认包，其中确认号是客户端 FIN 报文的序列号 + 1。&lt;/p&gt;
&lt;p&gt;发送完成后，服务端进入&lt;strong&gt;关闭等待&lt;/strong&gt;（CLOSE_WAIT）&lt;strong&gt;状态；&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;客户端收到这个确认包后，就会进入&lt;strong&gt;结束等待2&lt;/strong&gt;（FIN_WAIT_2）状态。&lt;/p&gt;
&lt;p&gt;这里要注意：&lt;/p&gt;
&lt;p&gt;这个阶段，客户端已经不会再发送数据了，但服务端如果还有没发完的业务数据，依然可以正常给客户端发送，客户端也会正常接收。&lt;/p&gt;
&lt;h3 id=&#34;第三次挥手&#34;&gt;第三次挥手
&lt;/h3&gt;&lt;p&gt;等服务端把所有剩余的数据都发送完毕后，也会给客户端发送一个&lt;strong&gt;结束标志位&lt;/strong&gt;（FIN=1）的结束包，告诉客户端：我的数据也全部发完了，之后也不会再发送数据了。&lt;br&gt;
发送完成后，服务端进入&lt;strong&gt;最后确认&lt;/strong&gt;（LAST_ACK）&lt;strong&gt;状态&lt;/strong&gt;。&lt;/p&gt;
&lt;h3 id=&#34;第四次挥手&#34;&gt;第四次挥手
&lt;/h3&gt;&lt;p&gt;客户端收到服务端的结束包后，立刻回复一个&lt;strong&gt;确认标志位&lt;/strong&gt;（ACK=1）的确认包，其中确认号是服务端FIN报文的序列号 + 1。&lt;/p&gt;
&lt;p&gt;发送完成后，客户端进入&lt;strong&gt;时间等待&lt;/strong&gt;（TIME_WAIT）状态，等待2MSL（最长报文寿命）的时间后，才会正式关闭连接；&lt;/p&gt;
&lt;p&gt;而服务端只要收到这个确认包，就会直接关闭连接。&lt;/p&gt;
&lt;p&gt;到这里，整个TCP连接就正式断开了。&lt;/p&gt;
&lt;h3 id=&#34;为什么握手只要三次挥手却要四次&#34;&gt;为什么握手只要三次，挥手却要四次？
&lt;/h3&gt;&lt;p&gt;握手的时候，服务端的SYN（同步报文）和ACK（确认报文）可以合并在同一个包里发送，所以三次就够了；&lt;/p&gt;
&lt;p&gt;但挥手的时候，服务端收到客户端的结束报文时，可能还有没发完的数据要继续传，所以只能先回复确认报文进行确认，等数据全部发完了，才能再发结束报文告诉客户端自己也可以关了。&lt;/p&gt;
&lt;p&gt;ACK和FIN分开发送，自然就变成了四次。&lt;/p&gt;
</description>
        </item>
        
    </channel>
</rss>
