登录代码提交

This commit is contained in:
tangping
2025-01-15 17:36:12 +08:00
parent 8c40855c4e
commit 22ac6c1fed
39 changed files with 2551 additions and 189 deletions

View File

@@ -0,0 +1,302 @@
package server_webSocket
import (
"common/clientMgr"
"common/config"
"common/model"
"encoding/binary"
"fmt"
"framework/goroutineMgr"
"github.com/gorilla/websocket"
"goutil/logUtil"
"goutil/timeUtil"
"strings"
"sync"
"sync/atomic"
"time"
)
const (
// 消息每次读取的上限值
con_MaxMessageSize = 2048 * 2
// 客户端失效的秒数
con_CLIENT_EXPIRE_SECONDS = 20
)
var (
// 全局客户端的id从1开始进行自增
globalClientId int32 = 0
// 字节的大小端顺序
byterOrder = binary.LittleEndian
)
// Client 实现IConnection接口的所有方法
// 定义客户端对象,以实现对客户端连接的封装
type Client struct {
// 唯一标识
id int32
// The websocket connection.
conn *websocket.Conn
// 接收到的消息内容
receiveData []byte
// 待发送的数据
sendData []*model.ServerResponseObject
// 连接是否关闭(通过此字段来协调receiveData和sendData方法)
closed bool
// 锁对象用于控制对sendDatap的并发访问receiveData不需要因为是同步访问
mutex sync.Mutex
// 玩家Id
playerId int64
// 上次活跃时间
activeTime int64
}
// 获取唯一标识
func (this *Client) GetId() int32 {
return this.id
}
// 获取玩家Id
// 返回值:
// 玩家Id
func (this *Client) GetPlayerId() int64 {
return this.playerId
}
// 玩家登陆
// playerId玩家Id
// 返回值:无
func (this *Client) PlayerLogin(playerId int64) {
this.playerId = playerId
}
// 获取远程地址IP_Port
func (this *Client) GetRemoteAddr() string {
items := strings.Split(this.conn.RemoteAddr().String(), ":")
return fmt.Sprintf("%s_%s", items[0], items[1])
}
// 获取远程地址IP
func (this *Client) getRemoteShortAddr() string {
items := strings.Split(this.conn.RemoteAddr().String(), ":")
return items[0]
}
// 获取待发送的数据
// 返回值:
// 待发送数据项
// 是否含有有效数据
func (this *Client) getSendData() (responseObj *model.ServerResponseObject, exists bool) {
this.mutex.Lock()
defer this.mutex.Unlock()
// 如果没有数据则直接返回
if len(this.sendData) == 0 {
return
}
// 取出第一条数据,并为返回值赋值
responseObj = this.sendData[0]
exists = true
// 删除已经取出的数据
this.sendData = this.sendData[1:]
return
}
// 发送数据
// sendDataItemObj:待发送数据项
// 返回值:无
func (this *Client) SendMessage(responseObj *model.ServerResponseObject) {
this.mutex.Lock()
defer this.mutex.Unlock()
this.sendData = append(this.sendData, responseObj)
}
// 清空待发送数据
func (this *Client) ClearSendData() {
this.mutex.Lock()
defer this.mutex.Unlock()
this.sendData = make([]*model.ServerResponseObject, 0, 16)
}
// 向客户端发送消息
// responseObj:返回值对象
func (this *Client) sendResponseObject(responseObj *model.ServerResponseObject) error {
beforeTime := time.Now().Unix()
//// 序列化发送的数据
//content, _ := json.Marshal(responseObj)
//
////debug模式下打印日志
//if debugUtil.IsDebug() {
//
// //记录日志,方便查询
// logUtil.WarnLog("向客户端发送消息%v", string(content))
//}
//
//// 进行zlib压缩
//if config.GetBaseConfig().IfCompressData {
// content, _ = zlibUtil.Compress(content, zlib.DefaultCompression)
//}
//检查是否需要压缩
if len(responseObj.DataByte) <= 0 {
responseObj.Compress(config.GetBaseConfig().IfCompressData)
}
// 发送消息
if err := this.sendMessage(responseObj.DataByte); err != nil {
return err
}
// 如果发送的时间超过3秒则记录下来
if time.Now().Unix()-beforeTime > 3 {
logUtil.WarnLog("消息Size:%d, UseTime:%d", len(responseObj.DataByte), time.Now().Unix()-beforeTime)
}
return nil
}
func (this *Client) sendMessage(message []byte) error {
this.mutex.Lock()
defer this.mutex.Unlock()
if err := this.conn.WriteMessage(websocket.BinaryMessage, message); err != nil {
return err
}
return nil
}
// 客户端活跃
// 返回值:无
func (this *Client) Active() {
atomic.StoreInt64(&this.activeTime, time.Now().Unix())
}
// 判断客户端是否超时超过300秒不活跃算作超时
// 返回值:是否超时
func (this *Client) Expired() bool {
return time.Now().Unix() > this.activeTime+con_CLIENT_EXPIRE_SECONDS
}
// 客户端连接对象断开
// 返回值:无
func (this *Client) Close() {
this.conn.Close()
this.closed = true
this.playerId = 0
}
// 格式化
func (this *Client) String() string {
return fmt.Sprintf("{Id:%d, RemoteAddr:%s, activeTime:%s, playerId:%s}", this.id, this.GetRemoteAddr(), timeUtil.Format(time.Unix(this.activeTime, 0), "yyyy-MM-dd HH:mm:ss"), this.playerId)
}
// -----------------------------实现IConnection接口方法end-------------------------
// 客户端启动函数
func (this *Client) start() {
go this.handleReceiveData()
go this.handleSendData()
}
// 处理从连接收到的数据
func (this *Client) handleReceiveData() {
// 处理goroutine数量
goroutineName := "server_webSocket.handleSendData"
goroutineMgr.MonitorZero(goroutineName)
defer goroutineMgr.ReleaseMonitor(goroutineName)
defer clientMgr.Disconnect(this)
// 无限循环,不断地读取数据,解析数据,处理数据
for {
if this.closed {
break
}
_, message, err := this.conn.ReadMessage()
if err != nil {
break
}
// 更新activeTime
this.Active()
// 约定len(message) == 0,为心跳请求
if len(message) == 0 {
if err := this.sendMessage([]byte{}); err != nil {
return
}
continue
}
clientMgr.HandleRequest(this, message)
}
}
// 处理向客户端发送的数据
func (this *Client) handleSendData() {
// 处理goroutine数量
goroutineName := "server_webSocket.handleSendData"
goroutineMgr.MonitorZero(goroutineName)
defer goroutineMgr.ReleaseMonitor(goroutineName)
defer clientMgr.Disconnect(this)
for {
if this.closed {
break
}
// 如果发送出现错误,表示连接已经断开,则退出方法;
if sendDataItemObj, exists := this.getSendData(); exists {
// 判断是否为断开客户端连接的数据
if sendDataItemObj.IsDisconnect() {
break
}
if err := this.sendResponseObject(sendDataItemObj); err != nil {
return
}
} else {
time.Sleep(5 * time.Millisecond)
}
}
}
// 新建客户端对象
// conn连接对象
// 返回值:客户端对象的指针
func newClient(conn *websocket.Conn) *Client {
conn.SetReadLimit(con_MaxMessageSize)
// 获得自增的id值
getIncrementId := func() int32 {
atomic.AddInt32(&globalClientId, 1)
return globalClientId
}
return &Client{
id: getIncrementId(),
conn: conn,
receiveData: make([]byte, 0, 1024),
sendData: make([]*model.ServerResponseObject, 0, 16),
activeTime: time.Now().Unix(),
playerId: 0,
}
}

