go语言300行代码实现即时通讯聊天室

学了2年Java,因为工作原因需要转Golang,3天时间学习了下go的基本语法,做这样一个聊天室小项目来巩固串联一下语法。

实现的功能:公聊,私聊,修改用户名

只用到了四个类:

  • main.go:用来启动服务器
  • server.go:服务器相关代码
  • client.go:客户端相关代码,用户可以直接操作的可视化界面
  • user.go:用户类,用来封装用户的业务逻辑

架构图
在这里插入图片描述
完整代码

server.go

package mainimport ("fmt""io""net""sync""time"
)type Server struct {Ip   stringPort int//在线用户列表OnlineMap map[string]*UsermapLock   sync.RWMutex//消息广播的ChannelMessage chan string
}func NewServer(ip string, port int) *Server {server := &Server{Ip:        ip,Port:      port,OnlineMap: make(map[string]*User),Message:   make(chan string),}return server
}func (s *Server) Handler(conn net.Conn) {//业务逻辑//fmt.Println("链接建立成功")user := NewUser(conn, s)user.Online()//监听用户是否活跃isLive := make(chan bool)go func() {buf := make([]byte, 4096)for {n, error := conn.Read(buf)if n == 0 {user.Offline()return}if error != nil && error != io.EOF {fmt.Println("read error")}msg := string(buf[:n-1])user.DoMessage(msg)//表示用户活跃isLive <- true}}()for {select {case <-isLive://当前用户活跃,不做任何时,激活select,重置定时器case <-time.After(time.Second * 300)://超时,将user强制关闭user.SendMsg("你被踢了")close(user.C)conn.Close()return}}
}func (s *Server) ListenMessager() {for {msg := <-s.Messages.mapLock.Lock()for _, user := range s.OnlineMap {user.C <- msg}s.mapLock.Unlock()}
}func (s *Server) BroadCast(user *User, msg string) {sendMsg := "[" + user.Addr + "]" + user.Name + ":" + msgs.Message <- sendMsg
}func (s *Server) Start() {listener, error := net.Listen("tcp", fmt.Sprintf("%s:%d", s.Ip, s.Port))if error != nil {fmt.Println("listener error...")return}defer listener.Close()go s.ListenMessager()for {conn, error := listener.Accept()if error != nil {fmt.Println("accept error...")continue}go s.Handler(conn)}}

client.go

