IMV5.0

news2024/11/27 21:13:16

背景内容:

经历了多个版本,基础内容在前面,可以使用之前的基础环境:

v1:
https://blog.csdn.net/wtt234/article/details/132139454

v2:
https://blog.csdn.net/wtt234/article/details/132144907

v3:
https://blog.csdn.net/wtt234/article/details/132148572

v4:
https://blog.csdn.net/wtt234/article/details/132169338

一、修改内容

二、代码

2.1main.go

package main

func main() {
	server := NewServer("127.0.0.1", 8000)
	server.Start()
}

2.2server.go

package main

import (
	"fmt"
	"io"
	"net"
	"sync"
)

type Server struct {
	Ip   string
	Port int

	//在线用户的列表
	OnlineMap map[string]*User
	mapLock   sync.RWMutex

	//消息广播的channel
	Message chan string
}

//创建一个server的接口
func NewServer(ip string, port int) *Server {
	server := &Server{
		Ip:        ip,
		Port:      port,
		OnlineMap: make(map[string]*User),
		Message:   make(chan string),
	}

	return server
}

//监听Message广播消息channel的goroutine,一旦有消息就发送给全部的在线User
func (this *Server) ListenMessager() {
	for {
		msg := <-this.Message

		//将msg发送给全部的在线User
		this.mapLock.Lock()
		for _, cli := range this.OnlineMap {
			cli.C <- msg
		}
		this.mapLock.Unlock()
	}
}

//广播消息的方法
func (this *Server) BroadCast(user *User, msg string) {
	sendMsg := "[" + user.Addr + "]" + user.Name + ":" + msg

	this.Message <- sendMsg
}

func (this *Server) Handler(conn net.Conn) {
	//...当前链接的业务
	//fmt.Println("链接建立成功")

	user := NewUser(conn, this)

	user.Online()

	//接受客户端发送的消息
	go func() {
		buf := make([]byte, 4096)
		for {
			n, err := conn.Read(buf)
			if n == 0 {
				user.Offline()
				return
			}

			if err != nil && err != io.EOF {
				fmt.Println("Conn Read err:", err)
				return
			}

			//提取用户的消息(去除'\n')
			msg := string(buf[:n-1])

			//用户针对msg进行消息处理
			user.DoMessage(msg)
		}
	}()

	//当前handler阻塞
	select {}
}

//启动服务器的接口
func (this *Server) Start() {
	//socket listen
	listener, err := net.Listen("tcp", fmt.Sprintf("%s:%d", this.Ip, this.Port))
	if err != nil {
		fmt.Println("net.Listen err:", err)
		return
	}
	//close listen socket
	defer listener.Close()

	//启动监听Message的goroutine
	go this.ListenMessager()

	for {
		//accept
		conn, err := listener.Accept()
		if err != nil {
			fmt.Println("listener accept err:", err)
			continue
		}

		//do handler
		go this.Handler(conn)
	}
}

2.3user.go

package main

import "net"

type User struct {
	Name string
	Addr string
	C    chan string
	conn net.Conn

	server *Server
}

//创建一个用户的API
func NewUser(conn net.Conn, server *Server) *User {
	userAddr := conn.RemoteAddr().String()

	user := &User{
		Name: userAddr,
		Addr: userAddr,
		C:    make(chan string),
		conn: conn,

		server: server,
	}

	//启动监听当前user channel消息的goroutine
	go user.ListenMessage()

	return user
}

//用户的上线业务
func (this *User) Online() {

	//用户上线,将用户加入到onlineMap中
	this.server.mapLock.Lock()
	this.server.OnlineMap[this.Name] = this
	this.server.mapLock.Unlock()

	//广播当前用户上线消息
	this.server.BroadCast(this, "已上线")
}

//用户的下线业务
func (this *User) Offline() {

	//用户下线,将用户从onlineMap中删除
	this.server.mapLock.Lock()
	delete(this.server.OnlineMap, this.Name)
	this.server.mapLock.Unlock()

	//广播当前用户上线消息
	this.server.BroadCast(this, "下线")

}

//给当前User对应的客户端发送消息
func (this *User) SendMsg(msg string) {
	this.conn.Write([]byte(msg))
}

//用户处理消息的业务
func (this *User) DoMessage(msg string) {
	if msg == "who" {
		//查询当前在线用户都有哪些

		this.server.mapLock.Lock()
		for _, user := range this.server.OnlineMap {
			onlineMsg := "[" + user.Addr + "]" + user.Name + ":" + "在线...\n"
			this.SendMsg(onlineMsg)
		}
		this.server.mapLock.Unlock()

	} else {
		this.server.BroadCast(this, msg)
	}
}

