1、目录结构如下:
2、main入口调用:main.go
package main
import (
"fmt"
"socket_server/server"
)
func main() {
(&server.SocketServer{
Network: "tcp4",
Address: "127.0.0.1:8879",
Clients: make(map[string]*server.TcpConn),
ClientTimeOutSecond: 5,
MaxClientNum: 2,
OnError: func(msg string, err error) {
fmt.Println(msg, err)
},
OnStart: func(server *server.SocketServer) {
fmt.Println("启动OK")
},
OnClientConnect: func(client *server.TcpConn) {
fmt.Println("客户端连接成功:", client.Id)
},
OnClientClose: func(client *server.TcpConn) {
fmt.Println("客户端连接关闭:", client.Id)
},
OnMessage: func(client *server.TcpConn, msg string) {
fmt.Println("接收数据:", msg)
client.Connect.Write([]byte("服务端接收到了你的消息:" + msg + "&&&&"))
},
}).Start()
}
3、socket主服务:SocketServer.go
package server
import (
"fmt"
"net"
"sync"
"time"
)
//socket主服务
type SocketServer struct {
Network string
Address string //监听ip和端口,例如:127.0.0.1:8000
Clients map[string]*TcpConn //客户端列表
ClientTimeOutSecond int64 //客户端超时时间,N秒没有收到客户端消息就关闭
MaxClientNum int //客户端最大连接数
CurrentClientNum int //当然客户端连接数量
OnError func(msg string, err error) //发生错误
OnStart func(server *SocketServer) //socket启动
OnClientConnect func(client *TcpConn) //客户端连接上
OnClientClose func(client *TcpConn) //与客户端关闭连接
OnMessage func(client *TcpConn, msg string) //接收到客户端消息
}
//启动socket
func (server *SocketServer) Start() {
listener, err := net.Listen(server.Network, server.Address)
if err != nil {
server.OnError("Listen失败", err)
return
}
defer listener.Close()
fmt.Printf("socket 启动成功;Network=%s,Address=%s", server.Network, server.Address)
server.OnStart(server)
go server.CheckClient()
for true {
conn, err := listener.Accept()
if err != nil {
server.OnError("Accept失败", err)
continue
}
if server.CurrentClientNum >= server.MaxClientNum {
fmt.Println("已经达到最大连接数了:", server.CurrentClientNum)
conn.Close()
continue
}
client := MakeClient(conn, server)
server.OnClientConnect(client)
server.AddClient(client)
go client.HandleMessage()
}
}
var mutex sync.Mutex
func (server *SocketServer) AddClient(client *TcpConn) {
mutex.Lock()
defer mutex.Unlock()
server.Clients[client.Id] = client
server.CurrentClientNum++
fmt.Println("新增连接,连接数:", server.CurrentClientNum)
}
func (server *SocketServer) RemoveClient(client *TcpConn) {
mutex.Lock()
defer mutex.Unlock()
if _, ok := server.Clients[client.Id]; ok {
client.Connect.Close()
delete(server.Clients, client.Id)
server.OnClientClose(client)
server.CurrentClientNum--
fmt.Println("移除连接,连接数:", server.CurrentClientNum)
}
}
//检查超时
func (server *SocketServer) CheckClient() {
for true {
if server.ClientTimeOutSecond < 1 {
time.Sleep(5 * time.Second)
continue
}
mutex.Lock()
nowTime := time.Now().Unix()
for key, value := range server.Clients {
if nowTime-value.LastTime > server.ClientTimeOutSecond {
value.Connect.Close()
fmt.Println("移除超时客户端:", key, len(server.Clients))
}
}
mutex.Unlock()
time.Sleep(5 * time.Second)
}
}
4、客户端连接对象:TcpConn
package server
import (
"net"
"strings"
"time"
)
//客户端连接,一个连接一个TcpConn
type TcpConn struct {
Id string //客户端唯一标识
Connect net.Conn //客户端连接对象
Server *SocketServer
LastTime int64 //最后通讯时间
}
//创建连接客户端
func MakeClient(connnect net.Conn, server *SocketServer) *TcpConn {
client := &TcpConn{
Id: connnect.RemoteAddr().String(),
Connect: connnect,
Server: server,
LastTime: time.Now().Unix(),
}
return client
}
//接收数据
func (conn *TcpConn) HandleMessage() {
var buffer [1024]byte //测试用8,真实环境用多少一点
msg := ""
for true {
readcount, err := conn.Connect.Read(buffer[:])
if err != nil {
conn.Server.RemoveClient(conn)
conn.Server.OnError("读取数据错误,关闭连接:", err)
break
}
if readcount == 0 {
conn.Server.OnError("读取数据失败:"+string(readcount), nil)
continue
}
conn.LastTime = time.Now().Unix()
msg += string(buffer[:readcount])
//fmt.Println("msg1:", msg)
if strings.Contains(msg, "&&&&") {
msgs := strings.Split(msg, "&&&&") //"我是中国人&&&&哈哈哈哈&&&&"切出来的数组长度是3,将数组位置1和2的都是一条完整的数据
if len(msgs) > 1 {
for _, m := range msgs[0 : len(msgs)-1] {
conn.Server.OnMessage(conn, m)
}
msg = msgs[len(msgs)-1]
//fmt.Println("msg2:", msg)
}
}
}
}
5、测试客户端:SocketClient.go 和 main.go
package client
import (
"fmt"
"net"
"strings"
"sync"
)
type SocketClient struct {
Network string
Address string //监听ip和端口,例如:127.0.0.1:8000
OnMessage func(msg string)
Connect net.Conn
Wg sync.WaitGroup
}
func (client *SocketClient) Start() error {
conn, err := net.Dial(client.Network, client.Address)
if err != nil {
return err
}
client.Wg.Add(1)
go HandleMessage(conn, client)
client.Connect = conn
return nil
}
//接收数据
func HandleMessage(conn net.Conn, client *SocketClient) {
var buffer [8]byte //测试用8,真实环境用多少一点
msg := ""
defer client.Wg.Done()
for true {
readcount, err := conn.Read(buffer[:])
if err != nil || readcount == 0 {
fmt.Println(err)
break
}
msg += string(buffer[:readcount])
if strings.Contains(msg, "&&&&") {
msgs := strings.Split(msg, "&&&&") //"我是中国人&&&&哈哈哈哈&&&&"切出来的数组长度是3,将数组位置1和2的是一条数据
if len(msgs) > 1 {
for _, m := range msgs[0 : len(msgs)-1] {
client.OnMessage(m)
}
msg = msgs[len(msgs)-1]
}
}
}
}
package main
import (
"fmt"
"socket_client/client"
"time"
)
func main() {
for true {
var client = &client.SocketClient{
Network: "tcp4",
Address: "127.0.0.1:8879",
OnMessage: func(msg string) {
fmt.Println("接收到服务端的消息", msg)
},
}
err := client.Start()
if err != nil {
fmt.Println("连接服务端失败", err)
return
}
//for true {
client.Connect.Write([]byte("我是中国人&&&哈哈哈哈&&&&"))
client.Connect.Write([]byte("I come from china&&&&are you?&&&&"))
//time.Sleep(time.Second * 3)
//}
client.Wg.Wait()
fmt.Println("与服务器连接断开,3秒后重试")
time.Sleep(time.Second * 3)
}
}
6、运行效果如下: