Hidewnd Docs Hidewnd Docs
首页
  • 常用开发环境
  • 常用提示词
  • 常用Linux命令
  • Java开发聊天机器人
  • word模板生成实现方案
  • 基于Go写一个极简的通讯demo
  • SpringBoot配置文件加密处理
  • SpringBoot优雅的抛出业务异常
  • 通用大模型适配器
  • 10分钟快速搭建个人博客
  • [学习笔记]Lua
  • [学习笔记]JVM
  • [学习笔记]设计模式
  • [学习笔记]Linux笔记
  • [部署笔记]搭建Typecho博客
  • [部署笔记]部署Qsign签名机
  • [部署笔记]安装PVE系统
  • [部署笔记]部署KingBaseV9电科金仓
  • 技艺成本
  • 剑三网站合集
  • 合并大区角色数据处理
  • 25PT冷龙峰教学笔记
  • 25PT太极宫教学笔记
  • 25PT弓月城教学笔记
关于
GitHub (opens new window)
首页
  • 常用开发环境
  • 常用提示词
  • 常用Linux命令
  • Java开发聊天机器人
  • word模板生成实现方案
  • 基于Go写一个极简的通讯demo
  • SpringBoot配置文件加密处理
  • SpringBoot优雅的抛出业务异常
  • 通用大模型适配器
  • 10分钟快速搭建个人博客
  • [学习笔记]Lua
  • [学习笔记]JVM
  • [学习笔记]设计模式
  • [学习笔记]Linux笔记
  • [部署笔记]搭建Typecho博客
  • [部署笔记]部署Qsign签名机
  • [部署笔记]安装PVE系统
  • [部署笔记]部署KingBaseV9电科金仓
  • 技艺成本
  • 剑三网站合集
  • 合并大区角色数据处理
  • 25PT冷龙峰教学笔记
  • 25PT太极宫教学笔记
  • 25PT弓月城教学笔记
关于
GitHub (opens new window)
  • 常用开发环境
  • 常用提示词
  • 常用Linux命令
  • Java开发聊天机器人
  • word模板生成实现方案
  • 基于Go写一个极简的通讯demo
    • 定义服务端
      • Server具体实现
      • User具体实现
    • 定义客户端
      • 初始化客户端
      • 客户端封装功能
  • SpringBoot配置文件加密处理
  • SpringBoot优雅的抛出业务异常
  • 通用大模型适配器
  • 10分钟快速搭建个人博客
  • 文档
hidewnd
2023-12-24
目录

基于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

创建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

监听用户上线


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

服务端对用户消息的处理器


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

服务端启动器


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

主函数启动


package main


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

1
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

# 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

创建一个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

监听用户状态


  
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

具体实现用户的上下线


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

解析用户的消息


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

完整代码

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

# 定义客户端

# 初始化客户端

客户端结构体

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

通过参数命令来定义并启动客户端

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

# 客户端封装功能

封装修改用户名

  
// 包装更新用户名请求  
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

封装查询在线用户


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

封装广播聊天


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

封装私聊


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

封装客户端菜单命令


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

调整业务函数


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

完整代码

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
帮助我改善此页面 (opens new window)
上次更新: 2026/01/20, 13:53:16
word模板生成实现方案
SpringBoot配置文件加密处理

← word模板生成实现方案 SpringBoot配置文件加密处理→

Theme by Vdoing | Copyright © 2024-2026 Hidewnd
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式