[go学习笔记.第十六章.TCP编程] 4.项目-海量用户即时通讯系统-显示在线用户列表,群聊

news2025/1/15 19:35:06

1.实现功能-完成登录时能返回当前在线用户

用户登录后,可以得到当前在线用户列表

示意图如下: 

 步骤:

(1).编写了server/processBlock/userManager.go

package processBlock

import (
    "fmt"
)

//因为UserManager实例在服务器中有且只有一个,并且在很多地方都要使用,因此,将其定义为全局变量
var (
    userManager *UserManager
)

type UserManager struct {
    onlineUsers map[int]*UserProcess
}

//完成对UserManager的初始化
func init() {
    userManager = &UserManager {
        onlineUsers: make(map[int]*UserProcess, 1024),
    }
}

//完成对onlineUsers添加
func (this *UserManager) AddOnlineUser(up *UserProcess)  {
    this.onlineUsers[up.UserId] = up
}

//完成对onlineUsers删除
func (this *UserManager) DelOnlineUser(up *UserProcess)  {
    delete(this.onlineUsers, up.UserId)
}

//返回当前所有在线用户
func (this *UserManager) GetAllOnlineUser() map[int]*UserProcess {
    return this.onlineUsers
}

//根据id返回对应的值
func (this *UserManager) GetOnlineUserById(userId int) (up *UserProcess, err error)  {
    //如何从map中取出一个值,带检测方式
    up, ok := this.onlineUsers[userId]
    if !ok { // 说明要查找的这个用户,当前不在线
        err = fmt.Errorf("用户 %d 不存在",  userId)
        return
    }
    return
}

(2).完善了sercer/processBlock/userProcess.go中的Login()方法

        loginResMes.Code = 200
        //这里用户已经登录成功,把登录成功的用户放入userManager中
        //将登录成功的用户id赋给this
        this.UserId = loginMes.UserId
        userManager.AddOnlineUser(this)
        //将当前在线用户的id放入loginResMes.UsersId中
        //遍历userManager.onlineUsers
        for id, _ := range userManager.onlineUsers {
            loginResMes.UsersId = append(loginResMes.UsersId, id)
        }
        fmt.Println("登录成功", user)

(3).完善了client/processBlock/userProcess.go中的Login()方法

if loginResMes.Code == 200 {
        // fmt.Println("登录成功") 
        //显示当前在线用户列表:loginResMes.UsersId
        fmt.Println("当前在线用户列表:")
        for _, v := range loginResMes.UsersId {
            //如果要求不显示自己在线,使用continue
            if v == userId {
                continue
            }
            fmt.Printf("用户id:%v\n", v)
        }
        fmt.Println()

        //这里需要启动一个协程,保持和服务器通讯,如果服务器有数据,则推送给客户端,客户端接收后显示在终端
        go ServerProcessMes(conn)
        //1.显示登录成功的菜单[循环显示]
        for {
            ShowMenu()
        }
    }

(4).完善了common/message/message.go中的LoginResMes ()

type LoginResMes struct {
    Code int `json:"code"` //返回状态码: 200 登录成功, 500 用户未注册
    UsersId []int   //增加一个字段:保存用户id的切片,用户返回给客户端
    Error string `json:"error"` //返回错误信息
}

2.当一个新的用户上线后,其它已经登录的用户也能获取最新在线用户列表

思路1:

1.当有一个用户上线后,服务器就马上把维护的onlieUsers map整体推送

思路2:

1.服务器有自己的策略,每隔一定的时间,把维护的onlineUsers map整体推送

思路3:

1.当一个用户A上线,服务器就把A用户的上线信息,推送给所有在线的用户

2.客户端也需要维护一个map,map中记录了他的好友(目前就是所有人)map[int]User

3.客户端和服务器的通讯通道,要依赖serverProcessMes协程

(1).server/processBlock/userProcess.go增加了方法

