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、运行效果如下: