学了2年Java,因为工作原因需要转Golang,3天时间学习了下go的基本语法,做这样一个聊天室小项目来巩固串联一下语法。
实现的功能:公聊,私聊,修改用户名
只用到了四个类:
- main.go:用来启动服务器
- server.go:服务器相关代码
- client.go:客户端相关代码,用户可以直接操作的可视化界面
- user.go:用户类,用来封装用户的业务逻辑
架构图
完整代码
server.go
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111package main import ( "fmt" "io" "net" "sync" "time" ) type Server struct { Ip string Port int //在线用户列表 OnlineMap map[string]*User mapLock sync.RWMutex //消息广播的Channel Message 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.Message s.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 + ":" + msg s.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
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177package main import ( "flag" "fmt" "io" "net" "os" ) type Client struct { ServerIp string ServerPort int Name string conn net.Conn flag 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 = conn return client } func (c *Client) menu() bool { var flag int fmt.Println("1.公聊模式") fmt.Println("2.私聊模式") fmt.Println("3.修改用户名") fmt.Println("0.退出") fmt.Scanln(&flag) if flag >= 0 && flag <= 3 { c.flag = flag return 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 string fmt.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 string var chatMsg string c.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 + "nn" _, 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 := "whon" _, 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 int func 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
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115package main import ( "net" "strings" ) type User struct { Name string Addr string C chan string conn net.Conn server *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] = 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(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|xxx newName := 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] = u u.server.mapLock.Unlock() u.Name = newName u.SendMsg("用户名成功修改为:" + newName + "n") } } else if len(msg) > 4 && msg[:3] == "to|" { //私聊 to|zhangsan|你好 //获取对方用户名 remoteName := strings.Split(msg, "|")[1] if remoteName == "" { u.SendMsg("用户名格式不对n") return } //获取对方user remoteUser, 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.C u.conn.Write([]byte(msg + "n")) } }
main.go
复制代码
1
2
3
4
5
6package main func main() { server := NewServer("127.0.0.1", 8888) server.Start() }
到此这篇关于300行代码实现go语言即时通讯聊天室的文章就介绍到这了,更多相关go语言即时通讯聊天室内容请搜索靠谱客以前的文章或继续浏览下面的相关文章希望大家以后多多支持靠谱客!
最后
以上就是温柔饼干最近收集整理的关于300行代码实现go语言即时通讯聊天室的全部内容,更多相关300行代码实现go语言即时通讯聊天室内容请搜索靠谱客的其他文章。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复