基于Go写一个极简的通讯demo
提示
该demo来源于B站教程视频【8小时转职Golang工程师(如果你想低成本学习Go语言)】 https://www.bilibili.com/video/BV1gf4y1r79E/?p=52&share_source=copy_web&vd_source=727d145bfa2bc1ec2bdd67cf624091fc 我跟随教程视频写的一个简单的demo, 用于巩固基础 其中根据自身习惯修改了部分代码 源码仓库: https://github.com/hidewnd/imDemo.git 其中可能包含一些错误逻辑和,欢迎指正
window环境
客户端构建:go build -o client.exe .\client.go
服务端构建:go build - go build -o server.exe .\main.go .\server.go .\User.go
# 定义服务端
# Server具体实现
结构体
type Server struct {
//服务端的IP地址
Ip string
//服务端的IP端口
Port int
// 在线用户
OnlineUserMap map[string]*User
// 在线用户map的同步锁
mapLock sync.RWMutex
// 消息广播channel
Message chan string
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
创建Server接口
func NewServer(ip string, port int) *Server {
server := &Server{
Ip: ip,
Port: port,
OnlineUserMap: make(map[string]*User),
Message: make(chan string),
}
return server
}
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
监听用户上线
// BroadCast 服务端发送广播消息
func (s *Server) BroadCast(user *User, msg string) {
sendMsg := "[" + user.Addr + "]" + user.Name + ":" + msg
s.Message <- sendMsg
}
// ListenMessage 在线用户监听器
func (s *Server) ListenMessage() {
for {
msg := <-s.Message
s.mapLock.Lock()
for _, cli := range s.OnlineUserMap {
cli.C <- msg
}
s.mapLock.Unlock()
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
服务端对用户消息的处理器
// Handler handler处理
func (s *Server) Handler(conn net.Conn) {
fmt.Print("链接建立成功")
// 加入在线用户集
user := NewUser(conn, s)
user.Online()
fmt.Println("[" + user.Addr + "]" + user.Name + ": online...")
isLive := make(chan bool)
// 广播用户发送信息
go func() {
buf := make([]byte, 4096)
for {
n, err := conn.Read(buf)
if n == 0 {
user.Offline()
fmt.Println("[" + user.Addr + "]" + user.Name + ": offline...")
return
}
if err != nil && err != io.EOF {
fmt.Println("conn Read err:", err)
return
}
fmt.Println("[" + user.Addr + "]" + user.Name + ":" + string(buf))
// 提取用户信息 去除 '\n' msg := string(buf[:n-1])
user.DoMessage(msg)
}
}()
// 超时强制退出监听检测处理
for {
select {
case <-isLive:
case <-time.After(time.Second * 60):
user.DoMessage("You have been forced offline\n")
fmt.Println("[" + user.Addr + "]" + user.Name + ": have been forced offline")
close(user.C)
err := conn.Close()
if err != nil {
return
}
}
}
}
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
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
服务端启动器
func (s *Server) Start() {
listener, err := net.Listen("tcp", fmt.Sprintf("%s:%d", s.Ip, s.Port))
if err != nil {
fmt.Println("net.listener err:", err)
return
}
defer func(listener net.Listener) {
err := listener.Close()
if err != nil {
fmt.Println("net.listener err:", err)
}
}(listener)
// 启动在线用户监听
go s.ListenMessage()
fmt.Println("start success....")
for {
// accept
conn, err := listener.Accept()
if err != nil {
fmt.Println("listener Accept err:", err)
continue
}
// handler
go s.Handler(conn)
}
}
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
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
主函数启动
package main
func main() {
server := NewServer("127.0.0.1", 8888)
server.Start()
}
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
完整代码
server.go
package main
import (
"fmt"
"io" "net" "sync" "time")
type Server struct {
Ip string
Port int
// 在线用户
OnlineUserMap map[string]*User
mapLock sync.RWMutex
// 消息广播channel
Message chan string
}
// NewServer 创建Server接口
func NewServer(ip string, port int) *Server {
server := &Server{
Ip: ip,
Port: port,
OnlineUserMap: make(map[string]*User),
Message: make(chan string),
}
return server
}
func (s *Server) BroadCast(user *User, msg string) {
sendMsg := "[" + user.Addr + "]" + user.Name + ":" + msg
s.Message <- sendMsg
}
func (s *Server) ListenMessage() {
for {
msg := <-s.Message
s.mapLock.Lock()
for _, cli := range s.OnlineUserMap {
cli.C <- msg
}
s.mapLock.Unlock()
}
}
// Handler handler处理
func (s *Server) Handler(conn net.Conn) {
fmt.Print("链接建立成功")
// 加入在线用户集
user := NewUser(conn, s)
user.Online()
fmt.Println("[" + user.Addr + "]" + user.Name + ": online...")
isLive := make(chan bool)
// 广播用户发送信息
go func() {
buf := make([]byte, 4096)
for {
n, err := conn.Read(buf)
if n == 0 {
user.Offline()
fmt.Println("[" + user.Addr + "]" + user.Name + ": offline...")
return
}
if err != nil && err != io.EOF {
fmt.Println("conn Read err:", err)
return
}
fmt.Println("[" + user.Addr + "]" + user.Name + ":" + string(buf))
// 提取用户信息 去除 '\n' msg := string(buf[:n-1])
user.DoMessage(msg)
}
}()
// 超时强制退出监听检测处理
for {
select {
case <-isLive:
case <-time.After(time.Second * 60):
user.DoMessage("You have been forced offline\n")
fmt.Println("[" + user.Addr + "]" + user.Name + ": have been forced offline")
close(user.C)
err := conn.Close()
if err != nil {
return
}
}
}
}
// Start 启动服务器接口
func (s *Server) Start() {
listener, err := net.Listen("tcp", fmt.Sprintf("%s:%d", s.Ip, s.Port))
if err != nil {
fmt.Println("net.listener err:", err)
return
}
defer func(listener net.Listener) {
err := listener.Close()
if err != nil {
fmt.Println("net.listener err:", err)
}
}(listener)
// 启动在线用户监听
go s.ListenMessage()
fmt.Println("start success....")
for {
// accept
conn, err := listener.Accept()
if err != nil {
fmt.Println("listener Accept err:", err)
continue
}
// handler
go s.Handler(conn)
}
}
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
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
# User具体实现
用户结构体
type User struct {
// 用户名
Name string
// 用户IP地址
Addr string
// chan
C chan string
// 链接
conn net.Conn
// 所属的服务
server *Server
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
创建一个User
func NewUser(c net.Conn, server *Server) *User {
userAddr := c.RemoteAddr().String()
user := &User{
Name: userAddr,
Addr: userAddr,
C: make(chan string),
conn: c,
server: server,
}
go user.ListenMessage()
return user
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
监听用户状态
func (u *User) ListenMessage() {
for {
msg := <-u.C
_, err := u.conn.Write([]byte(msg + "\n"))
if err != nil {
fmt.Println("write err:", err)
return
}
}
}
// SendMsg 给客户端发送消息
func (u *User) SendMsg(msg string) {
_, err := u.conn.Write([]byte(msg))
if err != nil {
fmt.Println("send Msg err:", err)
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
具体实现用户的上下线
// Online 广播用户上线通知
func (u *User) Online() {
u.server.mapLock.Lock()
u.server.OnlineUserMap[u.Name] = u
u.server.mapLock.Unlock()
u.server.BroadCast(u, "online...")
}
// Offline 广播用户下线通知
func (u *User) Offline() {
u.server.mapLock.Lock()
delete(u.server.OnlineUserMap, u.Name)
u.server.mapLock.Unlock()
u.server.BroadCast(u, "offline...")
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
解析用户的消息
func (u *User) DoMessage(message string) {
if len(message) > 0 {
msg := strings.Split(message, "|")
if len(msg) > 1 {
switch msg[0] {
case "rename":
newName := msg[1]
_, ok := u.server.OnlineUserMap[newName]
if ok {
u.SendMsg("this name is already used\n")
return
}
u.server.mapLock.Lock()
u.server.OnlineUserMap[newName] = u
delete(u.server.OnlineUserMap, u.Name)
u.server.mapLock.Unlock()
u.Name = newName
u.SendMsg("update newName success\n")
break
case "to":
// to|用户名|消息
if len(msg) < 3 {
u.server.BroadCast(u, "Command format error\n")
return
}
remoteUer, ok := u.server.OnlineUserMap[msg[1]]
if !ok {
u.server.BroadCast(u, msg[1]+" not found\n")
return
}
remoteUer.SendMsg(msg[2])
}
} else {
switch message {
case "who":
u.server.mapLock.Lock()
for _, user := range u.server.OnlineUserMap {
onlineMsg := "[" + user.Addr + "]" + user.Name + ":online\n"
u.SendMsg(onlineMsg)
}
u.server.mapLock.Unlock()
break
default:
u.server.BroadCast(u, message)
}
}
}
}
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
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
完整代码
package main
import (
"fmt"
"net" "strings")
type User struct {
Name string
Addr string
C chan string
conn net.Conn
server *Server
}
func NewUser(c net.Conn, server *Server) *User {
userAddr := c.RemoteAddr().String()
user := &User{
Name: userAddr,
Addr: userAddr,
C: make(chan string),
conn: c,
server: server,
}
go user.ListenMessage()
return user
}
// Online 广播用户上线通知
func (u *User) Online() {
u.server.mapLock.Lock()
u.server.OnlineUserMap[u.Name] = u
u.server.mapLock.Unlock()
u.server.BroadCast(u, "online...")
}
// Offline 广播用户下线通知
func (u *User) Offline() {
u.server.mapLock.Lock()
delete(u.server.OnlineUserMap, u.Name)
u.server.mapLock.Unlock()
u.server.BroadCast(u, "offline...")
}
func (u *User) DoMessage(message string) {
if len(message) > 0 {
msg := strings.Split(message, "|")
if len(msg) > 1 {
switch msg[0] {
case "rename":
newName := msg[1]
_, ok := u.server.OnlineUserMap[newName]
if ok {
u.SendMsg("this name is already used\n")
return
}
u.server.mapLock.Lock()
u.server.OnlineUserMap[newName] = u
delete(u.server.OnlineUserMap, u.Name)
u.server.mapLock.Unlock()
u.Name = newName
u.SendMsg("update newName success\n")
break
case "to":
// to|用户名|消息
if len(msg) < 3 {
u.server.BroadCast(u, "Command format error\n")
return
}
remoteUer, ok := u.server.OnlineUserMap[msg[1]]
if !ok {
u.server.BroadCast(u, msg[1]+" not found\n")
return
}
remoteUer.SendMsg(msg[2])
}
} else {
switch message {
case "who":
u.server.mapLock.Lock()
for _, user := range u.server.OnlineUserMap {
onlineMsg := "[" + user.Addr + "]" + user.Name + ":online\n"
u.SendMsg(onlineMsg)
}
u.server.mapLock.Unlock()
break
default:
u.server.BroadCast(u, message)
}
}
}
}
func (u *User) ListenMessage() {
for {
msg := <-u.C
_, err := u.conn.Write([]byte(msg + "\n"))
if err != nil {
fmt.Println("write err:", err)
return
}
}
}
// SendMsg 给客户端发送消息
func (u *User) SendMsg(msg string) {
_, err := u.conn.Write([]byte(msg))
if err != nil {
fmt.Println("send Msg err:", err)
}
}
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
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
# 定义客户端
# 初始化客户端
客户端结构体
type Client struct {
// 服务端ip
ServerIp string
// 服务端端口
ServerPort int
// 客户端名
Name string
// 客户端管道
conn net.Conn
// 客户端模式
flag int
}
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
// NewClient 创建一个监听
func NewClient(serverIp string, serverPort int) *Client {
client := &Client{
ServerIp: serverIp,
ServerPort: serverPort,
flag: 999,
}
// 建立tcp长链接
conn, err := net.Dial("tcp", fmt.Sprintf("%s:%d", client.ServerIp, client.ServerPort))
if err != nil {
fmt.Println("dial err:", err)
return nil
}
client.conn = conn
return client
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
通过参数命令来定义并启动客户端
func init() {
// 初始化配置,通过 -ip设置IP地址
flag.StringVar(&serverIp, "i", "127.0.0.1", "设置服务器的IP地址(默认127.0.0.1)")
// 初始化配置,通过 -p设置IP端口
flag.IntVar(&serverPort, "p", 8888, "设置服务器的端口(默认8888)")
}
// DealResponse 监听服务端返回的消息
func (client *Client) DealResponse() {
_, err := io.Copy(os.Stdout, client.conn)
if err != nil {
return
}
}
// 具体业务的实现
func (client *Client) Run() {
}
func main() {
// 命令行解析
flag.Parse()
client := NewClient(serverIp, serverPort)
if client == nil {
fmt.Println(">>> 链接服务器失败")
return
}
go client.DealResponse()
fmt.Println(">>> 链接服务器成功")
client.Run()
}
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
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
# 客户端封装功能
封装修改用户名
// 包装更新用户名请求
func (client *Client) updateUserName() bool {
fmt.Println(">>> 请输入用户名")
_, err := fmt.Scanln(&client.Name)
if err != nil {
return false
}
sendMsg := "rename|" + client.Name + "\n"
_, err = client.conn.Write([]byte(sendMsg))
if err != nil {
fmt.Println(">>> conn write err:", err)
return false
}
return true
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
封装查询在线用户
func (client *Client) listUser() bool {
sendMsg := "who\n"
_, err := client.conn.Write([]byte(sendMsg))
if err != nil {
fmt.Println(">>> conn write err:", err)
return false
}
return true
}
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
封装广播聊天
// PublicChat 公聊模式
func (client *Client) publicChat() {
var chatMsg string
fmt.Println(">>> 请输入发送内容,输入exit退出")
_, err := fmt.Scanln(&chatMsg)
if err != nil {
return
}
for chatMsg != "exit" {
if len(chatMsg) != 0 {
sendMsg := chatMsg + "\n"
_, err := client.conn.Write([]byte(sendMsg))
if err != nil {
fmt.Println(">>> conn write err:", err)
break
}
}
// 继续监听下一个发送信息,直到exit
chatMsg = ""
fmt.Println(">>> 请输入发送内容,输入exit退出")
_, err := fmt.Scanln(&chatMsg)
if err != nil {
return
}
}
}
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
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
封装私聊
// PrivateChat 私聊模式
func (client *Client) privateChat() {
var remote, chatMsg string
client.listUser()
for remote != "exit" {
fmt.Println(">>> 请输入发送对象,输入exit退出")
_, err := fmt.Scanln(&remote)
if err != nil {
return
}
for chatMsg != "exit" {
if len(chatMsg) != 0 {
// 发送消息到服务端
sendMsg := "to|" + remote + "|" + chatMsg + "\n"
_, err := client.conn.Write([]byte(sendMsg))
if err != nil {
fmt.Println(">>> conn write err:", err)
break
}
}
// 继续监听下一个发送信息,直到exit
chatMsg = ""
fmt.Println(">>> 请输入发送内容,输入exit退出")
_, err := fmt.Scanln(&chatMsg)
if err != nil {
return
}
}
// 内循环退出,继续监听输入内容选择用户,知道exit
remote = ""
fmt.Println(">>> 请输入发送对象,输入exit退出")
_, err = fmt.Scanln(&remote)
if err != nil {
return
}
}
}
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
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
封装客户端菜单命令
// Menu 命令菜单
func (client *Client) Menu() bool {
var code int
fmt.Println("1: 公聊模式")
fmt.Println("2: 私聊模式")
fmt.Println("3: 更新用户名")
fmt.Println("0: 退出")
_, err := fmt.Scanln(&code)
if err != nil {
return false
}
if code >= 0 && code <= 3 {
client.flag = code
return true
}
return false
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
调整业务函数
func (client *Client) Run() {
for client.flag != 0 {
// 过滤非法的菜单code
for !client.Menu() {
}
// 根据菜单code进行功能调度
switch client.flag {
case 1:
client.publicChat()
break
case 2:
client.privateChat()
break
case 3:
client.updateUserName()
break
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
完整代码
package main
import (
"flag"
"fmt" "io" "net" "os")
var serverIp string
var serverPort int
type Client struct {
ServerIp string
ServerPort int
Name string
conn net.Conn
flag int
}
// NewClient 创建一个监听
func NewClient(serverIp string, serverPort int) *Client {
client := &Client{
ServerIp: serverIp,
ServerPort: serverPort,
flag: 999,
}
// 建立tcp长链接
conn, err := net.Dial("tcp", fmt.Sprintf("%s:%d", client.ServerIp, client.ServerPort))
if err != nil {
fmt.Println("dial err:", err)
return nil
}
client.conn = conn
return client
}
// Menu 命令菜单
func (client *Client) Menu() bool {
var code int
fmt.Println("1: 公聊模式")
fmt.Println("2: 私聊模式")
fmt.Println("3: 更新用户名")
fmt.Println("0: 退出")
_, err := fmt.Scanln(&code)
if err != nil {
return false
}
if code >= 0 && code <= 3 {
client.flag = code
return true
}
return false
}
// 包装更新用户名请求
func (client *Client) updateUserName() bool {
fmt.Println(">>> 请输入用户名")
_, err := fmt.Scanln(&client.Name)
if err != nil {
return false
}
sendMsg := "rename|" + client.Name + "\n"
_, err = client.conn.Write([]byte(sendMsg))
if err != nil {
fmt.Println(">>> conn write err:", err)
return false
}
return true
}
// 查询用户信息
func (client *Client) listUser() bool {
sendMsg := "who\n"
_, err := client.conn.Write([]byte(sendMsg))
if err != nil {
fmt.Println(">>> conn write err:", err)
return false
}
return true
}
// PrivateChat 私聊模式
func (client *Client) privateChat() {
var remote, chatMsg string
client.listUser()
for remote != "exit" {
fmt.Println(">>> 请输入发送对象,输入exit退出")
_, err := fmt.Scanln(&remote)
if err != nil {
return
}
for chatMsg != "exit" {
if len(chatMsg) != 0 {
// 发送消息到服务端
sendMsg := "to|" + remote + "|" + chatMsg + "\n"
_, err := client.conn.Write([]byte(sendMsg))
if err != nil {
fmt.Println(">>> conn write err:", err)
break
}
}
// 继续监听下一个发送信息,直到exit
chatMsg = ""
fmt.Println(">>> 请输入发送内容,输入exit退出")
_, err := fmt.Scanln(&chatMsg)
if err != nil {
return
}
}
// 内循环退出,继续监听输入内容选择用户,知道exit
remote = ""
fmt.Println(">>> 请输入发送对象,输入exit退出")
_, err = fmt.Scanln(&remote)
if err != nil {
return
}
}
}
// PublicChat 公聊模式
func (client *Client) publicChat() {
var chatMsg string
fmt.Println(">>> 请输入发送内容,输入exit退出")
_, err := fmt.Scanln(&chatMsg)
if err != nil {
return
}
for chatMsg != "exit" {
if len(chatMsg) != 0 {
sendMsg := chatMsg + "\n"
_, err := client.conn.Write([]byte(sendMsg))
if err != nil {
fmt.Println(">>> conn write err:", err)
break
}
}
// 继续监听下一个发送信息,直到exit
chatMsg = ""
fmt.Println(">>> 请输入发送内容,输入exit退出")
_, err := fmt.Scanln(&chatMsg)
if err != nil {
return
}
}
}
func (client *Client) Run() {
for client.flag != 0 {
// 过滤非法的菜单code
for !client.Menu() {
}
// 根据菜单code进行功能调度
switch client.flag {
case 1:
client.publicChat()
break
case 2:
client.privateChat()
break
case 3:
client.updateUserName()
break
}
}
}
func init() {
// 初始化配置,通过 -ip设置IP地址
flag.StringVar(&serverIp, "i", "127.0.0.1", "设置服务器的IP地址(默认127.0.0.1)")
// 初始化配置,通过 -p设置IP端口
flag.IntVar(&serverPort, "p", 8888, "设置服务器的端口(默认8888)")
}
func (client *Client) DealResponse() {
_, err := io.Copy(os.Stdout, client.conn)
if err != nil {
return
}
}
func main() {
// 命令行解析
flag.Parse()
client := NewClient(serverIp, serverPort)
if client == nil {
fmt.Println(">>> 链接服务器失败")
return
}
go client.DealResponse()
fmt.Println(">>> 链接服务器成功")
client.Run()
}
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
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
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
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
帮助我改善此页面 (opens new window)
上次更新: 2026/01/20, 13:53:16