项目简介
使用go开发的客户端和服务器,使用时,使用CMD窗口开启多个客户端,服务端可以使用IDE,也可以使用CMD窗口
功能包含:群发,断联,重连
客户端代码
package main
import (
"bufio"
"fmt"
"net"
"os"
"sync"
)
var wg sync.WaitGroup
func main() {
fmt.Println("启动客户端")
conn, err := net.Dial("tcp", "0.0.0.0:8935")
if err != nil {
fmt.Println("客户端连接服务器 出现错误:" + err.Error())
return
} else {
fmt.Println("客户端成功连接上 服务器")
fmt.Println("当前客户端地址和端口:" + conn.LocalAddr().String())
wg.Add(2)
go sendMsgProcess(&conn)
go receiveMsgProcess(&conn)
wg.Wait()
}
}
// 接收服务器返回的消息
func receiveMsgProcess(conn *net.Conn) {
defer wg.Done()
defer (*conn).Close()
var bytes []byte = make([]byte, 1*1024)
for {
n, err := (*conn).Read(bytes)
if err != nil {
fmt.Println("从服务器收到的数据有错误" + err.Error())
return
}
if n > 0 && err == nil {
msg := string(bytes[:n])
fmt.Println(msg)
}
}
}
// 处理发送给服务器消息
func sendMsgProcess(conn *net.Conn) {
defer wg.Done()
defer (*conn).Close()
reader := bufio.NewReader(os.Stdin)
for {
str, err := reader.ReadString('\n')
if err != nil {
fmt.Println("读取客户端输入的信息有误")
return
}
if err == nil && str != "" {
_, err := (*conn).Write([]byte(str))
if err != nil {
fmt.Println("转换为字节数组时出现错误")
return
}
}
}
}
服务器代码
package main
import (
"fmt"
"net"
"strconv"
)
// 存储 客户端 连接过来的所有用户
var clients []net.Conn = make([]net.Conn, 0)
func main() {
fmt.Println("启动服务器")
listener, err := net.Listen("tcp", ":8935")
if err != nil {
fmt.Println("服务器启动 出现错误:" + err.Error())
return
} else {
fmt.Println("服务器启动成功!!")
fmt.Println("当前服务器地址和端口:" + listener.Addr().String())
}
//死循环, 用来一直接收需要连接的客户端
for {
conn, err := listener.Accept()
if err != nil {
fmt.Println("请求连接服务器端的客户端:" + conn.RemoteAddr().String() + " 出现了错误:" + err.Error())
return
}
if conn != nil && err == nil {
fmt.Println("客户端:" + conn.RemoteAddr().String() + "连接成功")
//新增加的用户 加入到 切片中
clients = append(clients, conn)
fmt.Println("当前与服务器连接的客户端数量为" + strconv.Itoa(len(clients)))
//单个协程 处理当前连接的逻辑
go processConn(&conn)
}
}
}
// 从clients切片中移除对应的客户端
func removeClient(client *net.Conn) {
//找到索引
var index uint16
for i, v := range clients {
if v.RemoteAddr().String() == (*client).RemoteAddr().String() {
index = uint16(i)
}
}
//去掉索引位置的client
clients = append(clients[:index], clients[index+1:]...)
}
// 处理连接
func processConn(conn *net.Conn) {
defer (*conn).Close()
var bytes []byte = make([]byte, 1*1024)
for {
n, err := (*conn).Read(bytes)
if err != nil {
fmt.Println("从此客户端接收到的数据有错误" + err.Error())
//如果 从客户端返回的数据错误,就将此客户端从切片中移除
removeClient(conn)
fmt.Println("已将该用户" + (*conn).RemoteAddr().String() + "移除")
return
}
if n > 0 && err == nil {
msg := string(bytes[:n])
fmt.Println((*conn).RemoteAddr().String() + ":" + msg)
go forward(conn, msg)
}
}
}
// 将消息分发给所有用户
func forward(itself *net.Conn, str string) {
for _, client := range clients {
if client.RemoteAddr().String() == (*itself).RemoteAddr().String() {
continue
}
fmt.Println("转发给其他所有客户端:" + client.RemoteAddr().String() + str)
client.Write([]byte((*itself).RemoteAddr().String() + ":" + str))
}
}