//编写通知所有在线用户的方法
//userId要通知其他在线用户:我上线了
func (this *UserProcess) NotifyOthersOnlineUser(userId int) {
    //遍历onlineUsers,然后一个一个地发送NotifyUserStatusMes
    for id, up := range userManager.onlineUsers {
        //过滤自己
        if id == userId {
            continue
        }
        //开始通知[单独写一个方法]
        up.NotifyMeOnline(userId)
    }
}

func (this *UserProcess) NotifyMeOnline(userId int) {
    //组装NotifyUserStatusMes
    var mes message.Message
    mes.Type = message.NotifyUserStatusMesType
    var notifyUserStatusMes message.NotifyUserStatusMes
    notifyUserStatusMes.UserId = userId
    notifyUserStatusMes.UserStatus = message.UserOnline

    //将notifyUserStatusMes序列化
    data, err := json.Marshal(notifyUserStatusMes)
    if err != nil {
        fmt.Println("NotifyMeOnline json marshal fail, err=", err)
        return
    }
    //将序列化后的notifyUserStatusMes赋值给mes.Data 
    mes.Data = string(data)
    //对mes再次序列化
    data, err = json.Marshal(mes)
    if err != nil {
        fmt.Println("NotifyMeOnline json marshal fail, err=", err)
        return
    }
    //发送,创建一个Transfer实例
    tf := &utils.Transfer {
        Conn: this.Conn,
    }
    err = tf.WritePkg(data)
    if err != nil {
        fmt.Println("NotifyMeOnline WritePkg fail, err=", err)
        return
    }
    return 
}

(2).server/processBlock/userProcess.go Login方法修改了代码

        loginResMes.Code = 200
        //这里用户已经登录成功,把登录成功的用户放入userManager中
        //将登录成功的用户id赋给this
        this.UserId = loginMes.UserId
        userManager.AddOnlineUser(this)
        //通知其他在线用户,我上线了
        this.NotifyOthersOnlineUser(loginMes.UserId)
        //将当前在线用户的id放入loginResMes.UsersId中
        //遍历userManager.onlineUsers
        for id, _ := range userManager.onlineUsers {
            loginResMes.UsersId = append(loginResMes.UsersId, id)
        }
        fmt.Println("登录成功", user)

(3).common/message/message.go增加了方法以及常量配置

//定义消息类型
const (
    LoginMesType = "LoginMes"
    LoginResMesType = "LoginResMes"
    RegisterMesType = "RegisterMes"
    RegisterResMesType = "RegisterResMes"
    NotifyUserStatusMesType = "NotifyUserStatusMes"
)

//定义几个用户状态常量
const (
    UserOnline = iota
    UserOffline
    UserBusyStatus
)
//为了配合服务端推送用户状态变化的消息
type NotifyUserStatusMes struct {
    UserId int `json:"userId"` // 用户id
    UserStatus int `json:"userStatus"` // 用户状态
}

(4).新增文件client/processBlock/userManager.go

package processBlock

import (
    "fmt"
    "go_code/chatroom/common/message"
)

//客户端要维护的map
var onlineUsers map[int]*message.User = make(map[int]*message.User, 10)

//在客户端显示当前在线用户
func outputOnlineUser() {
    //遍历onlineUsers
    fmt.Println("当前在线用户列表:")
    for id, _ := range onlineUsers {
        fmt.Println("用户id:\t", id)
    }
}
//编写一个方法,处理返回的NotifyUserStatusMes
func updateUserStatus(notifyUserStatusMes *message.NotifyUserStatusMes) {
    user, ok := onlineUsers[notifyUserStatusMes.UserId]
    if !ok { // 原来没有
        user = &message.User{
            UserId: notifyUserStatusMes.UserId,
        }       
    }
    user.UserStatus = notifyUserStatusMes.UserStatus
    onlineUsers[notifyUserStatusMes.UserId] = user

    outputOnlineUser()
}

(5).client/processBlock/server.go修改