//监听当前User channel的 方法,一旦有消息,就直接发送给对端客户端
func (this *User) ListenMessage() {
	for {
		msg := <-this.C

		this.conn.Write([]byte(msg + "\n"))
	}
}

三、客户端登录

3.1服务运行

go run main.go server.go user.go 
 

 3.2客户端运行

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

04-8_Qt 5.9 C++开发指南_QTableWidget的使用

文章目录 1. QTableWidget概述2. 源码2.1 可视化UI设计2.2 程序框架2.3 qwintspindelegate.h2.4 qwintspindelegate.cpp2.5 mainwindow.h2.6 mainwindow.cpp 1. QTableWidget概述 QTableWidget是Qt中的表格组件类。在窗体上放置一个QTableWidget 组件后,可以在 PropertyEditor…

二、 MySQL 内部技术架构

二、 MySQL 内部技术架构 047 Mysql内部支持缓存查询吗&#xff1f; 当MySQL接收到客户端的查询SQL之后&#xff0c;仅仅只需要对其进行相应的权限验证之后&#xff0c;就会通过Query Cache来查找结果&#xff0c;甚至都不需要经过Optimizer模块进行执行计划的分析优化&…

产品缺陷管理软件:了解功能与选择要点

在现代社会&#xff0c;产品缺陷管理软件已经成为了各个行业必不可少的工具。它可以帮助企业更好地管理和解决产品中存在的缺陷问题&#xff0c;提高产品质量和客户满意度。然而&#xff0c;市场上存在着众多的产品缺陷管理软件&#xff0c;如何选择一款好用、适合自己的软件成…

Java实现数字加密

Java实现数字加密 需求分析代码实现小结Time 需求分析 1.首先&#xff0c;考虑方法是否需要接收数据处理&#xff1f; 需要一个4位数&#xff0c;至于是哪一个数&#xff0c;让方法的调用者传递。 所以&#xff0c;方法的参数&#xff0c;就是这个需要加密的四位数 2.接着&…

Unity 编辑器资源导入处理函数 OnPostprocessAudio :深入解析与实用案例

Unity 编辑器资源导入处理函数 OnPostprocessAudio 用法 点击封面跳转下载页面 简介 在Unity中&#xff0c;我们可以使用编辑器资源导入处理函数&#xff08;OnPostprocessAudio&#xff09;来自定义处理音频资源的导入过程。这个函数是继承自AssetPostprocessor类的&#xff…

电压信号转电流信号

用运算放大器配置电流&#xff0c;使其既能做同相放大电路&#xff0c;也能把电压转化为电流信号 1、当SW1断开情况下&#xff0c;OUT的电压仅受U1.3产生的同相放大电路有关&#xff0c;把0-3V输入转换成0-10V 2、当SW1闭合时 设输入INT的电压信号为Vi&#xff0c;负载电阻R8的…

04-7_Qt 5.9 C++开发指南_QTreeWidget和QDockWidget

文章目录 1. 实例功能简述2. 源码2.1 可视化UI设计2.2 mainwindow.h2.3 mainwindow.cpp 1. 实例功能简述 本节介绍 QTreeWidget、QDockWidget 的使用&#xff0c;以及用 QLabel 显示图片的方法。实例 samp4_8以QTreeWidget 为主要组件&#xff0c;创建一个照片管理器&#xff…

分享:2023新手做闲鱼电商如何轻松过万。详细步骤分享

科思创业汇 大家好&#xff0c;这里是科思创业汇&#xff0c;一个轻资产创业孵化平台。赚钱的方式有很多种&#xff0c;我希望在科思创业汇能够给你带来最快乐的那一种&#xff01; 如果一个人想赚很多钱&#xff0c;他必须学会从小钱开始。如果他想赚一点钱&#xff0c;他必…

springboot(2)

springmvc 把软件系统分为3个基本部分&#xff1a;模型&#xff08;Model&#xff09;、视图&#xff08;View&#xff09;和控制器 &#xff08;Controller&#xff09;。 模型&#xff08;Model&#xff09;&#xff1a;Model是由一个实体Bean实现的&#xff0c;是数据的载体…

Modbus TCP转Profibus DP网关modbus tcp报文解析

