GO网络编程(五):海量用户通信系统3:整体框架与C/S通信总体流程【重要】

这个系统其实是尚硅谷的老韩讲的(尚硅谷网络编程项目),但是他讲得很碎片化,思路不够清晰,时间又长,所以要掌握还是挺难的。如果你听了他的视频,不去梳理系统业务流程,不去看代码就往下听,那是很容易懵圈的。好在本人做了登录模块和服务器处理消息的业务流程图,我相信这一定有助于大家整理思路和理解系统业务流程。另外,因为老韩之后把login函数的部分代码封装到单独的包里了,所以我就干脆从头开始快速讲一遍,当然之前讲过的知识不会再讲。

目录

    • 一、系统框架搭建
    • 二、C/S通信总体流程
      • 1.登录模块总体流程
      • 2.服务器处理消息总体流程

一、系统框架搭建

首先我们需要搭建好目录结构,目录结构如下

海量用户通信系统/
├── go.mod
├── client/
│   ├── main.go
│   └── login.go
├── server/
│   └── main.go
└── common/├── message/│   └── message.go└── utils/└── utils.go

注意,模块名需要自定义,我的模块名叫MassUsrsCom。搭建好后,按如下步骤构建初步的代码:
1.在message.go中定义消息类型

package messageconst (LoginMesType    = "LoginMes"LoginResMesType = "LoginResMes"RegisterMesType = "RegisterMes"
)type Message struct {Type string `json:"type"` //消息类型Data string `json:"data"` //消息
}// 定义两个消息..后面需要再增加
type LoginMes struct {UserID   int    `json:"userID"`   //用户idUserPwd  string `json:"userPwd"`  //用户密码UserName string `json:"userName"` //用户名
}type LoginResMes struct {Code  int    `json:"code"`  //返回状态码 500表示该用户未注册 200表示登录成功Error string `json:"error"` //返回错误信息
}
type RegisterMes struct {
}

2.在utils.go中声明读数据包和写数据包的函数

package utilsimport ("MassUsrsCom/common/message""encoding/binary""encoding/json""fmt""net"
)// 读数据包
func ReadPkg(conn net.Conn) (mes message.Message, err error) {return
}// 写数据包
func WritePkg(conn net.Conn, data []byte) (err error) {return
}

3.在login.go中声明 login函数

package mainimport ("MassUsrsCom/common/message""MassUsrsCom/common/utils""encoding/json""fmt""net"
)func login(userID int, userPwd string) (err error) {return
}

4.在client包的main.go中写完整的代码

package mainimport ("fmt"
)// 定义两个变量,一个表示用户id,一个表示用户密码
var userID int
var userPwd stringfunc main() {//接收用户的选择var key int//判断是否还继续显示菜单var loop = truefor loop {fmt.Println("------------------欢迎登录多人聊天系统")fmt.Println("\t\t\t 1 登录聊天室")fmt.Println("\t\t\t 2 注册用户")fmt.Println("\t\t\t 3 退出系统")fmt.Println("\t\t\t 请选择(1-3):")fmt.Scanln(&key)switch key {case 1:fmt.Println("登录聊天室")loop = falsecase 2:fmt.Println("注册用户")loop = falsecase 3:fmt.Println("退出系统")loop = falsedefault:fmt.Println("你的输入有误,请重新输入")}}//根据用户输入显示新的提示信息if key == 1 {//说明用户要登录fmt.Printf("请输入用户的id号:")fmt.Scanf("%d\n", &userID)fmt.Printf("请输入用户的密码:")fmt.Scanf("%s\n", &userPwd)login(userID, userPwd)} else if key == 2 {fmt.Println("进行用户注册的逻辑...")}
}

5.在server包的main.go中写部分代码