//显示登录成功后的界面
func ShowMenu()  {
    fmt.Println("--------恭喜xxx登录成功--------")
    fmt.Println("--------1.显示在线用户列表--------")
    fmt.Println("--------2.发送消息--------")
    fmt.Println("--------3.信息列表--------")
    fmt.Println("--------4.退出系统--------")
    fmt.Println("-------请选择(1~4):----")
    var key int
    fmt.Scanf("%d\n", &key)
    switch key {
        case 1:
            // fmt.Println("显示在线用户列表")
            outputOnlineUser()
        case 2:
            fmt.Println("发送消息")
        case 3:
            fmt.Println("信息列表")
        case 4:
            fmt.Println("退出了系统")
            os.Exit(0)
        default:
            fmt.Println("输入错误,请重新输入")
    }
}

//和服务端端保持通讯
func ServerProcessMes(conn net.Conn)  {
    //创建一个Transfer实例,让它不停地读取服务器发送的消息
    tf := &utils.Transfer {
        Conn: conn,
    }
    for {
        fmt.Println("客户端正在等待读取服务器发送的消息")
        mes, err := tf.ReadPkg()
        if err != nil {
            fmt.Println("tf.readpkg err =", err)
            return
        }
        //如果读取到消息,则进行下一步逻辑处理    
        switch mes.Type {
            case message.NotifyUserStatusMesType: //有人上线了
                //1.取出NotifyUserStatusMes
                var notifyUserStatusMes message.NotifyUserStatusMes
                json.Unmarshal([]byte(mes.Data), &notifyUserStatusMes)
                //2.把这个用户的消息,保存到客户维护的map[int]User中
                updateUserStatus(&notifyUserStatusMes)
                //处理
        }
        // fmt.Printf("mes=%v\n", mes) 
    }
}

3.实现功能-完成登录后用户可以群聊 

完成客户端可以发送消息的思路

1.新增一个消息结构体SmMes

2.新增一个model CurUser

3.在smsProcess.go增加相应的方法 SendGroupMes,发送一个群聊的消息

4.在服务器端接收到SmsMes消息

5.在server/process/smsProcess.go文件增加群发消息的方法

6.在客户端还要增加去处理服务器端转发的群发消息

示意图

 步骤1:当用户上线后,可以将群聊消息发给服务器,服务器就可以接收到

(1).common/message/message.go增加方法

//定义消息类型
const (
    LoginMesType = "LoginMes"
    LoginResMesType = "LoginResMes"
    RegisterMesType = "RegisterMes"
    RegisterResMesType = "RegisterResMes"
    NotifyUserStatusMesType = "NotifyUserStatusMes"
    SmsMesType = "SmsMes"
)

//增加一个SmsMes,发送消息
type SmsMes struct {
    Content string `json:"content"`//内容
    User //匿名结构体,继承type User struct
}

(2).新建文件client/model/curUser.go

package model

import(
    "net"
    "go_code/chatroom/common/message"
)

//该结构体目的:维护当前连接
//在客户端很多地方会使用到CurUser,所以将其作为一个全局的,放在userManager.go中统一管理

type CurUser struct {
    Conn net.Conn
    message.User
}

(3).client/processBlock/smsProcess.go增加方法

package processBlock

import (
    "fmt"
    "encoding/json"
    "go_code/chatroom/common/message"
    "go_code/chatroom/client/utils"
)

type SmsProcess struct {

}

