300行代码实现go语言即时通讯聊天室_第1页
300行代码实现go语言即时通讯聊天室_第2页
300行代码实现go语言即时通讯聊天室_第3页
300行代码实现go语言即时通讯聊天室_第4页
300行代码实现go语言即时通讯聊天室_第5页
已阅读5页,还剩7页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第300行代码实现go语言即时通讯聊天室学了2年Java,因为工作原因需要转Golang,3天时间学习了下go的基本语法,做这样一个聊天室小项目来巩固串联一下语法。

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

只用到了四个类:

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

架构图

server.go

packagemain

import(

"fmt"

"io"

"net"

"sync"

"time"

typeServerstruct{

Ipstring

Portint

//在线用户列表

OnlineMapmap[string]*User

mapLocksync.RWMutex

//消息广播的Channel

Messagechanstring

funcNewServer(ipstring,portint)*Server{

server:=Server{

Ip:ip,

Port:port,

OnlineMap:make(map[string]*User),

Message:make(chanstring),

returnserver

func(s*Server)Handler(connnet.Conn){

//业务逻辑

//fmt.Println("链接建立成功")

user:=NewUser(conn,s)

user.Online()

//监听用户是否活跃

isLive:=make(chanbool)

gofunc(){

buf:=make([]byte,4096)

for{

n,error:=conn.Read(buf)

ifn==0{

user.Offline()

return

iferror!=nilerror!=io.EOF{

fmt.Println("readerror")

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.Message

s.mapLock.Lock()

for_,user:=ranges.OnlineMap{

user.C-msg

s.mapLock.Unlock()

func(s*Server)BroadCast(user*User,msgstring){

sendMsg:="["+user.Addr+"]"+user.Name+":"+msg

s.Message-sendMsg

func(s*Server)Start(){

listener,error:=net.Listen("tcp",fmt.Sprintf("%s:%d",s.Ip,s.Port))

iferror!=nil{

fmt.Println("listenererror...")

return

deferlistener.Close()

gos.ListenMessager()

for{

conn,error:=listener.Accept()

iferror!=nil{

fmt.Println("accepterror...")

continue

gos.Handler(conn)

client.go

packagemain

import(

"flag"

"fmt"

"io"

"net"

"os"

typeClientstruct{

ServerIpstring

ServerPortint

Namestring

connnet.Conn

flagint

funcNewClient(serverIpstring,serverPortint)*Client{

client:=Client{

ServerIp:serverIp,

ServerPort:serverPort,

flag:9999,

conn,error:=net.Dial("tcp",fmt.Sprintf("%s:%d",serverIp,serverPort))

iferror!=nil{

fmt.Println("netdialerror...")

returnnil

client.conn=conn

returnclient

func(c*Client)menu()bool{

varflagint

fmt.Println("1.公聊模式")

fmt.Println("2.私聊模式")

fmt.Println("3.修改用户名")

fmt.Println("0.退出")

fmt.Scanln(flag)

ifflag=0flag=3{

c.flag=flag

returntrue

}else{

fmt.Println("请输入合法数字")

returnfalse

//修改用户名

func(c*Client)UpdateName()bool{

fmt.Println("请输入用户名")

fmt.Scanln(c.Name)

sendMsg:="rename|"+c.Name+"\n"

_,error:=c.conn.Write([]byte(sendMsg))

iferror!=nil{

fmt.Println("conn.writeerror...")

returnfalse

returntrue

func(c*Client)PublicChat(){

varchatMsgstring

fmt.Println("请输入聊天内容,输入exit退出")

fmt.Scanln(chatMsg)

forchatMsg!="exit"{

iflen(chatMsg)!=0{

msg:=chatMsg+"\n"

_,error:=c.conn.Write([]byte(msg))

iferror!=nil{

fmt.Println("conn.Writeerror....")

break

chatMsg=""

fmt.Println("请输入聊天内容,输入exit退出")

fmt.Scanln(chatMsg)

func(c*Client)PrivateChat(){

varremoteUserstring

varchatMsgstring

c.SelectUsers()

fmt.Println("请输入聊天对象的用户名,输入exit退出")

fmt.Scanln(remoteUser)

forremoteUser!="exit"{

fmt.Println("请输入聊天内容,输入exit退出")

fmt.Scanln(chatMsg)

forchatMsg!="exit"{

iflen(chatMsg)!=0{

msg:="to|"+remoteUser+"|"+chatMsg+"\n\n"

_,error:=c.conn.Write([]byte(msg))

iferror!=nil{

fmt.Println("conn.Writeerror....")

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))

iferror!=nil{

fmt.Println("conn.Writeerror....")

return

//处理server返回的消息

func(c*Client)DealResponse(){

io.Copy(os.Stdout,c.conn)

func(c*Client)Run(){

forc.flag!=0{

forc.menu()!=true{

switchc.flag{

case1:

//公聊

c.PublicChat()

case2:

//私聊

c.PrivateChat()

case3:

//修改用户名

c.UpdateName()

varserverIpstring

varserverPortint

funcinit(){

flag.StringVar(serverIp,"ip","","设置服务器IP地址(默认为)")

flag.IntVar(serverPort,"port",8888,"设置服务器端口(默认为8888)")

funcmain(){

flag.Parse()

client:=NewClient(serverIp,serverPort)

ifclient==nil{

fmt.Println("链接服务器失败")

return

goclient.DealResponse()

fmt.Println("链接服务器成功")

client.Run()

user.go

packagemain

import(

"net"

"strings"

typeUserstruct{

Namestring

Addrstring

Cchanstring

connnet.Conn

server*Server

funcNewUser(connnet.Conn,server*Server)*User{

userAddr:=conn.RemoteAddr().String()

user:=User{

Name:userAddr,

Addr:userAddr,

C:make(chanstring),

conn:conn,

server:server,

gouser.ListenMessage()

returnuser

//用户上线

func(u*User)Online(){

u.server.mapLock.Lock()

u.server.OnlineMap[u.Name]=u

u.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(msgstring){

u.conn.Write([]byte(msg))

//处理消息

func(u*User)DoMessage(msgstring){

ifmsg=="who"{

//查询当前在线用户

u.server.mapLock.Lock()

for_,user:=rangeu.server.OnlineMap{

onlineMsg:="["+user.Addr+"]"+user.Name+":在线...\n"

u.SendMsg(onlineMsg)

u.server.mapLock.Unlock()

}elseiflen(msg)7msg[:7]=="rename|"{

//修改用户名rename|xxx

newName:=strings.Split(msg,"|")[1]

//判断名字是否已经存在

_,ok:=u.server.OnlineMap[newName]

ifok{

u.SendMsg("用户名已存在\n")

}else{

u.server.mapLock.Lock()

delete(u.server.OnlineMap,u.Name)

u.server.OnlineMap[newName]=u

u.server.mapLock.Unlock()

u.Name=newName

u.SendMsg

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论