package mainimport ("flag""fmt""io""net""os"
)type Client struct {ServerIp   stringServerPort intName       stringconn       net.Connflag       int
}func NewClient(serverIp string, serverPort int) *Client {client := &Client{ServerIp:   serverIp,ServerPort: serverPort,flag:       9999,}conn, error := net.Dial("tcp", fmt.Sprintf("%s:%d", serverIp, serverPort))if error != nil {fmt.Println("net dial error...")return nil}client.conn = connreturn client
}func (c *Client) menu() bool {var flag intfmt.Println("1.公聊模式")fmt.Println("2.私聊模式")fmt.Println("3.修改用户名")fmt.Println("0.退出")fmt.Scanln(&flag)if flag >= 0 && flag <= 3 {c.flag = flagreturn true} else {fmt.Println(">>>>请输入合法数字<<<<")return false}
}//修改用户名
func (c *Client) UpdateName() bool {fmt.Println(">>>>请输入用户名")fmt.Scanln(&c.Name)sendMsg := "rename|" + c.Name + "\n"_, error := c.conn.Write([]byte(sendMsg))if error != nil {fmt.Println("conn.write error...")return false}return true
}//公聊
func (c *Client) PublicChat() {var chatMsg stringfmt.Println(">>>>请输入聊天内容,输入exit退出")fmt.Scanln(&chatMsg)for chatMsg != "exit" {if len(chatMsg) != 0 {msg := chatMsg + "\n"_, error := c.conn.Write([]byte(msg))if error != nil {fmt.Println("conn.Write error....")break}}chatMsg = ""fmt.Println(">>>>请输入聊天内容,输入exit退出")fmt.Scanln(&chatMsg)}
}//私聊
func (c *Client) PrivateChat() {var remoteUser stringvar chatMsg stringc.SelectUsers()fmt.Println(">>>>请输入聊天对象的用户名,输入exit退出")fmt.Scanln(&remoteUser)for remoteUser != "exit" {fmt.Println(">>>>请输入聊天内容,输入exit退出")fmt.Scanln(&chatMsg)for chatMsg != "exit" {if len(chatMsg) != 0 {msg := "to|" + remoteUser + "|" + chatMsg + "\n\n"_, error := c.conn.Write([]byte(msg))if error != nil {fmt.Println("conn.Write error....")break}}chatMsg = ""fmt.Println(">>>>请输入聊天内容,输入exit退出")fmt.Scanln(&chatMsg)}c.SelectUsers()remoteUser = ""fmt.Println(">>>>请输入聊天对象的用户名,输入exit退出")fmt.Scanln(&remoteUser)}}//查询在线用户
func (c *Client) SelectUsers() {sendMsg := "who\n"_, error := c.conn.Write([]byte(sendMsg))if error != nil {fmt.Println("conn.Write error....")return}
}//处理server返回的消息
func (c *Client) DealResponse() {io.Copy(os.Stdout, c.conn)
}
func (c *Client) Run() {for c.flag != 0 {for c.menu() != true {}switch c.flag {case 1://公聊c.PublicChat()case 2://私聊c.PrivateChat()case 3://修改用户名c.UpdateName()}}
}var serverIp string
var serverPort intfunc init() {flag.StringVar(&serverIp, "ip", "127.0.0.1", "设置服务器IP地址(默认为127.0.0.1)")flag.IntVar(&serverPort, "port", 8888, "设置服务器端口(默认为8888)")
}
func main() {flag.Parse()client := NewClient(serverIp, serverPort)if client == nil {fmt.Println(">>>>链接服务器失败")return}go client.DealResponse()fmt.Println(">>>>链接服务器成功")client.Run()
}

user.go

package mainimport ("net""strings"
)type User struct {Name   stringAddr   stringC      chan stringconn   net.Connserver *Server
}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,}go user.ListenMessage()return user
}//用户上线
func (u *User) Online() {u.server.mapLock.Lock()u.server.OnlineMap[u.Name] = uu.server.mapLock.Unlock()u.server.BroadCast(u, "上线")
}//用户下线
func (u *User) Offline() {u.server.mapLock.Lock()delete(u.server.OnlineMap, u.Name)u.server.mapLock.Unlock()u.server.BroadCast(u, "下线")
}//给当前user的客户端发送消息
func (u *User) SendMsg(msg string) {u.conn.Write([]byte(msg))
}//处理消息
func (u *User) DoMessage(msg string) {if msg == "who" {//查询当前在线用户u.server.mapLock.Lock()for _, user := range u.server.OnlineMap {onlineMsg := "[" + user.Addr + "]" + user.Name + ":在线...\n"u.SendMsg(onlineMsg)}u.server.mapLock.Unlock()} else if len(msg) > 7 && msg[:7] == "rename|" {//修改用户名 rename|xxxnewName := strings.Split(msg, "|")[1]//判断名字是否已经存在_, ok := u.server.OnlineMap[newName]if ok {u.SendMsg("用户名已存在\n")} else {u.server.mapLock.Lock()delete(u.server.OnlineMap, u.Name)u.server.OnlineMap[newName] = uu.server.mapLock.Unlock()u.Name = newNameu.SendMsg("用户名成功修改为:" + newName + "\n")}} else if len(msg) > 4 && msg[:3] == "to|" {//私聊  to|zhangsan|你好//获取对方用户名remoteName := strings.Split(msg, "|")[1]if remoteName == "" {u.SendMsg("用户名格式不对\n")return}//获取对方userremoteUser, ok := u.server.OnlineMap[remoteName]if !ok {u.SendMsg("用户不存在\n")return}//获取消息msg := strings.Split(msg, "|")[2]if msg == "" {u.SendMsg("无消息内容,重新发送\n")}//发送消息remoteUser.SendMsg(u.Name + "对您说:" + msg)} else {u.server.BroadCast(u, msg)}
}func (u *User) ListenMessage() {for {msg := <-u.Cu.conn.Write([]byte(msg + "\n"))}
}

main.go

package mainfunc main() {server := NewServer("127.0.0.1", 8888)server.Start()
}

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

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

相关文章

用微信打开链接提示“已停止访问该网页”可以用MaxJump来解除限制。

出现这种情的原因呢&#xff0c;我相信大家也去了解了很多&#xff0c;但是对于商家来说&#xff0c;我们要避免出现这种情况&#xff0c;或出现了要立马解决。了解原因再去想解决办法是技术的事情。一天没解决&#xff0c;就多一天的损失。原因大同小异&#xff0c;无非是域名…

Chrome解决访问限制SameSite设置

Cookie——SameSite属性 SameSite属性&#xff1a;Chrome浏览器为了防止CSRF攻击和用户追踪&#xff0c;Cookie的SameSite属性用来限制第三方Cookie&#xff0c;从而减少安全风险。即如调用第三方登录组件&#xff0c;会完全禁止第三方Cookie&#xff0c;跨站点时&#xff0c;…

如何给同事开通GA账户访问权限?

在很多时候&#xff0c;需要多人同事管理一个账户数据&#xff0c;那么数据需要共享。如何让大家都有可以查看的权限呢&#xff1f; GA数据查看有三个层级&#xff0c;每个层级都可以邀请他人查看权限&#xff0c;具体使用哪一个&#xff0c;看每个人的需求。 账户访问邀请权限…

禁止访问微信

微信找ip段&#xff0c;手动找了很久&#xff0c;后来用Proxifier&#xff0c;设置个假的代理ip 然后把wechat.exe加入到里面&#xff0c; 规则经过这个代理&#xff0c;默认的就直接通过&#xff0c; 然后看日志的报错信息 每次用shell wc -l统计下ip数&#xff0c;直到…

【Telegram】开启允许权限让你的TG可以实现bot直接监控频道

这篇教程教你怎么让自己的bot机器人监听群组或者频道&#xff08;不设置管理员的情况下&#xff09; 开启权限 1.首先我们TG找到BotFather 打开跟他的会话窗口&#xff0c;发送 /setprivacy 点击下面出现来的你的机器人名称。 选择第二个Disable 即可 2.如下图所示 3.出现…

限制服务器访问指定网站,如何允许或限制某一国或地区的用户访问网站

部分用户出于精准流量或其它需求&#xff0c;往往会限制某一国或地区的用户访问他们的网站&#xff0c;比如我们中文网站&#xff0c;可能会限制法国用户的访问&#xff0c;这如何去实现呢&#xff1f;我们的思路就是通过IP地址去限制。也就是说要先找到某一国或地区的IP&#…

限制guest账号访问硬盘权限

首先&#xff0c;请使用管理员账户登录系统。 打开 计算机 &#xff0c;右键单击D盘&#xff0c;选择 属性 。 在打开的窗口中依次单击 安全 选项卡&#xff0c;编辑 按钮&#xff0c;单击 添加 按钮。 在 输入对象名称来选择 的框中输入 guest &#xff0c;然后依次单击 检…

当前浏览器限制了第三方Cookie , 影响正常登录,你可以更改浏览器的隐私设置,解除限制后重试。

问题&#xff1a;如果是要在浏览器上用微信登录wps网址&#xff0c;不要用官方给的i.wps.cn&#xff0c;会一直出现标题所述的提示&#xff0c;你设置了浏览器也没用。 解决&#xff1a;登录https://account.wps.cn这个网址&#xff0c;不会弹cookie被限制提示&#xff0c;可以…

从租售比看中国房价的合理性

所谓“租售比”&#xff0c;是指每平方米使用面积的月租金与每平方米建筑面积房价之间的比值。国际通行标准认为&#xff0c;合理的房屋租售比在1:300到1:200之间。这个比值意味着如果把房子出租&#xff0c;200个至300个月&#xff08;大致相当于16年至25年&#xff09;内能收…

房地产投资占GDP比例畸高 中国房地产泡沫是一颗毒瘤

转&#xff1a; http://house.ifeng.com/detail/2014_05_04/46139202_0.shtml 房地产投资占GDP比例畸高 2013年房地产投资占GDP比例高达16%&#xff0c;而事实上从1960年来但凡房地产投资占GDP比例高于6%的国家&#xff0c;房地产泡沫都出现了破灭。而事实上&#xff0c;当年日…

终于有人把房价和汇率的关系讲清了!

http://cj.sina.com.cn/article/detail/2652907442/93864?cresinapc&modg&loc39&r0&doct0&rfunc80&tjnone&s0 房价和汇率的影响机制 首先&#xff0c;我们抽离掉其他因素&#xff0c;单单考虑汇率和房价二者的关系&#xff0c;二者变化是同向的还…

chatgpt赋能python:Python粘贴不了的原因和解决方案

Python粘贴不了的原因和解决方案 在Python编程过程中&#xff0c;我们可能会遇到粘贴代码无效的情况&#xff0c;这是非常棘手的问题&#xff0c;会导致出现各种错误和bug。本文将为您介绍Python粘贴不了的常见原因和解决方案&#xff0c;帮助您顺畅地进行Python编程。 常见原…

“为什么?是什么?怎么做?” — 关于AI安全性的几个问题

©PaperWeekly 原创 作者 | 杨靖锋 我在 2023 年 5 月 5 日开始写这篇文章的英文版&#xff0c;并在 2023 年 5 月 8 日完成了它。 英文博客原文&#xff1a; https://jingfengyang.github.io/safety Twitter原文&#xff1a; https://twitter.com/JingfengY/status/16561…

WebGLM综述以及相关工作

清华唐杰新作WebGLM&#xff1a;参数100亿、主打联网搜索&#xff0c;性能超OpenAI WebGPT github仓库地址&#xff1a;https://github.com/THUDM/WebGLM 上周五在WAIC 上的论坛报告回放。先放两个供大家参考&#xff0c;另外的报告会陆续放在 B 站。另外还有一个贴近落地实践的…

预测超级计算机排名2020,足球超级计算机预测2019/2020英超联赛排名

原标题&#xff1a;足球超级计算机预测2019/2020英超联赛排名 英超联赛很快就将拉开帷幕&#xff0c;人们都在急切地等待着。球迷们已经开始猜测他们俱乐部的最终排名怎么样了。但是光凭人们自己要想 预测英超联赛的最终结果是不可能的。但是在赛季开始之前&#xff0c;有一个足…

超级计算机预测英超 新闻,超级计算机预测英超最终排名:利物浦卫冕成功,热刺进入前四...

直播吧10月14日讯 在英超结束了前四轮比赛之后(曼城、曼联、维拉及伯恩利目前只赛三场)&#xff0c;外媒talkSPORT利用自己的超级计算机对本赛季的英超最终排名进行了一次预测&#xff0c;结果显示利物浦将卫冕成功&#xff0c;曼城、切尔西及热刺分列二至四位&#xff0c;伯恩…

计算机学院转会,2020年英超冬窗转会汇总,你主队的操作让你满意吗?

虎扑2月1日讯 本赛季英超冬窗已经正式关闭&#xff0c;我们将各支俱乐部的转会交易情况进行了汇总&#xff0c;你主队的操作有没有让你感到满意呢&#xff1f; 1、利物浦 转入&#xff1a;南野拓实(萨尔茨堡红牛)、乔-哈迪(布伦特福德) 转出&#xff1a;赫比-凯恩(赫尔城/租借)…

英国G5名校入学考试加分项目有哪些?

申请英本的同学都知道&#xff0c;学校不仅单纯考量申请者的学科成绩&#xff0c;还考察申请者某一学科的综合实力。随着竞争不断加剧&#xff0c;升学压力也越来越大&#xff0c;如何精准把握学校的“入学考试加分项”&#xff0c;是许多学生和家长都非常关心的问题。今天L老师…

【模电知识总结】三极管

文章目录 一、三极管是什么&#xff1f;二、发展历史三、结构与原理1、内部结构2、工作原理 四、伏安特性1、三极管输入特性2、三极管的输出特性 五、答疑1、把两个二极管背靠背焊接在一起&#xff0c;能否当三极管用&#xff1f;2、为什么VB要大于一个电压阈值&#xff0c;三极…

深度神经网络是谁发明的,神经网络是谁发明的人

神经网络的历史是什么&#xff1f; 沃伦麦卡洛克和沃尔特皮茨&#xff08;1943&#xff09;基于数学和一种称为阈值逻辑的算法创造了一种神经网络的计算模型。这种模型使得神经网络的研究分裂为两种不同研究思路。 一种主要关注大脑中的生物学过程&#xff0c;另一种主要关注…