//发送群聊消息
func (this *SmsProcess) SendGroupMes(content string) (err error) {
    //1.创建一个mes
    var mes message.Message
    mes.Type = message.SmsMesType
    //2.创建smsMes实例
    var smsMes message.SmsMes
    smsMes.Content = content
    smsMes.UserId = curUser.UserId
    smsMes.UserStatus = curUser.UserStatus
    //3.序列化smsMes
    data, err := json.Marshal(smsMes)
    if err != nil {
        fmt.Println("SendGroupMes json Marshal smsMes fail, err = ", err)
        return
    }
    //4.给mes.Data赋值
    mes.Data = string(data)
    //5.再次序列化mes
    data, err = json.Marshal(mes)
    if err != nil {
        fmt.Println("SendGroupMes json Marshal mes fail, err = ", err)
        return
    }
    //6.将mes发送给服务器
    tf := &utils.Transfer{
        Conn: curUser.Conn,
    }
    err = tf.WritePkg(data)
    if err != nil {
        fmt.Println("SendGroupMes transfer writePkg fail, err = ", err)
        return
    }
    return 
}   

(4).client/processBlock/userProcess.go Login()方法初始化CurUser结构体

//初始化CurUser
        curUser.Conn = conn
        curUser.UserId = userId
        curUser.UserStatus = message.UserOnline

        // fmt.Println("登录成功") 
        //显示当前在线用户列表:loginResMes.UsersId
        fmt.Println("当前在线用户列表:")
        for _, v := range loginResMes.UsersId {
            //如果要求不显示自己在线,使用continue
            if v == userId {
                continue
            }
            fmt.Printf("用户id:%v\n", v)
            //完成客户端的onlineUsers完成初始化
            user := &message.User {
                UserId: v,
                UserStatus: message.UserOnline,
            }
            onlineUsers[v] = user
        }
        fmt.Println()

        //这里需要启动一个协程,保持和服务器通讯,如果服务器有数据,则推送给客户端,客户端接收后显示在终端
        go ServerProcessMes(conn)
        //1.显示登录成功的菜单[循环显示]
        for {
            ShowMenu()
        }

(5).client/processBlock/server.go调用群聊方法

//显示登录成功后的界面
func ShowMenu()  {
    fmt.Println("--------恭喜xxx登录成功--------")
    fmt.Println("--------1.显示在线用户列表--------")
    fmt.Println("--------2.发送消息--------")
    fmt.Println("--------3.信息列表--------")
    fmt.Println("--------4.退出系统--------")
    fmt.Println("-------请选择(1~4):----")
    var key int
    var content string

    //有时候总会使用SmsProcess实例,故把该实例定义在switch外面
    smsProcess := &SmsProcess{}
    fmt.Scanf("%d\n", &key)
    switch key {
        case 1:
            // fmt.Println("显示在线用户列表")
            outputOnlineUser()
        case 2:
            fmt.Println("请输入想对大家说的话:")
            fmt.Scanf("%s\n", &content)
            smsProcess.SendGroupMes(content)
        case 3:
            fmt.Println("信息列表")
        case 4:
            fmt.Println("退出了系统")
            os.Exit(0)
        default:
            fmt.Println("输入错误,请重新输入")
    }
}

步骤2:服务器可以将接收到的消息,群发给所有在线用户(发送者除外)

完成客户端可以发送消息的思路

1.新增一个消息结构体SmMes 

2.新增一个model CurUser

3.在smsProcess.go增加相应的方法 SendGroupMes,发送一个群聊的消息

4.在服务器端接收到SmsMes消息

5.在server/process/smsProcess.go文件增加群发消息的方法

6.在客户端还要增加去处理服务器端转发的群发消息SmsMes

(1).server/processBlock/smsProcess.go新增方法

package processBlock

import(
    "fmt"
    "net"
    "encoding/json"
    "go_code/chatroom/common/message"
    "go_code/chatroom/server/utils"
)

type SmsProcess struct {

}

//转发消息
func (this *SmsProcess) SendGroupMes(mes *message.Message)  {
    //遍历服务器端的onlineUsers map[int]*UserProcess
    //将消息转发出去
    //取出mes中的内容
    var smsMes message.SmsMes
    err := json.Unmarshal([]byte(mes.Data), &smsMes)
    if err != nil {
        fmt.Println("SendGroupMes json Ummarshal fail, err = ", err)
        return
    }

    data, err := json.Marshal(mes)
    if err != nil {
        fmt.Println("SendGroupMes json Marshal fail, err = ", err)
        return
    }
    for id, up := range userManager.onlineUsers {
        //过滤自己:不需要给自己发送消息
        if id == smsMes.UserId {
            continue
        }       
        this.SendMesToEachOnlineUser(data, up.Conn)
    }
}

