知识点

通过Go实现了简要聊天室,主要应用了如下知识:

1.代码中同时包括了服务器和客户端的内容

2.客户端包括了两部分内容,一部分是chatSend函数,接受用户的输入;
另一部分是connect到server,接受相关信息;

3.server由三个部分组成。
第一部分就是不停地accept各个客户端;
第二个就是为每一个客户端创立Handler函数,接受客户端发来的信息;
第三个就是echoHandler函数,它的作用就是将从某一用户接受过来的信息广播给其他所有的客户端,就是这么简单。

Demo

文件名chat.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
package main

import (
"fmt"
"os"
"net"
)

func main() {
if len(os.Args) != 3 {
fmt.Println("Wrong pare")
os.Exit(0)
}

if os.Args[1] == "server" && len(os.Args) == 3 {
StartServer(os.Args[2])
}

if os.Args[1] == "client" && len(os.Args) == 3 {
StartClient(os.Args[2])
}
}

// 检查错误
func checkError(err error, info string)(res bool){
if(err != nil){
fmt.Println(info + " " + err.Error())
return false
}
return true
}

// 服务器接收线程
func Handler(conn net.Conn, messages chan string){
fmt.Println("connection is commected from ...", conn.RemoteAddr().String())

buf := make([]byte, 1024)
for{
length, err := conn.Read(buf)
if(checkError(err, "Connection") == false){
conn.Close()
break
}
if length > 0 {
buf[length] = 0
}
reciveStr := string(buf[0: length])
messages <- reciveStr
}
}

// 服务器发送线程
func echoHandler(conns *map[string]net.Conn, messages chan string){
for{
msg := <- messages
fmt.Println(msg)

for key, value := range * conns {
fmt.Println("connection is conneted from ...", key)
_, err := value.Write([]byte(msg))
if(err != nil){
fmt.Println(err.Error())
delete(*conns, key)
}
}
}

}

// 启动服务器
func StartServer(port string){
service := ":" + port
tcpAddr, err := net.ResolveTCPAddr("tcp4", service)
checkError(err, "ResolveTCPAddr")

l, err := net.ListenTCP("tcp", tcpAddr)
checkError(err, "ListenTCP")
conns := make(map[string]net.Conn)
messages := make(chan string, 10)

//广播服务启动
go echoHandler(&conns, messages)

for {
fmt.Println("Listening ...")
conn, err := l.Accept()
checkError(err, "Accept")
fmt.Println("Accepting ...")

conns[conn.RemoteAddr().String()] = conn
//启动新线程
go Handler(conn, messages)
}
}

//客户端发送线程
func chatSend(conn net.Conn){
var input string
username := conn.LocalAddr().String()

for{
fmt.Scanln(&input)
if input == "/quit"{
fmt.Println("Bye bye ...")
conn.Close()
os.Exit(0)
}

lens, err := conn.Write([]byte(username + "Say :::" + input))

fmt.Println(lens)
if(err != nil){
fmt.Println(err.Error())
conn.Close()
break
}
}
}

//客户端启动程序
func StartClient(tcpaddr string){
tcpAddr, err := net.ResolveTCPAddr("tcp4", tcpaddr)
checkError(err, "ResolveTCPAddr")

conn, err := net.DialTCP("tcp", nil, tcpAddr)
checkError(err, "DialTCP")

//启动客户端发送线程
go chatSend(conn)

//客户端轮询
buf := make([]byte, 1024)
for{
length, err := conn.Read(buf)
if(checkError(err, "Connection") == false){
conn.Close()
fmt.Println("Server is dead ... Bye bye")
os.Exit(0)
}

fmt.Println(string(buf[0: length]))
}
}

测试

启动服务端

1
go run chat.go server 9090

返回

1
Listening ...

同时启动客户端

1
go run chat.go client :9090

此时服务端 提示

1
connection is commected from ... 127.0.0.1:50756

也可以同时再开启一个客户端
实现2个客户端通话