捷米JM-DPM-TCP网关。在Profibus总线侧作为主站&#xff0c;在以太网侧作为ModbusTcp服务器功能&#xff0c; 下面是介绍捷米JM-DPM-TCP主站网关组态工具的配置方法 2, Profibus主站组态工具安装 执行资料光盘中的安装文件setup64.exe或setup.exe安装组态工具。安装过程中一直…

画原型只需6招,快速成原型图!

画原型图&#xff0c;是产品设计过程中的重头戏。一个优秀的原型图&#xff0c;能把设计理念以视觉的形式呈现出来&#xff0c;让团队感受产品的交互和体验&#xff0c;明确下一步要做什么。那么&#xff0c;怎样才能画出高质量的原型图呢&#xff1f;下面就来介绍几招实用的技…

文件传输软件的市场现状和未来趋势

文件传输软件是一种能够在不同计算机之间高效、便捷、安全地传送各种类型的文件的应用软件。它是计算机领域中的一项重要技术&#xff0c;涉及到网络通信、数据加密、文件管理等多个方面。随着互联网和移动互联网的发展&#xff0c;文件传输软件的市场需求也日益增大&#xff0…

每日汇评:在50日移动均线下方,黄金的下行势头依然强劲

1、黄金价格连续第二天下跌&#xff0c;美元在周五的抛售后恢复稳定&#xff1b; 2、在中国和美国公布关键通胀数据之前&#xff0c;投资者保持谨慎&#xff1b; 3、在日相对强弱指数(RSI)偏弱的情况下&#xff0c;金价在持续跌破1925美元的情况下&#xff0c;可能跌至1910美…

嵌入式开发学习(STC51-3-点亮led)

内容 点亮第一个led&#xff1b; led闪烁&#xff1b; led流水灯&#xff1b; led简介 led即发光二极管&#xff0c;它具有单向导电性&#xff0c;通过5mA左右电流即可发光&#xff0c;电流越大&#xff0c;其亮度越强&#xff0c;但若电流过大&#xff0c;会烧毁二极管&…

Matplotlib引领数据图表绘制

Matplotlib引领数据图表绘制 前言图像得组成画图设置 figure设置标题设置坐标轴设置 label 和 legend添加注释使用子图中文乱码解决保存图形显示图形条形图直方图散点图饼状图 总结 前言 在数据科学领域&#xff0c;数据可视化是一种强大的工具&#xff0c;能够将复杂的数据转…

Redis单机,主从,哨兵,集群四大模式

Redis 单机模式 Redis 单机模式是指 Redis 数据库在单个服务器上以独立的、单一的进程运行的模式。在这种模式下&#xff0c;Redis 不涉及数据分片或集群配置&#xff0c;所有的数据和操作都在一个实例中进行。以下是关于 Redis 单机模式的详细介绍&#xff1a; 单一实例&#…

数据连接,图文档与BOM数据紧密相连

在现代制造业的产品开发和生产过程中&#xff0c;图文档和BOM数据是不可或缺的重要信息。图文档记录了产品的设计和工程数据&#xff0c;而BOM数据明确了产品所需物料的清单和规格。然而&#xff0c;由于图文档和BOM数据分属不同的系统&#xff0c;数据之间的连接和共享往往成为…

赢在起跑线:美国计算机读研规划攻略

以下是一个去美国学计算机的读研规划&#xff0c;供您参考&#xff1a;01 基础准备 学术准备&#xff1a;在本科阶段&#xff0c;您需要确保已经掌握了计算机科学的基本知识和技能&#xff0c;包括计算机体系结构、编程语言、数据结构和算法等。同时&#xff0c;建议您参与一…

[学习笔记]微信小程序全套开发流程(ing)

https://www.bilibili.com/video/BV1mV4y1o7fu 1.整体概述 2.环境搭建 略 4.纯净版项目 5.快速入门 5.1组件(类似HTML标签) wxml中的标签html中的标签textspanviewdivimageimgiconnavigatora view组件 <view><view class"c0">学生&#xff1a;<…

怎样理解黑盒测试和白盒测试?二者有什么关系

按照使用的测试技术可以将软件测试分为黑盒测试与白盒测试。 &#xff08;1&#xff09;黑盒测试 黑盒测试就是把软件(程序)当作一个有输入与输出的黑匣子&#xff0c;它把程序当作一个输入域到输出域的映射&#xff0c;只要输入的数据能输出预期的结果即可&#xff0c;不必关…