package mainimport ("MassUsrsCom/common/message""MassUsrsCom/common/utils""encoding/json""fmt""io""net"
)// 处理登录消息
func serverProcessLogin(conn net.Conn, mes *message.Message) (err error) {return
}// 判断并处理不同种类的消息
func serverProcessMes(conn net.Conn, mes *message.Message) (err error) {switch mes.Type {case message.LoginMesType://处理登录逻辑err = serverProcessLogin(conn, mes)case message.RegisterMesType://处理注册default:fmt.Println("消息类型不存在,无法处理...")}return
}// 处理和客户端的通信
func process(conn net.Conn) {
}
func main() {
}

二、C/S通信总体流程

1.登录模块总体流程

流程图
在这里插入图片描述

代码

func login(userID int, userPwd string) (err error) {//下一个就要开始定协议// fmt.Printf("userId=%d pwd=%s\n", userId, pwd)// return nil//1.连接到服务器conn, err := net.Dial("tcp", "localhost:8889")if err != nil {fmt.Println("net.Dial error:", err)return}//延时关闭defer conn.Close()//2.初始化一个Mes 结构体var mes message.Messagemes.Type = message.LoginMesType//3.初始化一个LoginMes 结构体var loginMes message.LoginMesloginMes.UserID = userIDloginMes.UserPwd = userPwd//4.将loginMes 序列化data, err := json.Marshal(loginMes)if err != nil {fmt.Println("json.Marshal error:", err)return}//5.将序列化后的loginMes作为mes的Data部分mes.Data = string(data)//6.将mes序列化data, err = json.Marshal(mes)if err != nil {fmt.Println("json.Marshal error:", err)return}//7.发送消息,即mes的Data部分err = utils.WritePkg(conn, data)if err != nil {fmt.Println("WritePkg(conn) error:", err)return}//8.接收服务器端返回的信息(消息mes或错误)mes, err = utils.ReadPkg(conn) //mesif err != nil {fmt.Println("ReadPkg(conn) error:", err)return}//9.将mes的Data部分反序列化成LoginResMesvar loginResMes message.LoginResMeserr = json.Unmarshal([]byte(mes.Data), &loginResMes)if err != nil {fmt.Println("json.Unmarshal error:", err)return}//10.验证LoginResMesif loginResMes.Code == 200 {fmt.Println("登录成功")} else if loginResMes.Code == 500 {fmt.Println(loginResMes.Error)}return
}

2.服务器处理消息总体流程

流程图
在这里插入图片描述

代码

// 处理和客户端的通信
func process(conn net.Conn) {//这里需要延时关闭conndefer conn.Close()//循环读取客户端发送的信息for {mes, err := utils.ReadPkg(conn) //读取客户端消息if err != nil {if err == io.EOF {fmt.Println("客户端退出,相关的服务器协程也退出...")return} else {fmt.Println(err)return}}err = serverProcessMes(conn, &mes) //处理客户端的消息if err != nil {fmt.Println(err)return}}
}
func main() {//提示信息fmt.Println("服务器在8889端口监听")listen, err := net.Listen("tcp", "0.0.0.0:8889")if err != nil {fmt.Println("服务器监听端口失败:", err)return}defer listen.Close()//一旦监听成功,就等待客户端来连接服务器for {fmt.Println("等待客户端来连接服务器......")conn, err := listen.Accept()if err != nil {fmt.Println("客户端连接服务器失败:", err)continue}//一旦连接成功,则启动一个协程和客户端保持通信go process(conn)}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/446101.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

专题十一_递归_回溯_剪枝_综合练习_算法专题详细总结

目录 1. 找出所有⼦集的异或总和再求和(easy) 解析: 方法一: 解法二: 总结: 2. 全排列 Ⅱ(medium) 解析: 解法一:只关心“不合法”的分支 解法二&…

关于Linux下C++程序内存dump的分析和工具

前言 程序崩溃令人很崩溃,特别是让人找不到原因的崩溃,但是合适的工具可以帮助人很快的定位到问题,在AI基础能力ASR服务开发时,找到了一种比较实用和简单的内存崩溃的dump分析工具breakpad, 可以帮助在Linux下C开发程…

QD1-P8 HTML 格式化标签(font、pre、b、strong、i、u、del、s、sub、sup)

本节学习&#xff1a;HTML 格式化标签。 本节视频 www.bilibili.com/video/BV1n64y1U7oj?p8 ‍ 一、font 标签 用途&#xff1a;定义文本的字体大小、颜色和 face&#xff08;字体类型&#xff09;。 示例 <!DOCTYPE html> <html><head><meta cha…

难点:Linux 死机定位(进程虚拟地址空间耗尽)

死机定位(进程虚拟地址空间耗尽) 一、死机现象 内存富裕,但内存申请失败。 死机时打印: 怀疑是: 1、内存碎片原因导致。 2、进程虚拟地址空间耗尽导致。 3、进程资源限制导致。 二、内存碎片分析 1、理论知识:如何分析内存碎片化情况 使用 /proc/buddyinfo: /proc/…

CCF推荐被调查,这8本被标记On Hold

近两年“On Hold”期刊频出&#xff0c;作为投稿选刊风向标&#xff0c;上榜期刊一定要避雷投稿&#xff01;本期科检易学术小编盘点目前被科睿唯安官方标记为“On Hold”的计算机工程类的8本期刊&#xff0c;提醒广大学者&#xff0c;选刊需谨慎&#xff0c;注意避雷哦&#x…

Spark高级用法-内置函数

目录 读取数据 1.字符串 2.数值类 3.时间类型 4.条件判断 5.窗口函数 读取数据 # 内置数据集 from pyspark.sql import SparkSession,functions as F ss SparkSession.builder.getOrCreate()# 读取文件准尉df df ss.read.csv(hdfs://node1:8020/data/students.csv,hea…

【uniapp】使用uniapp实现一个输入英文单词翻译组件

目录 1、组件代码 2、组件代码 3、调用页面 4、展示 前言&#xff1a;使用uniapp调用一个在线单词翻译功能 1、组件代码 2、组件代码 YouDaoWordTranslator <template><view class"translator"><input class"ipttext" type"te…

JVM 内存模型与垃圾回收过程详解

JVM 内存模型与垃圾回收过程详解 文章目录 JVM 内存模型与垃圾回收过程详解1. JVM内存分区1.1 具体分区1.2 JVM内存分区的必要性 2. 垃圾回收2.1 CMS垃圾回收器2.2 G1垃圾回收器2.3 JVM垃圾回收从新生代到老年代 1. JVM内存分区 1.1 具体分区 Java虚拟机&#xff08;JVM&#…

计算机毕业设计 内蒙古旅游景点数据分析系统的设计与实现 Python毕业设计 Python毕业设计选题 Spark 大数据【附源码+安装调试】

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…

06-ArcGIS For JavaScript-requestAnimationFrame动画渲染

文章目录 概述setInterval&#xff08;&#xff09;与setTimeout()requestAnimationFrame()requestAnimationFrame在ArcGIS For JavaScript的应用结果 概述 本节主要讲解与时间相关的三个方法setTimeout()、setInterval()和requestAnimationFrame()&#xff0c;这三个方法都属…

Java每日面试题(集合)(day18)

目录 常见的集合有哪些&#xff1f;Collection和Collections有什么区别&#xff1f;ArrayList 和 Array&#xff08;数组&#xff09;的区别&#xff1f;ArrayList 和 LinkedList 的区别是什么&#xff1f;Arraylist 和 Vector 的区别HashMap和Hashtable的区别哪些集合类是线程…

计算机丢失mfc100u.dll的5种常用解决方法分享

1.mfc100u.dll的重要性 系统运行中的应用 mfc100u.dll 文件在 Windows 系统中扮演着至关重要的角色&#xff0c;尤其是在运行基于 MFC 库开发的应用程序时。以下是 mfc100u.dll 在系统运行中的应用和重要性分析&#xff1a; 系统稳定性与兼容性的关键 mfc100u.dll 文件确保…

map和set(一)

首先模拟一下key形式类 使用的结构是搜索二叉树 结点中有左孩子和右孩子 还有一个存储的值 template <class K>struct BSTnode//搜索二叉树不支持修改 中序遍历是有序的{K _key;BSTnode<K>* _left;BSTnode<K>* _right;BSTnode(const K& key):_key(key…

adum1201数字隔离器中文资料与应用

ADuM1201是ADI公司推出的一款数字隔离器&#xff0c;其典型应用有工业自动化、通讯电源管理、医疗设备以及汽车等领域。本文将对ADuM1201数字隔离器进行详细的介绍和应用分析&#xff0c;以帮助读者更好地了解和使用该产品。 一、ADuM1201数字隔离器概述 1、基本参数 ADuM120…

卷积神经网络细节问题及知识点

一、Batch Normalization Batch Normalization&#xff08;BN&#xff0c;批归一化&#xff09; 是深度学习中的一种技术&#xff0c;主要用于加速神经网络的训练过程&#xff0c;同时提高网络的稳定性和收敛速度。它通过对每一层的输出进行归一化&#xff0c;减少梯度消失和梯…

Ubuntu安装Mysql并实现远程登录【ubuntu 24.04/mysql 8.0.39】

一、安装MySQL sudo apt update # 更新软件源 sudo apt install mysql-server -y # 安装 mysql --version # 查看版本 sudo systemctl status mysql # 查看运行状态 netstat -tln # 以数字ip形式显示mysql的tcp监听状态二、设置MySQL的root密码 sudo mysql -u root # 使…

第二十三篇:网络拥塞了,TCP/IP如何解决的?

一.显示拥塞通知 当发生网络拥塞时&#xff0c;发送主机应该减少数据包的发送量。作为IP上层协议&#xff0c;TCP虽然也能控制网络拥塞&#xff0c;不过它是通过数据包的实际损坏情况来判断是否发生拥塞。然而这种方法不能在数据包损坏之前减少数据包的发送量。 为了解决这个…

pytorch与卷积神经网络实战笔记

课程视频链接 CNN卷积神经网络算法原理 全神经网络的整体结构 输入层&#xff08;x1, x2, x3…&#xff09;->隐藏层&#xff08;全连接&#xff09;->输出层&#xff0c;整体就类似于一个函数&#xff0c;输入x&#xff0c;经过函数module(x)得到输出y的过程&#xf…

笔试算法总结

文章目录 题目1题目2题目3题目4 题目1 使用 StringBuilder 模拟栈的行为&#xff0c;通过判断相邻2个字符是否相同&#xff0c;如果相同就进行删除 public class Main {public static String fun(String s) {if (s null || s.length() < 1) return s;StringBuilder builde…

闲谈Promise

预备知识 回调函数&#xff1a;当一个函数作为参数传入另一个函数中&#xff0c;并且它不会立刻执行&#xff0c;当满足一定条件之后&#xff0c;才会执行&#xff0c;这种函数称为回调函数。比如&#xff1a;定时器。异步任务&#xff1a;与之对应的概念是同步任务&#xff0…