func (this *SmsProcess) SendMesToEachOnlineUser(data []byte, conn net.Conn) {
    //创建一个Transfer实例,发送data
    tf := &utils.Transfer {
        Conn : conn,
    }
    err := tf.WritePkg(data)
    if err != nil {
        fmt.Println("转发消息失败, err = ", err)
    }
    return 
}

 (2).server/main/processor.go中调用smsProcess. SendGroupMes()方法

//编写一个ServerProcessMes函数
//功能:根据客户端发送消息类型不同,决定调用哪个函数来处理
func (this *Processor) serverProcessMes(mes *message.Message) (err error)  {
    switch mes.Type {
        case message.LoginMesType : 
            //处理登录消息
            //创建一个UserProcess
            up := &processBlock.UserProcess{
                Conn: this.Conn,
            }
            err = up.ServerProcessLogin(mes)
        case message.RegisterMesType : 
            //处理注册
            up := &processBlock.UserProcess{
                Conn: this.Conn,
            }
            err = up.ServerProcessRegister(mes)
        case message.SmsMesType : 
            //穿甲一个SmsProcess实例,完成消息的转发
            sms := &processBlock.SmsProcess{}
            sms.SendGroupMes(mes)
        default :
            fmt.Println("消息类型不存在, 无法处理...")
    }
    return
}

(3).client/processBlock/smsManager.go 新增方法

package processBlock

import(
    "fmt"
    "encoding/json"
    "go_code/chatroom/common/message"
)

//该文件目前是为了处理输出消息相关逻辑

func outputGroupMes(mes *message.Message)  { //这个地方mes一定是smsMes
    //显示
    //1.反序列化mes
    var smsMes message.SmsMes
    err := json.Unmarshal([]byte(mes.Data), &smsMes)
    if err != nil {
        fmt.Println("outputGroupMes json.Unmarshal fail, err =", err)
        return
    }
    //显示消息
    info := fmt.Sprintf("用户:%d\t,对大家说:%s", smsMes.UserId, smsMes.Content)
    fmt.Println(info)
}

(4).client/processBlock/server.go中调用方法 smsManger.outputGroupMes()