View File

@@ -0,0 +1,63 @@
package server_webSocket
import (
"fmt"
"net/http"
"sync"
"common/clientMgr"
"github.com/gorilla/websocket"
"goutil/debugUtil"
"goutil/logUtil"
)
var upgrader = websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
CheckOrigin: func(r *http.Request) bool {
return true
},
}
func handleConn(w http.ResponseWriter, r *http.Request) {
conn, err := upgrader.Upgrade(w, r, nil)
//是否debug模式
if debugUtil.IsDebug() {
logUtil.DebugLog(fmt.Sprintf("收到客户的websockte连接,ip%v", conn.RemoteAddr()))
}
if err != nil {
logUtil.ErrorLog("websocket.handleConn获取连接出错err:%v", err)
return
}
// 创建客户端对象
clientObj := newClient(conn)
clientObj.start()
clientMgr.RegisterClient(clientObj)
debugUtil.Printf("收到连接请求:remoteAdd:%s\n", conn.RemoteAddr())
}
// Start 启动服务器
func Start(wg *sync.WaitGroup, address string, isUseTSL bool) {
defer wg.Done()
msg := fmt.Sprintf("server_websocket begins to listen on:%s...", address)
fmt.Println(msg)
logUtil.InfoLog(msg)
http.HandleFunc("/", handleConn)
if isUseTSL {
err := http.ListenAndServeTLS(address, "tlsFile/7qule.com.pem", "tlsFile/7qule.com.key", nil)
if err != nil {
panic(fmt.Sprintf("server_websocket.ListenAndServeTLS, err:%v", err))
}
} else {
err := http.ListenAndServe(address, nil)
if err != nil {
panic(fmt.Sprintf("server_websocket.ListenAndServe, err:%v", err))
}
}
}