//和服务端端保持通讯
func ServerProcessMes(conn net.Conn)  {
    //创建一个Transfer实例,让它不停地读取服务器发送的消息
    tf := &utils.Transfer {
        Conn: conn,
    }
    for {
        fmt.Println("客户端正在等待读取服务器发送的消息")
        mes, err := tf.ReadPkg()
        if err != nil {
            fmt.Println("tf.readpkg err =", err)
            return
        }
        //如果读取到消息,则进行下一步逻辑处理    
        switch mes.Type {
            case message.NotifyUserStatusMesType: //有人上线了
                //1.取出NotifyUserStatusMes
                var notifyUserStatusMes message.NotifyUserStatusMes
                json.Unmarshal([]byte(mes.Data), &notifyUserStatusMes)
                //2.把这个用户的消息,保存到客户维护的map[int]User中
                updateUserStatus(&notifyUserStatusMes)
                //处理
            case message.SmsMesType:  //有人群发消息了
                outputGroupMes(&mes)
        default:
                fmt.Println("")
        }
        // fmt.Printf("mes=%v\n", mes) 
    }

[上一节][go学习笔记.第十六章.TCP编程] 3.项目-海量用户即时通讯系统-redis介入,用户登录,注册

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

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

相关文章

博客系统前端页面

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 目录 博客系统 前言 一.预期效果 博客列表页效果 博客正文页效果 博客登录页效果 博客编辑页效果 二.实现博客列表页 实现导航栏 实现版心 实现个人信息 …

【DELM分类】基于matlab麻雀搜索算法改进深度学习极限学习机数据分类【含Matlab源码 2235期】

⛄一、麻雀搜索算法改进深度学习极限学习机数据分类 1 深度极限学习机 深度极限学习机算法(Deep Extreme Learning Machine, DELM)又称多层极限学习机.存在N个训练样本,其中 2 麻雀搜索算法(SSA) 2020年,薛建凯等人提出了麻雀搜索算法.麻雀搜索算法是一…

python判断语句

一、布尔类型和比较运算符 布尔类型 只有两个结果 是 / 否 定义变量存储布尔类型数据: 变量名称布尔类型字面量 布尔类型的数据不仅可以通过定义得到也可以通过比较运算符比较内容得到 比较运算符: 二、if判断语句基本格式 程序中的判断&#…

如何鉴别一个成功的Scrum 教练?

成功的Scrum教练:如何鉴别一个成功的Scrum教练?了解更多关于优秀的Scrum专家的特征。 前言: 成功的Scrum 教练 - 我认为的九大标准 如何判别Scrum 教练是否是合格的?Scrum 教练成功的标准是什么?经常使用Confluence回顾性模板是不…

java创建线程的方式到底有几种?(详解)

创建线程的方式到底有几种?一,创建多线程的方式1,官方解释2,实现Runnable接口3,继承Thread类3,二者区别3.1,本质区别3.2,优先考虑使用第一种二,误以为是创建线程的几种新…

react(子传父、父传子)

目录 1. 父传子 数组/对象 的两种写法 2. 子传父&#xff1a; 3. 生成唯一id的库&#xff1a; 4. 对接收的组件进行验证 1. 父传子 数组/对象 的两种写法 function App() {const obj [{age:19},{age:19}]return (<div className"App"><header classNa…

Jmeter常用参数化技巧总结

说起接口测试&#xff0c;相信大家在工作中用的最多的还是Jmeter。 JMeter是一个100&#xff05;的纯Java桌面应用&#xff0c;由Apache组织的开放源代码项目&#xff0c;它是功能和性能测试的工具。具有高可扩展性、支持Web(HTTP/HTTPS)、SOAP、FTP、JAVA 等多种协议。 在做…

uniapp之使用map组件显示接收过来的经纬度

目录 前言 效果图 提示 总代码 分析 1.显示自己位置的属性 2.markers 点标记 前言 由于项目的需求&#xff0c;我需要从主页面接收经纬度&#xff0c;并渲染至地图上面&#xff0c;同时呢&#xff0c;也要在该位置上显示图标标记点&#xff08;红色&#xff09;&#x…

兴业数金 测试 面试真题|面经

兴业数金测试服务中心技术面&#xff08; 一面二面&#xff09; 时间线流程 8.12一面&#xff08;30min&#xff09;->8.31邮件通知二面&#xff0c;填写职位申请表->9.2二面&#xff08;25min&#xff0c;二面需要用小鱼易连&#xff0c;需提前下载和注册&#xff09; …

儿童台灯怎么选对眼睛最好?2022年的现在如何挑选儿童台灯呢

儿童台灯选择首要考虑因素就是护眼&#xff0c;而是否护眼&#xff0c;可以从以下几个角度去看。 一、照度。根据国家标准划分&#xff0c;照度可分为国A和国AA两级&#xff0c;它们可以衡量光线明亮程度和均匀程度&#xff0c;儿童台灯选择国AA级对眼睛最好。 二、显色指数。…

Java#19(面向对象三大特征之一:多态)

目录 一.多态 二.多态中调用成员的特点 三.instanceof关键字 一.多态 多态:同类型的对象,表现出的不同形态 格式:父类类型 对象名称 子类对象; 前提: (1)有继承关系 (2)有父类引用指向子类对象 (3)有方法重构 优点: (1)使用父类作为参数,可以接收所有子类对象 (2)体现多态的…

科技金融企业助力乡村振兴,能有多大新意?

最近几年&#xff0c;越来越多科技互联网企业开始承担起他们的社会责任&#xff0c;成为乡村振兴领域一股不可忽视的力量。作为电商平台&#xff0c;阿里、拼多多、京东助力农产品上行&#xff0c;解决农产品的销售难题&#xff0c;直接为乡村振兴领域做出大贡献&#xff0c;但…

罗丹明PEG活性酯 RB-PEG-NHS,罗丹明聚乙二醇活性酯,Rhodamine-PEG-NHS

产品名称 罗丹明聚乙二醇活性酯 RB-PEG-NHS 中文名称 罗丹明PEG活性酯 活性酯PEG罗丹明 活性酯聚乙二醇罗丹明 英文名称 RB-PEG-NHS RB-PEG-SC Rhodamine-PEG-NHS 分子量 400 600 1000 2000 3400 5000 10000 结构式&#xff1a; CAS N/A 溶解度 溶于DMSO,DMF,DCM&#xff…

Linux进阶-编译工具链

gcc编译器&#xff08;预处理、编译&#xff09; binutils工具集&#xff08;汇编、链接&#xff09; 本地编译&#xff1a;编译工具链和目标程序运行在相同的架构平台。 交叉编译&#xff1a;编译工具链和目标程序运行在不同的架构平台。 ARM-GCC是GCC编译工具链的一个分支…

Spring Data JPA审计

Spring Data JPA为跟踪持久性层的变化提供了很好的支持。通过使用审核&#xff0c;我们可以存储或记录有关实体更改的信息&#xff0c;例如谁创建或更改了实体以及何时进行更改。 我们可以利用实体字段上的CreatedBy,CreatedDate,LastModifiedDate,LastModifiedBy注释来指示 S…

PointNet 和 PointNet++ 作者讲座学习笔记

文章目录前人的工作三维数据的表达形式把点云转化为体素&#xff0c;再用3D CNNPointNet两个挑战置换不变性旋转不变性PointNet的分类网络PointNet的分割网络PointNet的限制PointNet多级点云特征学习分类分割小区域大小参考资料前人的工作 三维数据的表达形式 点云&#xff1…

Adaptive AUTOSAR Technology Sharing

文章目录一、目录二、未来汽车基础设施需求三、整车架构四、CP vs AP五、AP架构1.Execution Management与State Management的关系2.Service-oriented communication2.Diagnostic Management3.Persistency4.Log and Trace5.安全支持6.安全方法7.信息安全8. AutoSar&#xff1a;T…

Selenium4之CDP

相较于以前的版本&#xff0c;Selenium4除了推出了relative Locators&#xff0c;还有一个比较重要的更新就是对于Chrome Dev Tools Protocol的支持。 Chrome Dev Tools Protocol帮助用户监测、检查、调试和模版化Chrome浏览器以及基于Chromium的其它浏览器&#xff08;比如EDG…

Spring Boot 2.x系列【27】应用篇之代码混淆

有道无术&#xff0c;术尚可求&#xff0c;有术无道&#xff0c;止于术。 本系列Spring Boot版本2.7.0 文章目录概述代码混淆ProGuard使用Maven 插件直接使用工具混淆概述 代码混淆 代码混淆(Obfuscated code)亦称花指令&#xff0c;是将计算机程序的代码&#xff0c;转换成…

创建.NET MAUI程序

.NET MAUI&#xff0c;先说说读音&#xff0c;Maui&#xff0c;英 [ˈmaui]&#xff0c; 美 [ˈmaʊi]&#xff0c;直接读&#xff1a;毛伊&#xff0c;或者读大写字母MAUI。 .NET 多平台应用 UI (.NET MAUI) 是一个跨平台框架&#xff0c;用于使用 C# 和 XAML 创建本机移动和…