├── LICENSE
├── README.md
├── baccaratServer
├── baccaratServer.go
├── connectedSessions
│ ├── session.go
│ └── sessionManager.go
├── distributePacket.go
├── docs
│ ├── 51_GameStart.puml
│ └── 52_Batting.puml
├── go.mod
├── go.sum
├── main.go
├── protocol
│ ├── errorcode.go
│ ├── packet.go
│ └── packetID.go
└── roomPkg
│ ├── Game.go
│ ├── define.go
│ ├── room.go
│ ├── roomManager.go
│ ├── roomUser.go
│ ├── room_Packet.go
│ ├── room_PacketChat.go
│ ├── room_PacketEnter.go
│ ├── room_PacketGame.go
│ └── room_PacketLeave.go
├── bin
├── config_logger.json
├── run_baccaratServer.bat
├── run_chatServer.bat
├── run_chatServer2.bat
└── run_echoServer.bat
├── chatServer
├── chatServer.go
├── connectedSessions
│ ├── session.go
│ └── sessionManager.go
├── distributePacket.go
├── go.mod
├── go.sum
├── logger.go
├── main.go
├── protocol
│ ├── errorcode.go
│ ├── packet.go
│ └── packetID.go
└── roomPkg
│ ├── define.go
│ ├── room.go
│ ├── roomManager.go
│ ├── room_Packet.go
│ ├── room_PacketChat.go
│ ├── room_PacketEnter.go
│ └── room_PacketLeave.go
├── chatServer2
├── chatServer.go
├── clientSessionEvent.go
├── configAppServer.go
├── connectedSessions
│ ├── checkState.go
│ ├── session.go
│ └── sessionManager.go
├── distributePacket.go
├── go.mod
├── go.sum
├── main.go
├── protocol
│ ├── errorcode.go
│ ├── internalPacket.go
│ ├── packet.go
│ └── packetID.go
├── roomPkg
│ ├── define.go
│ ├── room.go
│ ├── roomManager.go
│ ├── roomPacketDistributor.go
│ ├── roomPacketPipe.go
│ ├── room_Packet.go
│ ├── room_PacketChat.go
│ └── room_PacketEnterLeave.go
└── timerScheduler.go
├── chatServer_msgpack
├── chatServer.go
├── connectedSessions
│ ├── session.go
│ └── sessionManager.go
├── distributePacket.go
├── go.mod
├── go.sum
├── main.go
├── protocol
│ ├── errorcode.go
│ ├── packet.go
│ └── packetID.go
└── roomPkg
│ ├── define.go
│ ├── room.go
│ ├── roomManager.go
│ ├── room_Packet.go
│ ├── room_PacketChat.go
│ ├── room_PacketEnter.go
│ └── room_PacketLeave.go
├── csharp_test_client
├── App.config
├── ClientSimpleTcp.cs
├── DevLog.cs
├── Packet.cs
├── PacketBufferManager.cs
├── PacketDefine.cs
├── PacketProcessForm.cs
├── Program.cs
├── Properties
│ ├── AssemblyInfo.cs
│ ├── Resources.Designer.cs
│ ├── Resources.resx
│ ├── Settings.Designer.cs
│ └── Settings.settings
├── csharp_test_client.csproj
├── csharp_test_client.sln
├── mainForm.Designer.cs
├── mainForm.cs
└── mainForm.resx
├── csharp_test_client_msgpack
├── App.config
├── ClientSimpleTcp.cs
├── DevLog.cs
├── Packet.cs
├── PacketBufferManager.cs
├── PacketDefine.cs
├── PacketProcessForm.cs
├── Program.cs
├── Properties
│ ├── AssemblyInfo.cs
│ ├── Resources.Designer.cs
│ ├── Resources.resx
│ ├── Settings.Designer.cs
│ └── Settings.settings
├── csharp_test_client_msgpack.csproj
├── csharp_test_client_msgpack.sln
├── mainForm.Designer.cs
├── mainForm.cs
└── mainForm.resx
├── echoServer
├── echoServer.go
├── go.mod
├── go.sum
└── main.go
├── gohipernetFake
├── TcpSession.go
├── clientSessionManager.go
├── configNetwork.go
├── define.go
├── go.mod
├── go.sum
├── goHiperNet.go
├── goHiperNet_Impl.go
├── log.go
├── packetEnDecoder.go
├── utilDeque.go
└── utilPrintPanicStack.go
├── lib_opensource
├── 1m-go-tcp-server-master.zip
├── 1m-go-websockets-master.zip
└── gnet-dev.zip
├── socket_api.md.md
└── thirdparty
└── SimpleMsgPack.Net
├── .gitignore
├── LICENSE
├── README.md
├── Samples
├── App.config
├── Program.cs
├── Properties
│ └── AssemblyInfo.cs
└── SimpleMsgPackTester.csproj
├── SimpleMsgPack.sln
├── Source
├── BytesTools.cs
├── Consts.cs
├── MsgPack.cs
├── Program.cs
├── Properties
│ └── AssemblyInfo.cs
├── ReadTools.cs
├── SimpleMsgPack.csproj
└── WriteTools.cs
└── changes.txt
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Choi HeungBae
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # golang_socketGameServer_codelab
2 | - golang을 이용하여 실시간 통신 게임 서버 만들기 실습.
3 | - 각 서버의 원본 코드를 하나씩 따라서 코딩하면서 서버 만드는 방법을 배운다.
4 | - 코딩하면서 해당 코드의 구현 방법과 이유를 설명 듣는다.
5 |
6 | **버그가 있을 수 있습니다**. 버그 잡아서 수정하는 것도 학습 중 일부라고 생각해 주세요^^;.
7 |
8 |
9 | ## 목적
10 | - golang으로 소켓 통신용 서버를 만들 수 있는 기술고 경험을 쌓는 것이 목표이다.
11 | - golang으로 소켓 통신용 서버를 만든 경험이 없는(있더라도 작은) 사람을 대상으로 한다.
12 | - golang의 socket API를 사용하지 않고, 센트럴서버팀에서 만든 goHiperNet(golang 네트워크 라이브러리)의 짝퉁(?)을 사용한다.
13 | - 이 라이브러리는 goHiperNet과 API만 같고, 내부 구현은 완전 다르다.
14 | - 학습용으로 충분히 사용할 수 있다.
15 | - golang의 socket API를 사용하여 밑바닥부터 개발하는 방법을 배우고 싶다면 별도 요청을 바람.
16 | - 실습은 단계 별로 진행하고, 각 단계 별로 소요 시간은 다르다.
17 | - 시간이 많이 필요한 경우라도 1번에 최대 3시간을 넘지 않는다.
18 | - 한번에 너무 많이 나가면 뒤에 복습이 어려워지기 때문이다.
19 |
20 |
21 | ## 준비
22 | - 1인 1 노트북(Windows or OSX)
23 | - 최신 버전의 golang SDK
24 | - 최신 버전의 GoLand
25 | - 기본 golang의 문법 학습
26 | - 코딩은 한번도 해본적인 없는 경우도 괜찮음.
27 |
28 |
29 | ## 패킷 헤더
30 | 패킷 허더의 크기는 총 5바이트
31 | - 패킷의 총 크기(2바이트. 헤더와 보디 합친) + 패킷ID(2바이트) + 패킷Type(1바이트)
32 |
33 |
34 | ## 설명 영상
35 | - [실습 목적과 방법 설명](https://youtu.be/zR_zcY7SXio )
36 | - [Echo Server 만들기](https://youtu.be/OSiwcsPAO2o )
37 | - [채팅 서버 코드 설명](https://youtu.be/2rppKuW-wQg )
38 |
39 |
40 | ## echoServer
41 | - 디렉토리: echoServer
42 | - GoLand를 사용하여 golang용 프로그램을 만들고, 빌드/디버깅을 한다.
43 | - 아주 간단한 규모이다.
44 |
45 |
46 | ## chatServer
47 | - 디렉토리: chatServer
48 | - 방 개념의 채팅 서버
49 | - 패킷 요청 처리를 1개의 고루틴(스레드)에서만 한다.
50 | - echoServer에 비해 규모는 3~4배 크다.
51 |
52 | ### 추가 기능 구현
53 | - 1:1 귓속말
54 | - 방 초대
55 |
56 |
57 |
58 | ## baccaratServer
59 | - 디렉토리: baccaratServer
60 | - 겜블 게임인 바카라 게임을 온라인화 한 것이다.
61 | - 바카라 룰: https://namu.wiki/w/%EB%B0%94%EC%B9%B4%EB%9D%BC
62 | - chatServer에 바카라 게임 로직이 올라간 것으로 chatServer에 대한 이해가 꼭 필요하다.
63 |
64 | ### 추가 기능 구현
65 | - 게임 서버 Scale-Out 기능 구현
66 | - API Server(http)와 연동
67 | - 유저를 특정 게임 서버에 할당하는 기능
68 | - 매칭 기능
69 |
70 |
71 |
72 | ## chatServer2
73 | - 디렉토리: chatServer2
74 | - 방 개념의 채팅 서버
75 | - 패킷 요청 처리를 N개의 고루틴(스레드)에서 한다.
76 | - 패킷 처리를 멀티 고루틴에서 하므로 공유 객체 동기화를 조심해야 한다.
77 | - chatServer의 코드와 겹치는 부분이 많으므로 chatServer에 대한 이해가 꼭 필요하다
78 |
79 | ### 추가 기능 구현
80 | - Redis 연동
81 | - API Server(http)와 연동
82 | - 로그인을 API Server에서 한다.
83 |
84 |
85 | ## msgpack을 사용한 chatServer
86 | - 디렉토리: chatServer_msgpack
87 | - 클라이언트 디렉토리: csharp_test_client_msgpack
88 | - 서버와 클라이언트가 네트워크로 주고 받는 패킷 데이터 포맷을 msgpack을 사용한다.
89 | - [Go](https://github.com/vmihailenco/msgpack )
90 | - [C#](https://github.com/ymofen/SimpleMsgPack.Net )
91 | - golang 라이브러리와 데이터 포맷이 일치하지 않는 부분이 있어서 코드를 수정하였음.
92 | - thirdparty/SimpleMsgPack.Net 디렉토리에 코드가 있다/
93 |
94 |
95 | ## 참고
96 | - [유튜브: 오픈소스 코드로 배우는 Golang TCP Socket Server 프로그래밍 ](https://youtu.be/boDo8JoyHuo )
97 |
98 |
--------------------------------------------------------------------------------
/baccaratServer/baccaratServer.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | . "gohipernetFake"
6 | "strconv"
7 | "strings"
8 |
9 | "main/connectedSessions"
10 | "main/protocol"
11 | "main/roomPkg"
12 | )
13 |
14 | type configAppServer struct {
15 | GameName string
16 |
17 | RoomMaxCount int32
18 | RoomStartNum int32
19 | RoomMaxUserCount int32
20 | }
21 |
22 | type ChatServer struct {
23 | ServerIndex int
24 | IP string
25 | Port int
26 |
27 | PacketChan chan protocol.Packet
28 |
29 | RoomMgr *roomPkg.RoomManager
30 | }
31 |
32 | func createAnsStartServer(netConfig NetworkConfig, appConfig configAppServer) {
33 | OutPutLog(LOG_LEVEL_INFO,"", 0,"CreateServer !!!")
34 |
35 | var server ChatServer
36 |
37 | if server.setIPAddress(netConfig.BindAddress) == false {
38 | OutPutLog(LOG_LEVEL_ERROR,"", 0,"fail. server address")
39 | return
40 | }
41 |
42 | protocol.Init_packet();
43 |
44 | maxUserCount := appConfig.RoomMaxCount * appConfig.RoomMaxUserCount
45 | connectedSessions.Init(netConfig.MaxSessionCount, maxUserCount)
46 |
47 | server.PacketChan = make(chan protocol.Packet, 256)
48 |
49 | roomConfig := roomPkg.RoomConfig{
50 | appConfig.RoomStartNum,
51 | appConfig.RoomMaxCount,
52 | appConfig.RoomMaxUserCount,
53 | }
54 | server.RoomMgr = roomPkg.NewRoomManager(roomConfig)
55 |
56 |
57 | go server.PacketProcess_goroutine()
58 |
59 |
60 | networkFunctor := SessionNetworkFunctors{}
61 | networkFunctor.OnConnect = server.OnConnect
62 | networkFunctor.OnReceive = server.OnReceive
63 | networkFunctor.OnReceiveBufferedData = nil
64 | networkFunctor.OnClose = server.OnClose
65 | networkFunctor.PacketTotalSizeFunc = PacketTotalSize
66 | networkFunctor.PacketHeaderSize = PACKET_HEADER_SIZE
67 | networkFunctor.IsClientSession = true
68 |
69 | NetLibStartNetwork(&netConfig, networkFunctor)
70 | }
71 |
72 | func (server *ChatServer) setIPAddress(ipAddress string) bool {
73 | results := strings.Split(ipAddress, ":")
74 | if len(results) != 2 {
75 | return false
76 | }
77 |
78 | server.IP = results[0]
79 | server.Port, _ = strconv.Atoi(results[1])
80 |
81 | return true
82 | }
83 |
84 | func (server *ChatServer) OnConnect(sessionIndex int32, sessionUniqueID uint64) {
85 | OutPutLog(LOG_LEVEL_INFO,"", 0,fmt.Sprintf("[OnConnect] sessionIndex: %d", sessionIndex))
86 |
87 | connectedSessions.AddSession(sessionIndex, sessionUniqueID)
88 | }
89 |
90 | func (server *ChatServer) OnReceive(sessionIndex int32, sessionUniqueID uint64, data []byte) bool {
91 | server.DistributePacket(sessionIndex, sessionUniqueID, data)
92 | return true
93 | }
94 |
95 | func (server *ChatServer) OnClose(sessionIndex int32, sessionUniqueID uint64) {
96 | OutPutLog(LOG_LEVEL_INFO,"", 0,fmt.Sprintf("[OnClose] sessionIndex: %d", sessionIndex))
97 |
98 | server.disConnectClient(sessionIndex, sessionUniqueID)
99 | }
100 |
101 | func (server *ChatServer) disConnectClient(sessionIndex int32, sessionUniqueId uint64) {
102 | // 로그인도 안한 유저라면 그냥 여기서 처리한다.
103 | // 방 입장을 안한 유저라면 여기서 처리해도 괜찮지만 아래로 넘긴다.
104 | if connectedSessions.IsLoginUser(sessionIndex) == false {
105 | connectedSessions.RemoveSession(sessionIndex, false)
106 | return
107 | }
108 |
109 |
110 | packet := protocol.Packet {
111 | sessionIndex,
112 | sessionUniqueId,
113 | protocol.PACKET_ID_SESSION_CLOSE_SYS,
114 | 0,
115 | nil,
116 | }
117 |
118 | server.PacketChan <- packet
119 |
120 | OutPutLog(LOG_LEVEL_INFO,"", 0,fmt.Sprintf("[DisConnectClient] Login User sessionIndex: %d", sessionIndex))
121 | }
122 |
--------------------------------------------------------------------------------
/baccaratServer/connectedSessions/session.go:
--------------------------------------------------------------------------------
1 | package connectedSessions
2 |
3 | import (
4 | "sync/atomic"
5 |
6 | "main/protocol"
7 | )
8 |
9 | type session struct {
10 | _index int32
11 |
12 | _networkUniqueID uint64 //네트워크 세션의 유니크 ID
13 |
14 | _userID [protocol.MAX_USER_ID_BYTE_LENGTH]byte
15 | _userIDLength int8
16 |
17 | _connectTimeSec int64 // 연결된 시간
18 | _RoomNum int32 //
19 | _RoomNumOfEntering int32 // 현재 입장 중인 룸의 번호
20 | }
21 |
22 | func (session *session) Init(index int32) {
23 | session._index = index
24 | session.Clear()
25 | }
26 |
27 | func (session *session) _ClearUserId() {
28 | session._userIDLength = 0
29 | }
30 |
31 | func (session *session) Clear() {
32 | session._ClearUserId()
33 | session.setRoomNumber(0, -1, 0)
34 | session.SetConnectTimeSec(0, 0)
35 | }
36 |
37 | func (session *session) GetIndex() int32 {
38 | return session._index
39 | }
40 |
41 | func (session *session) GetNetworkUniqueID() uint64 {
42 | return atomic.LoadUint64(&session._networkUniqueID)
43 | }
44 |
45 | func (session *session) validNetworkUniqueID(uniqueId uint64) bool {
46 | return atomic.LoadUint64(&session._networkUniqueID) == uniqueId
47 | }
48 |
49 | func (session *session) GetNetworkInfo() (int32, uint64) {
50 | index := session.GetIndex()
51 | uniqueID := atomic.LoadUint64(&session._networkUniqueID)
52 | return index, uniqueID
53 | }
54 |
55 | func (session *session) setUserID(userID []byte) {
56 | session._userIDLength = int8(len(userID))
57 | copy(session._userID[:], userID)
58 | }
59 |
60 | func (session *session) getUserID() []byte {
61 | return session._userID[0:session._userIDLength]
62 | }
63 |
64 | func (session *session) getUserIDLength() int8 {
65 | return session._userIDLength
66 | }
67 |
68 | func (session *session) SetConnectTimeSec(timeSec int64, uniqueID uint64) {
69 | atomic.StoreInt64(&session._connectTimeSec, timeSec)
70 | atomic.StoreUint64(&session._networkUniqueID, uniqueID)
71 | }
72 |
73 | func (session *session) GetConnectTimeSec() int64 {
74 | return atomic.LoadInt64(&session._connectTimeSec)
75 | }
76 |
77 | func (session *session) SetUser(sessionUniqueId uint64,
78 | userID []byte,
79 | curTimeSec int64,
80 | ) {
81 | session.setUserID(userID)
82 | session.setRoomNumber(sessionUniqueId, -1, curTimeSec) // 방어적인 목적으로 채널 번호 초기화
83 | }
84 |
85 | func (session *session) IsAuth() bool {
86 | if session._userIDLength > 0 {
87 | return true
88 | }
89 |
90 | return false
91 | }
92 |
93 | func (session *session) setRoomEntering(roomNum int32) bool {
94 | if atomic.CompareAndSwapInt32(&session._RoomNumOfEntering, -1, roomNum) == false {
95 | return false
96 | }
97 |
98 | return true
99 | }
100 |
101 | func (session *session) setRoomNumber(sessionUniqueId uint64, roomNum int32, curTimeSec int64) bool {
102 | if roomNum == -1 {
103 | atomic.StoreInt32(&session._RoomNum, roomNum)
104 | atomic.StoreInt32(&session._RoomNumOfEntering, roomNum)
105 | return true
106 | }
107 |
108 | if sessionUniqueId != 0 && session.validNetworkUniqueID(sessionUniqueId) == false {
109 | return false
110 |
111 | }
112 | // 입력이 -1이 아닌경우 -1이 아닐 때만 compareswap으로 변경한다. 실패하면 채널 입장도 실패이다.
113 | if atomic.CompareAndSwapInt32(&session._RoomNum, -1, roomNum) == false {
114 | return false
115 | }
116 |
117 | atomic.StoreInt32(&session._RoomNumOfEntering, roomNum)
118 | return true
119 | }
120 |
121 | func (session *session) getRoomNumber() (int32, int32) {
122 | roomNum := atomic.LoadInt32(&session._RoomNum)
123 | roomNumOfEntering := atomic.LoadInt32(&session._RoomNum)
124 | return roomNum, roomNumOfEntering
125 | }
126 |
--------------------------------------------------------------------------------
/baccaratServer/connectedSessions/sessionManager.go:
--------------------------------------------------------------------------------
1 | package connectedSessions
2 |
3 | import (
4 | "sync"
5 | "sync/atomic"
6 | "time"
7 | )
8 |
9 | // 스레드 세이프 해야 한다.
10 | type Manager struct {
11 | _UserIDsessionMap *sync.Map
12 |
13 | _maxSessionCount int32
14 | _sessionList []*session
15 |
16 | _maxUserCount int32
17 |
18 | _currentLoginUserCount int32
19 | }
20 |
21 | var _manager Manager
22 |
23 | func Init(maxSessionCount int, maxUserCount int32) bool {
24 | _manager._UserIDsessionMap = new(sync.Map)
25 | _manager._maxUserCount = maxUserCount
26 |
27 | _manager._maxSessionCount = int32(maxSessionCount)
28 | _manager._sessionList = make([]*session, maxSessionCount)
29 |
30 | for i := 0; i < maxSessionCount; i++ {
31 | _manager._sessionList[i] = new(session)
32 |
33 | index := int32(i)
34 | _manager._sessionList[i].Init(index)
35 | }
36 |
37 | return true
38 | }
39 |
40 | func AddSession(sessionIndex int32, sessionUniqueID uint64) bool {
41 | if _validSessionIndex(sessionIndex) == false {
42 | return false
43 | }
44 |
45 | if _manager._sessionList[sessionIndex].GetConnectTimeSec() > 0 {
46 | return false
47 | }
48 |
49 | // 방어적인 목적으로 한번 더 Clear 한다
50 | _manager._sessionList[sessionIndex].Clear()
51 |
52 | _manager._sessionList[sessionIndex].SetConnectTimeSec(time.Now().Unix(), sessionUniqueID)
53 | return true
54 | }
55 |
56 | func RemoveSession(sessionIndex int32, isLoginedUser bool) bool {
57 | if _validSessionIndex(sessionIndex) == false {
58 | return false
59 | }
60 |
61 | if isLoginedUser {
62 | atomic.AddInt32(&_manager._currentLoginUserCount, -1)
63 |
64 | userID := string(_manager._sessionList[sessionIndex].getUserID())
65 | _manager._UserIDsessionMap.Delete(userID)
66 | }
67 |
68 | _manager._sessionList[sessionIndex].Clear()
69 |
70 | return true
71 | }
72 |
73 | func _validSessionIndex(index int32) bool {
74 | if index < 0 || index >= _manager._maxSessionCount {
75 | return false
76 | }
77 | return true
78 | }
79 |
80 | func GetNetworkUniqueID(sessionIndex int32) uint64 {
81 | if _validSessionIndex(sessionIndex) == false {
82 | return 0
83 | }
84 |
85 | return _manager._sessionList[sessionIndex].GetNetworkUniqueID()
86 | }
87 |
88 | func GetUserID(sessionIndex int32) ([]byte, bool) {
89 | if _validSessionIndex(sessionIndex) == false {
90 | return nil, false
91 | }
92 |
93 | return _manager._sessionList[sessionIndex].getUserID(), true
94 | }
95 |
96 | func SetLogin(sessionIndex int32, sessionUniqueId uint64, userID []byte, curTimeSec int64) bool {
97 | if _validSessionIndex(sessionIndex) == false {
98 | return false
99 | }
100 |
101 | newUserID := string(userID)
102 | if _, ok := _manager._UserIDsessionMap.Load(newUserID); ok {
103 | return false
104 | }
105 |
106 | _manager._sessionList[sessionIndex].SetUser(sessionUniqueId, userID, curTimeSec)
107 | _manager._UserIDsessionMap.Store(newUserID, _manager._sessionList[sessionIndex])
108 |
109 | atomic.AddInt32(&_manager._currentLoginUserCount, 1)
110 | return true
111 | }
112 |
113 | func IsLoginUser(sessionIndex int32) bool {
114 | if _validSessionIndex(sessionIndex) == false {
115 | return false
116 | }
117 |
118 | return _manager._sessionList[sessionIndex].IsAuth()
119 | }
120 |
121 | func SetRoomNumber(sessionIndex int32, sessionUniqueId uint64, roomNum int32, curTimeSec int64) bool {
122 | if _validSessionIndex(sessionIndex) == false {
123 | return false
124 | }
125 |
126 | return _manager._sessionList[sessionIndex].setRoomNumber(sessionUniqueId, roomNum, curTimeSec)
127 | }
128 |
129 | func GetRoomNumber(sessionIndex int32) (int32, int32) {
130 | if _validSessionIndex(sessionIndex) == false {
131 | return -1, -1
132 | }
133 | return _manager._sessionList[sessionIndex].getRoomNumber()
134 | }
135 |
--------------------------------------------------------------------------------
/baccaratServer/distributePacket.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "bytes"
5 | "time"
6 |
7 | . "gohipernetFake"
8 |
9 | "main/connectedSessions"
10 | "main/protocol"
11 | )
12 |
13 | func (server *ChatServer) DistributePacket(sessionIndex int32,
14 | sessionUniqueId uint64,
15 | packetData []byte,
16 | ) {
17 | packetID := protocol.PeekPacketID(packetData)
18 | bodySize, bodyData := protocol.PeekPacketBody(packetData)
19 |
20 | packet := protocol.Packet{Id: packetID}
21 | packet.UserSessionIndex = sessionIndex
22 | packet.UserSessionUniqueId = sessionUniqueId
23 | packet.Id = packetID
24 | packet.DataSize = bodySize
25 | packet.Data = make([]byte, packet.DataSize)
26 | copy(packet.Data, bodyData)
27 |
28 | server.PacketChan <- packet
29 | }
30 |
31 |
32 | func (server *ChatServer) PacketProcess_goroutine() {
33 | for {
34 | if server.PacketProcess_goroutine_Impl() {
35 | OutPutLog(LOG_LEVEL_INFO,"", 0,"Wanted Stop PacketProcess goroutine")
36 | break
37 | }
38 | }
39 |
40 | OutPutLog(LOG_LEVEL_INFO,"", 0,"Stop rooms PacketProcess goroutine")
41 | }
42 |
43 | func (server *ChatServer) PacketProcess_goroutine_Impl() bool {
44 | IsWantedTermination := false // 이 서버에서는 별 의미가 없음
45 | defer PrintPanicStack()
46 |
47 | secondTimeticker := time.NewTicker(time.Second)
48 | defer secondTimeticker.Stop()
49 |
50 |
51 | for {
52 | select {
53 | case packet := <-server.PacketChan:
54 | {
55 | sessionIndex := packet.UserSessionIndex
56 | sessionUniqueId := packet.UserSessionUniqueId
57 | bodySize := packet.DataSize
58 | bodyData := packet.Data
59 |
60 | if packet.Id == protocol.PACKET_ID_LOGIN_REQ {
61 | ProcessPacketLogin(sessionIndex, sessionUniqueId, bodySize, bodyData)
62 | } else if packet.Id == protocol.PACKET_ID_SESSION_CLOSE_SYS {
63 | ProcessPacketSessionClosed(server, sessionIndex, sessionUniqueId)
64 | } else {
65 | roomNumber, _ := connectedSessions.GetRoomNumber(sessionIndex)
66 | server.RoomMgr.PacketProcess(roomNumber, packet)
67 | }
68 | }
69 | case curTime := <-secondTimeticker.C:
70 | {
71 | server.RoomMgr.CheckRoomState(curTime.Unix())
72 | }
73 | }
74 | }
75 |
76 | return IsWantedTermination
77 | }
78 |
79 | func ProcessPacketLogin(sessionIndex int32,
80 | sessionUniqueId uint64,
81 | bodySize int16,
82 | bodyData []byte ) {
83 | //DB와 연동하지 않으므로 중복 로그인만 아니면 다 성공으로 한다
84 | var request protocol.LoginReqPacket
85 | if (&request).Decoding(bodyData) == false {
86 | _sendLoginResult(sessionIndex, sessionUniqueId, protocol.ERROR_CODE_PACKET_DECODING_FAIL)
87 | return
88 | }
89 |
90 | userID := bytes.Trim(request.UserID[:], "\x00");
91 |
92 | if len(userID) <= 0 {
93 | _sendLoginResult(sessionIndex, sessionUniqueId, protocol.ERROR_CODE_LOGIN_USER_INVALID_ID)
94 | return
95 | }
96 |
97 | curTime := time.Now().Unix()
98 |
99 | if connectedSessions.SetLogin(sessionIndex, sessionUniqueId, userID, curTime) == false {
100 | _sendLoginResult(sessionIndex, sessionUniqueId, protocol.ERROR_CODE_LOGIN_USER_DUPLICATION)
101 | return
102 | }
103 |
104 | _sendLoginResult(sessionIndex, sessionUniqueId, protocol.ERROR_CODE_NONE)
105 | }
106 |
107 | func _sendLoginResult(sessionIndex int32, sessionUniqueId uint64, result int16) {
108 | var response protocol.LoginResPacket
109 | response.Result = result
110 | sendPacket, _ := response.EncodingPacket()
111 |
112 | NetLibIPostSendToClient(sessionIndex, sessionUniqueId, sendPacket)
113 | }
114 |
115 |
116 | func ProcessPacketSessionClosed(server *ChatServer, sessionIndex int32, sessionUniqueId uint64) {
117 | roomNumber, _ := connectedSessions.GetRoomNumber(sessionIndex)
118 |
119 | if roomNumber > -1 {
120 | packet := protocol.Packet{
121 | sessionIndex,
122 | sessionUniqueId,
123 | protocol.PACKET_ID_ROOM_LEAVE_REQ,
124 | 0,
125 | nil,
126 | }
127 |
128 | server.RoomMgr.PacketProcess(roomNumber, packet)
129 | }
130 |
131 | connectedSessions.RemoveSession(sessionIndex, true)
132 | }
133 |
134 |
135 |
--------------------------------------------------------------------------------
/baccaratServer/docs/51_GameStart.puml:
--------------------------------------------------------------------------------
1 | @startuml
2 | note over Client: 방장만 보낼 수 있음
3 | Client --> GameServer: PACKET_ID_GAME_START_REQ
4 |
5 | GameServer --> Client: PACKET_ID_GAME_START_RES
6 |
7 | note over Client: 방에 있는 모든 유저들
8 | GameServer --> Client: PACKET_ID_GAME_START_NTF
9 | @enduml
--------------------------------------------------------------------------------
/baccaratServer/docs/52_Batting.puml:
--------------------------------------------------------------------------------
1 | @startuml
2 | Client --> GameServer: PACKET_ID_GAME_BATTING_REQ
3 |
4 | GameServer --> Client: PACKET_ID_GAME_BATTING_RES
5 |
6 | note over GameServer: 방에 있는 모든 유저들
7 | GameServer --> Client: PACKET_ID_GAME_BATTING_NTF
8 |
9 | note over GameServer: 모두 배팅 했거나 or 대기 시간이 지나면 게임 결과를 보낸다
10 | GameServer --> Client: PACKET_ID_GAME_RESULT_NTF
11 | note right GameServer: 일정 시간이 지나면 게임 플레이 가능
12 | @enduml
--------------------------------------------------------------------------------
/baccaratServer/go.mod:
--------------------------------------------------------------------------------
1 | module main
2 |
3 | go 1.13
4 |
5 | require (
6 | github.com/davecgh/go-spew v1.1.1 // indirect
7 | go.uber.org/atomic v1.4.0 // indirect
8 | go.uber.org/multierr v1.1.0 // indirect
9 | go.uber.org/zap v1.10.0
10 | gohipernetFake v0.0.0
11 | gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
12 | )
13 |
14 | replace gohipernetFake v0.0.0 => ../gohipernetFake
15 |
--------------------------------------------------------------------------------
/baccaratServer/go.sum:
--------------------------------------------------------------------------------
1 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
2 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
3 | go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU=
4 | go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
5 | go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI=
6 | go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
7 | go.uber.org/zap v1.10.0 h1:ORx85nbTijNz8ljznvCMR1ZBIPKFn3jQrag10X2AsuM=
8 | go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
9 | gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=
10 | gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
11 |
--------------------------------------------------------------------------------
/baccaratServer/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "flag"
5 |
6 | . "gohipernetFake"
7 | )
8 |
9 | func main() {
10 | NetLibInitLog(LOG_LEVEL_DEBUG, nil)
11 |
12 | netConfig, appConfig := parseAppConfig()
13 | netConfig.WriteNetworkConfig(true)
14 |
15 | // 아래 함수를 호출하면 강제적으로 종료 시킬 때까지 대기 상태가 된다.
16 | createAnsStartServer(netConfig, appConfig)
17 | }
18 |
19 | func parseAppConfig() (NetworkConfig, configAppServer) {
20 | appConfig := configAppServer{
21 | "chatServer",
22 | 1000,
23 | 0,
24 | 4,
25 | }
26 |
27 | netConfig := NetworkConfig{}
28 |
29 | flag.BoolVar(&netConfig.IsTcp4Addr, "c_IsTcp4Addr", true, "bool flag")
30 | flag.StringVar(&netConfig.BindAddress, "c_BindAddress", "127.0.0.1:11021", "string flag")
31 | flag.IntVar(&netConfig.MaxSessionCount, "c_MaxSessionCount", 0, "int flag")
32 | flag.IntVar(&netConfig.MaxPacketSize, "c_MaxPacketSize", 0, "int flag")
33 |
34 | flag.Parse()
35 | return netConfig, appConfig
36 | }
37 |
--------------------------------------------------------------------------------
/baccaratServer/protocol/errorcode.go:
--------------------------------------------------------------------------------
1 | package protocol
2 |
3 | const (
4 | ERROR_CODE_NONE = 1
5 |
6 | ERROR_CODE_PACKET_DECODING_FAIL = 51
7 | ERROR_CODE_PACKET_NOT_LOGIN_USER = 52
8 | ERROR_CODE_ROOM_NOT_REGISTED_PACKET_ID = 53
9 | ERROR_CODE_USER_NOT_IN_ROOM = 54
10 |
11 | ERROR_CODE_DISCONNECT_UNAUTHENTICATED_USER = 61
12 |
13 | ERROR_CODE_LOGIN_USER_DUPLICATION = 111
14 | ERROR_CODE_LOGIN_USER_INVALID_ID = 112
15 |
16 | ERROR_CODE_ROOM_NOT_IN_USER = 121
17 | ERROR_CODE_ROOM_INVALIDE_NUMBER = 122
18 |
19 | ERROR_CODE_ENTER_ROOM_ALREADY = 131
20 | ERROR_CODE_ENTER_ROOM_PREV_WORKING = 132
21 | ERROR_CODE_ENTER_ROOM_INVALID_USER_ID = 133
22 | ERROR_CODE_ENTER_ROOM_USER_FULL = 134
23 | ERROR_CODE_ENTER_ROOM_DUPLCATION_USER = 135
24 | ERROR_CODE_ENTER_ROOM_INVALID_SESSION_STATE = 136
25 | ERROR_CODE_ENTER_ROOM_AUTO_ROOM_NUMBER = 137
26 |
27 | ERROR_CODE_LEAVE_ROOM_INTERNAL_INVALID_USER = 141
28 |
29 | ERROR_CODE_ROOM_CHAT_CHAT_MSG_LEN = 151
30 |
31 | ERROR_CODE_ROOM_RELAY_FAIL_DECPDING = 161
32 |
33 | ERROR_CODE_ROOM_GAME_START_INVALID_ROOM_STATE = 171
34 | ERROR_CODE_ROOM_GAME_START_NOT_ENOUGH_MEMBERS = 172
35 | ERROR_CODE_ROOM_GAME_START_NOT_MASTER = 173
36 |
37 | ERROR_CODE_ROOM_GAME_BATTING_FAIL_PACKET = 181
38 | ERROR_CODE_ROOM_GAME_BATTING_INVALID_ROOM_STATE = 182
39 | ERROR_CODE_ROOM_GAME_BATTING_INVALID_BAT_SELECT = 183
40 | ERROR_CODE_ROOM_GAME_BATTING_SAME_BAT_SELECT = 184
41 | )
42 |
--------------------------------------------------------------------------------
/baccaratServer/protocol/packetID.go:
--------------------------------------------------------------------------------
1 | package protocol
2 |
3 |
4 | const (
5 | PACKET_ID_PING_REQ = 201
6 | PACKET_ID_PING_RES = 202
7 |
8 | PACKET_ID_ERROR_NTF = 203
9 |
10 | PACKET_ID_SESSION_CLOSE_SYS = 211
11 |
12 |
13 | PACKET_ID_LOGIN_REQ = 701
14 | PACKET_ID_LOGIN_RES = 702
15 |
16 | PACKET_ID_ROOM_ENTER_REQ = 721
17 | PACKET_ID_ROOM_ENTER_RES = 722
18 | PACKET_ID_ROOM_USER_LIST_NTF = 723
19 | PACKET_ID_ROOM_NEW_USER_NTF = 724
20 |
21 | PACKET_ID_ROOM_LEAVE_REQ = 726
22 | PACKET_ID_ROOM_LEAVE_RES = 727
23 | PACKET_ID_ROOM_LEAVE_USER_NTF = 728
24 |
25 | PACKET_ID_ROOM_CHAT_REQ = 731
26 | PACKET_ID_ROOM_CHAT_RES = 732
27 | PACKET_ID_ROOM_CHAT_NOTIFY = 733
28 |
29 | PACKET_ID_ROOM_RELAY_REQ = 741
30 | PACKET_ID_ROOM_RELAY_NTF = 742
31 |
32 | PACKET_ID_GAME_START_REQ = 751
33 | PACKET_ID_GAME_START_RES = 752
34 | PACKET_ID_GAME_START_NTF = 753
35 |
36 | PACKET_ID_GAME_BATTING_REQ = 761
37 | PACKET_ID_GAME_BATTING_RES = 762
38 | PACKET_ID_GAME_BATTING_NTF = 753
39 |
40 | PACKET_ID_GAME_RESULT_NTF = 764
41 |
42 | )
43 |
44 |
45 |
--------------------------------------------------------------------------------
/baccaratServer/roomPkg/define.go:
--------------------------------------------------------------------------------
1 | package roomPkg
2 |
3 | type RoomConfig struct {
4 | StartRoomNumber int32
5 | MaxRoomCount int32
6 | MaxUserCount int32
7 | }
8 |
9 |
10 | type addRoomUserInfo struct {
11 | userID []byte
12 |
13 | netSessionIndex int32
14 | netSessionUniqueId uint64
15 | }
16 |
17 | // 방의 상태
18 | const (
19 | ROOM_STATE_NOE = 1
20 | ROOM_STATE_GAME_WAIT_BATTING = 2
21 | ROOM_STATE_GAME_RESULT = 3
22 | )
23 |
24 | // 카드 정보
25 | const MAX_CARD_CONT = 52
26 | const CARD_ROW_COUNT = 13
27 | // 카드 순서 스페이드, 다이아몬드, 클로버, 하트 A,2,3,4,5,6,7,8,9,10,J,Q,K
28 | func makeCard() []int8 {
29 | a := make([]int8, MAX_CARD_CONT)
30 | for i := range a {
31 | a[i] = (int8)(i)
32 | }
33 | return a
34 | }
35 |
36 | const BATTING_WAIT_MILLISEC = 5000
37 | const NEXT_GAME_WAIT_MILLISEC = 10000
38 |
39 | const (
40 | BATTING_SELECT_NONE = 0
41 | BATTING_SELECT_PLAYER = 1
42 | BATTING_SELECT_BANKER = 2
43 | )
44 |
45 | // 게임 결과
46 | const (
47 | GAME_RESULT_WIN_PLAYER = 1
48 | GAME_RESULT_WIN_BANKER = 2
49 | GAME_RESULT_TIE = 3
50 | )
51 |
52 | type baccaratGameResultInfo struct {
53 | cardsBanker [3]int8
54 | cardsPlayer [3]int8
55 |
56 | playerScore int8
57 | bankerScore int8
58 |
59 | result int8
60 | }
61 |
62 |
--------------------------------------------------------------------------------
/baccaratServer/roomPkg/roomManager.go:
--------------------------------------------------------------------------------
1 | package roomPkg
2 |
3 | import (
4 | "main/protocol"
5 | )
6 |
7 |
8 | type RoomManager struct {
9 | _roomStartNum int32
10 | _maxRoomCount int32
11 | _roomCountList []int16
12 | _roomList []baseRoom
13 | }
14 |
15 | func NewRoomManager(config RoomConfig) *RoomManager {
16 | roomManager := new(RoomManager)
17 | roomManager._initialize(config)
18 | return roomManager
19 | }
20 |
21 | func (roomMgr *RoomManager) _initialize(config RoomConfig) {
22 | roomMgr._roomStartNum = config.StartRoomNumber
23 | roomMgr._maxRoomCount = config.MaxRoomCount
24 | roomMgr._roomCountList = make([]int16, config.MaxRoomCount)
25 | roomMgr._roomList = make([]baseRoom, config.MaxRoomCount)
26 |
27 | for i := int32(0); i < roomMgr._maxRoomCount; i++ {
28 | roomMgr._roomList[i].initialize(i, config)
29 | roomMgr._roomList[i].settingPacketFunction()
30 | }
31 | }
32 |
33 | func (roomMgr *RoomManager) GetAllChannelUserCount() []int16 {
34 | maxRoomCount := roomMgr._maxRoomCount
35 | for i := int32(0); i < maxRoomCount; i++ {
36 | roomMgr._roomCountList[i] = (int16)(roomMgr._getRoomUserCount(i))
37 | }
38 |
39 | return roomMgr._roomCountList
40 | }
41 |
42 | func (roomMgr *RoomManager) getRoomByNumber(roomNumber int32) *baseRoom {
43 | roomIndex := roomNumber - roomMgr._roomStartNum
44 |
45 | if roomNumber < 0 || roomIndex >= roomMgr._maxRoomCount {
46 | return nil
47 | }
48 |
49 | return &roomMgr._roomList[roomIndex]
50 | }
51 |
52 | // 이 함수를 호출할 때의 채널 인덱스는 꼭 호출자가 유효범위인 것을 보증해야 한다.
53 | func (roomMgr *RoomManager) _getRoomUserCount(roomId int32) int {
54 | return roomMgr._roomList[roomId].getCurUserCount()
55 | }
56 |
57 | func (roomMgr *RoomManager) PacketProcess(roomNumber int32, packet protocol.Packet) {
58 | isRoomEnterReq := false
59 |
60 | if roomNumber == -1 && packet.Id == protocol.PACKET_ID_ROOM_ENTER_REQ {
61 | isRoomEnterReq = true
62 |
63 | var requestPacket protocol.RoomEnterReqPacket
64 | (&requestPacket).Decoding(packet.Data)
65 |
66 | roomNumber = requestPacket.RoomNumber
67 | }
68 |
69 | room := roomMgr.getRoomByNumber(roomNumber)
70 | if room == nil {
71 | protocol.NotifyErrorPacket(packet.UserSessionIndex, packet.UserSessionUniqueId,
72 | protocol.ERROR_CODE_ROOM_INVALIDE_NUMBER)
73 | return
74 | }
75 |
76 | user := room.getUser(packet.UserSessionUniqueId)
77 | if user == nil && isRoomEnterReq == false {
78 | protocol.NotifyErrorPacket(packet.UserSessionIndex, packet.UserSessionUniqueId,
79 | protocol.ERROR_CODE_ROOM_NOT_IN_USER)
80 | return
81 | }
82 |
83 | funcCount := len(room._funcPackeIdlist)
84 | for i := 0; i < funcCount; i++ {
85 | if room._funcPackeIdlist[i] != packet.Id {
86 | continue
87 | }
88 |
89 | room._funclist[i](user, packet)
90 | return
91 | }
92 | }
93 |
94 | func (roomMgr *RoomManager) CheckRoomState(curTimeMilliSec int64) {
95 | //TODO 한번에 모든 방을 다 조사할 필요가 없다. 밀리세컨드 단위로 타이머를 돌게 하고 그룹 단위로 방을 조사한다
96 |
97 | for i := 0; i < (int)(roomMgr._maxRoomCount); i++ {
98 | roomMgr._roomList[i].checkState(curTimeMilliSec)
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/baccaratServer/roomPkg/roomUser.go:
--------------------------------------------------------------------------------
1 | package roomPkg
2 |
3 | import "main/protocol"
4 |
5 | type roomUser struct {
6 | netSessionIndex int32
7 | netSessionUniqueId uint64
8 |
9 | // <<< 다른 유저에게 알려줘야 하는 정보
10 | RoomUniqueId uint64
11 | IDLen int8
12 | ID [protocol.MAX_USER_ID_BYTE_LENGTH]byte
13 | // >>> 다른 유저에게 알려줘야 하는 정보
14 | packetDataSize int16 // 다른 유저에게 알려줘야 하는 정보 의 크기
15 |
16 | selectBat int8
17 | }
18 |
19 | func (user *roomUser) init(userID []byte, uniqueId uint64) {
20 | idlen := len(userID)
21 |
22 | user.IDLen = int8(idlen)
23 | copy(user.ID[:], userID)
24 |
25 | user.RoomUniqueId = uniqueId
26 |
27 | user.selectBat = BATTING_SELECT_NONE
28 | }
29 |
30 | func (user *roomUser) SetNetworkInfo(sessionIndex int32, sessionUniqueId uint64) {
31 | user.netSessionIndex = sessionIndex
32 | user.netSessionUniqueId = sessionUniqueId
33 | }
34 |
35 | func (user *roomUser) PacketDataSize() int16 {
36 | return int16(1) + int16(user.IDLen) + 8
37 | }
38 |
39 | func (user *roomUser) selectBatting(value int8) {
40 | user.selectBat = value
41 | }
42 |
--------------------------------------------------------------------------------
/baccaratServer/roomPkg/room_Packet.go:
--------------------------------------------------------------------------------
1 | package roomPkg
2 |
3 | import (
4 | "main/protocol"
5 | )
6 |
7 | func (room *baseRoom) _packetProcess_Relay(user *roomUser, packet protocol.Packet) int16 {
8 | var relayNotify protocol.RoomRelayNtfPacket
9 | relayNotify.RoomUserUniqueId = user.RoomUniqueId
10 | relayNotify.Data = packet.Data
11 | notifySendBuf, packetSize := relayNotify.EncodingPacket(packet.DataSize)
12 | room.broadcastPacket(packetSize, notifySendBuf, 0)
13 |
14 | return protocol.ERROR_CODE_NONE
15 | }
--------------------------------------------------------------------------------
/baccaratServer/roomPkg/room_PacketChat.go:
--------------------------------------------------------------------------------
1 | package roomPkg
2 |
3 | import (
4 | . "gohipernetFake"
5 |
6 | "main/protocol"
7 | )
8 |
9 |
10 | func (room *baseRoom) _packetProcess_Chat(user *roomUser, packet protocol.Packet) int16 {
11 | sessionIndex := packet.UserSessionIndex
12 | sessionUniqueId := packet.UserSessionUniqueId
13 |
14 | var chatPacket protocol.RoomChatReqPacket
15 | if chatPacket.Decoding(packet.Data) == false {
16 | _sendRoomChatResult(sessionIndex, sessionUniqueId, protocol.ERROR_CODE_PACKET_DECODING_FAIL)
17 | return protocol.ERROR_CODE_PACKET_DECODING_FAIL
18 | }
19 |
20 | // 채팅 최대길이 제한
21 | msgLen := len(chatPacket.Msgs)
22 | if msgLen < 1 || msgLen > protocol.MAX_CHAT_MESSAGE_BYTE_LENGTH {
23 | _sendRoomChatResult(sessionIndex, sessionUniqueId, protocol.ERROR_CODE_ROOM_CHAT_CHAT_MSG_LEN)
24 | return protocol.ERROR_CODE_ROOM_CHAT_CHAT_MSG_LEN
25 | }
26 |
27 |
28 | var chatNotifyResponse protocol.RoomChatNtfPacket
29 | chatNotifyResponse.RoomUserUniqueId = user.RoomUniqueId
30 | chatNotifyResponse.MsgLen = int16(msgLen)
31 | chatNotifyResponse.Msg = chatPacket.Msgs
32 | notifySendBuf, packetSize := chatNotifyResponse.EncodingPacket()
33 | room.broadcastPacket(packetSize, notifySendBuf, 0)
34 |
35 |
36 | _sendRoomChatResult(sessionIndex, sessionUniqueId, protocol.ERROR_CODE_NONE)
37 |
38 | return protocol.ERROR_CODE_NONE
39 | }
40 |
41 | func _sendRoomChatResult(sessionIndex int32, sessionUniqueId uint64, result int16) {
42 | response := protocol.RoomChatResPacket{ result }
43 | sendPacket, _ := response.EncodingPacket()
44 | NetLibIPostSendToClient(sessionIndex, sessionUniqueId, sendPacket)
45 | }
--------------------------------------------------------------------------------
/baccaratServer/roomPkg/room_PacketEnter.go:
--------------------------------------------------------------------------------
1 | package roomPkg
2 |
3 | import (
4 | "time"
5 |
6 | . "gohipernetFake"
7 |
8 | "main/connectedSessions"
9 | "main/protocol"
10 | )
11 |
12 | func (room *baseRoom) _packetProcess_EnterUser(inValidUser *roomUser, packet protocol.Packet) int16 {
13 | curTime := time.Now().Unix()
14 | sessionIndex := packet.UserSessionIndex
15 | sessionUniqueId := packet.UserSessionUniqueId
16 |
17 | var requestPacket protocol.RoomEnterReqPacket
18 | (&requestPacket).Decoding(packet.Data)
19 |
20 | //TODO 방의 상태가 NONE이 아니면 들어올 수 없다.
21 |
22 | userID, ok := connectedSessions.GetUserID(sessionIndex)
23 | if ok == false {
24 | _sendRoomEnterResult(sessionIndex, sessionUniqueId, 0,0, protocol.ERROR_CODE_ENTER_ROOM_INVALID_USER_ID)
25 | return protocol.ERROR_CODE_ENTER_ROOM_INVALID_USER_ID
26 | }
27 |
28 | userInfo := addRoomUserInfo{
29 | userID,
30 | sessionIndex,
31 | sessionUniqueId,
32 | }
33 | newUser, addResult := room.addUser(userInfo)
34 |
35 | if addResult != protocol.ERROR_CODE_NONE {
36 | _sendRoomEnterResult(sessionIndex, sessionUniqueId, 0, 0, addResult)
37 | return addResult
38 | }
39 |
40 | if connectedSessions.SetRoomNumber(sessionIndex, sessionUniqueId, room.getNumber(), curTime) == false {
41 | _sendRoomEnterResult(sessionIndex, sessionUniqueId, 0, 0, protocol.ERROR_CODE_ENTER_ROOM_INVALID_SESSION_STATE)
42 | return protocol.ERROR_CODE_ENTER_ROOM_INVALID_SESSION_STATE
43 | }
44 |
45 | if room.getCurUserCount() > 1 {
46 | //룸의 다른 유저에게 통보한다.
47 | room._sendNewUserInfoPacket(newUser)
48 |
49 | // 지금 들어온 유저에게 이미 채널에 있는 유저들의 정보를 보낸다
50 | room._sendUserInfoListPacket(newUser)
51 | }
52 |
53 |
54 | roomNumebr := room.getNumber()
55 | _sendRoomEnterResult(sessionIndex, sessionUniqueId, roomNumebr, newUser.RoomUniqueId, protocol.ERROR_CODE_NONE)
56 | return protocol.ERROR_CODE_NONE
57 | }
58 |
59 | func _sendRoomEnterResult(sessionIndex int32, sessionUniqueId uint64, roomNumber int32, userUniqueId uint64, result int16) {
60 | response := protocol.RoomEnterResPacket{
61 | result,
62 | roomNumber,
63 | userUniqueId,
64 | }
65 | sendPacket, _ := response.EncodingPacket()
66 | NetLibIPostSendToClient(sessionIndex, sessionUniqueId, sendPacket)
67 | }
68 |
69 |
70 | func (room *baseRoom) _sendUserInfoListPacket(user *roomUser) {
71 | userCount, userInfoListSize, userInfoListBuffer := room.allocAllUserInfo(user.netSessionUniqueId)
72 |
73 | var response protocol.RoomUserListNtfPacket
74 | response.UserCount = userCount
75 | response.UserList = userInfoListBuffer
76 | sendBuf, _ := response.EncodingPacket(userInfoListSize)
77 | NetLibIPostSendToClient(user.netSessionIndex, user.netSessionUniqueId, sendBuf)
78 | }
79 |
80 | func (room *baseRoom) _sendNewUserInfoPacket(user *roomUser) {
81 | userInfoSize, userInfoListBuffer := room._allocUserInfo(user)
82 |
83 | var response protocol.RoomNewUserNtfPacket
84 | response.User = userInfoListBuffer
85 | sendBuf, packetSize := response.EncodingPacket(userInfoSize)
86 | room.broadcastPacket(int16(packetSize), sendBuf, user.netSessionUniqueId) // 자신을 제외하고 모든 유저에게 Send
87 | }
88 |
89 |
90 |
--------------------------------------------------------------------------------
/baccaratServer/roomPkg/room_PacketGame.go:
--------------------------------------------------------------------------------
1 | package roomPkg
2 |
3 | import (
4 | . "gohipernetFake"
5 |
6 | "main/protocol"
7 | )
8 |
9 |
10 | func (room *baseRoom) _packetProcess_GameStart(user *roomUser, packet protocol.Packet) int16 {
11 | errorCode := (int16)(protocol.ERROR_CODE_NONE)
12 | sessionIndex := packet.UserSessionIndex
13 | sessionUniqueId := packet.UserSessionUniqueId
14 |
15 | // 방의 상태가 NONE 인가?
16 | if room.isStateNone() == false {
17 | errorCode = protocol.ERROR_CODE_ROOM_GAME_START_INVALID_ROOM_STATE
18 | goto CheckError
19 | }
20 |
21 | // 유저의 최소 수. 현재는 테스트를 위해 일단 1명이 최소 수
22 | if room.getCurUserCount() < 1 {
23 | errorCode = protocol.ERROR_CODE_ROOM_GAME_START_NOT_ENOUGH_MEMBERS
24 | goto CheckError
25 | }
26 |
27 | // 시작 요청은 방장이 하는가?
28 | if room.getMasterSessionUniqueId() != sessionUniqueId {
29 | errorCode = protocol.ERROR_CODE_ROOM_GAME_START_NOT_MASTER
30 | goto CheckError
31 | }
32 |
33 | // 게임을 시작한다.
34 | room.changeState(ROOM_STATE_GAME_WAIT_BATTING)
35 |
36 | _sendRoomGameStartResult(sessionIndex, sessionUniqueId, errorCode)
37 | _sendRoomGameStartNotify(room);
38 | return errorCode
39 |
40 | CheckError:
41 | _sendRoomGameStartResult(sessionIndex, sessionUniqueId, errorCode)
42 | return errorCode
43 | }
44 |
45 | func _sendRoomGameStartResult(sessionIndex int32, sessionUniqueId uint64, result int16) {
46 | response := protocol.RoomGameStartResPacket{ result }
47 | sendPacket, _ := response.EncodingPacket()
48 | NetLibIPostSendToClient(sessionIndex, sessionUniqueId, sendPacket)
49 | }
50 |
51 | func _sendRoomGameStartNotify(room *baseRoom) {
52 | notify := protocol.RoomGameStartNtfPacket{}
53 | notifySendBuf, packetSize := notify.EncodingPacket()
54 | room.broadcastPacket(packetSize, notifySendBuf, 0)
55 | }
56 |
57 |
58 |
59 | func (room *baseRoom) _packetProcess_GameBatting(user *roomUser, packet protocol.Packet) int16 {
60 | errorCode := (int16)(protocol.ERROR_CODE_NONE)
61 | sessionIndex := packet.UserSessionIndex
62 | sessionUniqueId := packet.UserSessionUniqueId
63 | var battingPacket protocol.RoomGameBattingReqPacket
64 |
65 | // 방의 상태가 배팅 기다림인가?
66 | if room.isStateGameBattingWait() == false {
67 | errorCode = protocol.ERROR_CODE_ROOM_GAME_BATTING_INVALID_ROOM_STATE
68 | goto CheckError
69 | }
70 |
71 | if battingPacket.Decoding(packet.Data) == false {
72 | errorCode = protocol.ERROR_CODE_ROOM_GAME_BATTING_FAIL_PACKET
73 | goto CheckError
74 | }
75 |
76 | if battingPacket.SelectSide < BATTING_SELECT_PLAYER || battingPacket.SelectSide > BATTING_SELECT_BANKER {
77 | errorCode = protocol.ERROR_CODE_ROOM_GAME_BATTING_INVALID_BAT_SELECT
78 | goto CheckError
79 | }
80 |
81 | if battingPacket.SelectSide == user.selectBat {
82 | errorCode = protocol.ERROR_CODE_ROOM_GAME_BATTING_SAME_BAT_SELECT
83 | goto CheckError
84 | }
85 |
86 |
87 | // 배팅하고, 모두에게 알린다.
88 | user.selectBatting(battingPacket.SelectSide)
89 |
90 | _sendRoomGameBattingResult(sessionIndex, sessionUniqueId, errorCode)
91 |
92 | _sendRoomGameBattingNotify(room, user.RoomUniqueId, battingPacket.SelectSide)
93 |
94 |
95 | if room.isAllUserBatting() {
96 | room.endGame()
97 | }
98 |
99 | return protocol.ERROR_CODE_NONE
100 |
101 | CheckError:
102 | _sendRoomGameBattingResult(sessionIndex, sessionUniqueId, errorCode)
103 | return errorCode
104 | }
105 |
106 | func _sendRoomGameBattingResult(sessionIndex int32, sessionUniqueId uint64, result int16) {
107 | response := protocol.RoomGameBattingResPacket{ result }
108 | sendPacket, _ := response.EncodingPacket()
109 | NetLibIPostSendToClient(sessionIndex, sessionUniqueId, sendPacket)
110 | }
111 |
112 | func _sendRoomGameBattingNotify(room *baseRoom, roomUserUniqueId uint64, selectSide int8) {
113 | notify := protocol.RoomGameBattingNtfPacket{ roomUserUniqueId, selectSide }
114 | notifySendBuf, packetSize := notify.EncodingPacket()
115 | room.broadcastPacket(packetSize, notifySendBuf, 0)
116 | }
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
--------------------------------------------------------------------------------
/baccaratServer/roomPkg/room_PacketLeave.go:
--------------------------------------------------------------------------------
1 | package roomPkg
2 |
3 | import (
4 | "time"
5 |
6 | . "gohipernetFake"
7 |
8 | "main/connectedSessions"
9 | "main/protocol"
10 | )
11 |
12 |
13 | func (room *baseRoom) _packetProcess_LeaveUser(user *roomUser, packet protocol.Packet) int16 {
14 | room._leaveUserProcess(user)
15 |
16 | sessionIndex := packet.UserSessionIndex
17 | sessionUniqueId := packet.UserSessionUniqueId
18 | _sendRoomLeaveResult(sessionIndex, sessionUniqueId, protocol.ERROR_CODE_NONE)
19 | return protocol.ERROR_CODE_NONE
20 | }
21 |
22 | func (room *baseRoom) _leaveUserProcess(user *roomUser) {
23 | //TODO 방의 상태가 ROOM_STATE_NOE, ROOM_STATE_GAME_RESULT 일 때만 나갈 수 있다.
24 |
25 | //TODO 유저가 접속이 끊어져서 나가는 경우라면 게임이 끝날 때까지 유저 정보 들고 있다가
26 | // ROOM_STATE_GAME_RESULT 상태일 때 제거한다.
27 |
28 | roomUserUniqueId := user.RoomUniqueId
29 | userSessionIndex := user.netSessionIndex
30 | userSessionUniqueId := user.netSessionUniqueId
31 |
32 | room._removeUser(user)
33 |
34 | room._sendRoomLeaveUserNotify(roomUserUniqueId, userSessionUniqueId)
35 |
36 | curTime := time.Now().Unix()
37 | connectedSessions.SetRoomNumber(userSessionIndex, userSessionUniqueId, -1, curTime)
38 | }
39 |
40 |
41 | func _sendRoomLeaveResult(sessionIndex int32, sessionUniqueId uint64, result int16) {
42 | response := protocol.RoomLeaveResPacket{ result }
43 | sendPacket, _ := response.EncodingPacket()
44 | NetLibIPostSendToClient(sessionIndex, sessionUniqueId, sendPacket)
45 | }
46 |
47 | func (room *baseRoom) _sendRoomLeaveUserNotify(roomUserUniqueId uint64, userSessionUniqueId uint64) {
48 | notifyPacket := protocol.RoomLeaveUserNtfPacket{roomUserUniqueId }
49 | sendBuf, packetSize := notifyPacket.EncodingPacket()
50 | room.broadcastPacket(int16(packetSize), sendBuf, userSessionUniqueId)
51 | }
--------------------------------------------------------------------------------
/bin/config_logger.json:
--------------------------------------------------------------------------------
1 | {
2 | "level": "debug",
3 | "encoding": "json",
4 | "maxSize": 100,
5 | "maxBackups" : 3,
6 | "maxAge" : 28,
7 | "encoderConfig": {
8 | "messageKey": "Msg",
9 | "levelKey": "Level",
10 | "timeKey": "Time",
11 | "nameKey": "Name",
12 | "callerKey": "Caller",
13 | "stacktraceKey": "St",
14 | "levelEncoder": "capital",
15 | "timeEncoder": "iso8601",
16 | "durationEncoder": "string",
17 | "callerEncoder": "short"
18 | },
19 | "outputPaths": [
20 | "stdout"
21 | ],
22 | "errorOutputPaths": [
23 | "stderr"
24 | ]
25 | }
26 |
--------------------------------------------------------------------------------
/bin/run_baccaratServer.bat:
--------------------------------------------------------------------------------
1 | baccaratServer.exe -c_IsTcp4Addr=true -c_BindAddress=127.0.0.1:11021 -c_MaxSessionCount=200 -c_MaxPacketSize=1024
--------------------------------------------------------------------------------
/bin/run_chatServer.bat:
--------------------------------------------------------------------------------
1 | chatServer.exe -c_IsTcp4Addr=true -c_BindAddress=127.0.0.1:11021 -c_MaxSessionCount=200 -c_MaxPacketSize=1024
--------------------------------------------------------------------------------
/bin/run_chatServer2.bat:
--------------------------------------------------------------------------------
1 | chatServer2.exe -c_IsTcp4Addr=true -c_BindAddress=127.0.0.1:11021 -c_MaxSessionCount=20000 -c_MaxPacketSize=1024 -c_MaxReceiveBufferSize=4012 -GameName=chatServer2 -RoomMaxCount=2 -RoomStartNum=0 -RoomMaxUserCount=2 -RoomMaxProcessBufferCount=2 -RoomCountByGoroutine=2 -RoomInternalPacketChanBufferCount=2 -CheckCountAtOnce=256 -CheckReriodMillSec=32 -LoginWaitTimeSec=6000 -DisConnectWaitTimeSec=6000 -RoomEnterWaitTimeSec=6000 -PingWaitTimeSec=6000 -MaxRequestCountPerSecond=6000
--------------------------------------------------------------------------------
/bin/run_echoServer.bat:
--------------------------------------------------------------------------------
1 | echoServer.exe -c_IsTcp4Addr=true -c_BindAddress=127.0.0.1:11021 -c_MaxSessionCount=20000 -c_MaxPacketSize=1024
--------------------------------------------------------------------------------
/chatServer/chatServer.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "strconv"
5 | "strings"
6 |
7 | . "gohipernetFake"
8 |
9 | "main/connectedSessions"
10 | "main/protocol"
11 | "main/roomPkg"
12 | )
13 |
14 | type configAppServer struct {
15 | GameName string
16 |
17 | RoomMaxCount int32
18 | RoomStartNum int32
19 | RoomMaxUserCount int32
20 | }
21 |
22 | type ChatServer struct {
23 | ServerIndex int
24 | IP string
25 | Port int
26 |
27 | PacketChan chan protocol.Packet
28 |
29 | RoomMgr *roomPkg.RoomManager
30 | }
31 |
32 | func createAnsStartServer(netConfig NetworkConfig, appConfig configAppServer) {
33 | OutPutLog(LOG_LEVEL_INFO, "", 0, "CreateServer !!!")
34 |
35 | var server ChatServer
36 |
37 | if server.setIPAddress(netConfig.BindAddress) == false {
38 | OutPutLog(LOG_LEVEL_INFO, "", 0, "fail. server address")
39 | return
40 | }
41 |
42 | protocol.Init_packet();
43 |
44 | maxUserCount := appConfig.RoomMaxCount * appConfig.RoomMaxUserCount
45 | connectedSessions.Init(netConfig.MaxSessionCount, maxUserCount)
46 |
47 | server.PacketChan = make(chan protocol.Packet, 256)
48 |
49 | roomConfig := roomPkg.RoomConfig{
50 | appConfig.RoomStartNum,
51 | appConfig.RoomMaxCount,
52 | appConfig.RoomMaxUserCount,
53 | }
54 | server.RoomMgr = roomPkg.NewRoomManager(roomConfig)
55 |
56 |
57 | go server.PacketProcess_goroutine()
58 |
59 |
60 | networkFunctor := SessionNetworkFunctors{}
61 | networkFunctor.OnConnect = server.OnConnect
62 | networkFunctor.OnReceive = server.OnReceive
63 | networkFunctor.OnReceiveBufferedData = nil
64 | networkFunctor.OnClose = server.OnClose
65 | networkFunctor.PacketTotalSizeFunc = PacketTotalSize
66 | networkFunctor.PacketHeaderSize = PACKET_HEADER_SIZE
67 | networkFunctor.IsClientSession = true
68 |
69 |
70 | NetLibStartNetwork(&netConfig, networkFunctor)
71 | }
72 |
73 | func (server *ChatServer) setIPAddress(ipAddress string) bool {
74 | results := strings.Split(ipAddress, ":")
75 | if len(results) != 2 {
76 | return false
77 | }
78 |
79 | server.IP = results[0]
80 | server.Port, _ = strconv.Atoi(results[1])
81 |
82 | return true
83 | }
84 |
85 |
86 |
87 |
88 | func (server *ChatServer) OnConnect(sessionIndex int32, sessionUniqueID uint64) {
89 | connectedSessions.AddSession(sessionIndex, sessionUniqueID)
90 | }
91 |
92 | func (server *ChatServer) OnReceive(sessionIndex int32, sessionUniqueID uint64, data []byte) bool {
93 | server.DistributePacket(sessionIndex, sessionUniqueID, data)
94 | return true
95 | }
96 |
97 | func (server *ChatServer) OnClose(sessionIndex int32, sessionUniqueID uint64) {
98 | server.disConnectClient(sessionIndex, sessionUniqueID)
99 | }
100 |
101 | func (server *ChatServer) disConnectClient(sessionIndex int32, sessionUniqueId uint64) {
102 | // 로그인도 안한 유저라면 그냥 여기서 처리한다.
103 | // 방 입장을 안한 유저라면 여기서 처리해도 괜찮지만 아래로 넘긴다.
104 | if connectedSessions.IsLoginUser(sessionIndex) == false {
105 | connectedSessions.RemoveSession(sessionIndex, false)
106 | return
107 | }
108 |
109 |
110 | packet := protocol.Packet {
111 | sessionIndex,
112 | sessionUniqueId,
113 | protocol.PACKET_ID_SESSION_CLOSE_SYS,
114 | 0,
115 | nil,
116 | }
117 |
118 | server.PacketChan <- packet
119 | }
120 |
--------------------------------------------------------------------------------
/chatServer/connectedSessions/session.go:
--------------------------------------------------------------------------------
1 | package connectedSessions
2 |
3 | import (
4 | "sync/atomic"
5 |
6 | "main/protocol"
7 | )
8 |
9 | type session struct {
10 | _index int32
11 |
12 | _networkUniqueID uint64 //네트워크 세션의 유니크 ID
13 |
14 | _userID [protocol.MAX_USER_ID_BYTE_LENGTH]byte
15 | _userIDLength int8
16 |
17 | _connectTimeSec int64 // 연결된 시간
18 | _RoomNum int32 //
19 | _RoomNumOfEntering int32 // 현재 입장 중인 룸의 번호
20 | }
21 |
22 | func (session *session) Init(index int32) {
23 | session._index = index
24 | session.Clear()
25 | }
26 |
27 | func (session *session) _ClearUserId() {
28 | session._userIDLength = 0
29 | }
30 |
31 | func (session *session) Clear() {
32 | session._ClearUserId()
33 | session.setRoomNumber(0, -1, 0)
34 | session.SetConnectTimeSec(0, 0)
35 | }
36 |
37 | func (session *session) GetIndex() int32 {
38 | return session._index
39 | }
40 |
41 | func (session *session) GetNetworkUniqueID() uint64 {
42 | return atomic.LoadUint64(&session._networkUniqueID)
43 | }
44 |
45 | func (session *session) validNetworkUniqueID(uniqueId uint64) bool {
46 | return atomic.LoadUint64(&session._networkUniqueID) == uniqueId
47 | }
48 |
49 | func (session *session) GetNetworkInfo() (int32, uint64) {
50 | index := session.GetIndex()
51 | uniqueID := atomic.LoadUint64(&session._networkUniqueID)
52 | return index, uniqueID
53 | }
54 |
55 | func (session *session) setUserID(userID []byte) {
56 | session._userIDLength = int8(len(userID))
57 | copy(session._userID[:], userID)
58 | }
59 |
60 | func (session *session) getUserID() []byte {
61 | return session._userID[0:session._userIDLength]
62 | }
63 |
64 | func (session *session) getUserIDLength() int8 {
65 | return session._userIDLength
66 | }
67 |
68 | func (session *session) SetConnectTimeSec(timeSec int64, uniqueID uint64) {
69 | atomic.StoreInt64(&session._connectTimeSec, timeSec)
70 | atomic.StoreUint64(&session._networkUniqueID, uniqueID)
71 | }
72 |
73 | func (session *session) GetConnectTimeSec() int64 {
74 | return atomic.LoadInt64(&session._connectTimeSec)
75 | }
76 |
77 | func (session *session) SetUser(sessionUniqueId uint64,
78 | userID []byte,
79 | curTimeSec int64,
80 | ) {
81 | session.setUserID(userID)
82 | session.setRoomNumber(sessionUniqueId, -1, curTimeSec) // 방어적인 목적으로 채널 번호 초기화
83 | }
84 |
85 | func (session *session) IsAuth() bool {
86 | if session._userIDLength > 0 {
87 | return true
88 | }
89 |
90 | return false
91 | }
92 |
93 | func (session *session) setRoomEntering(roomNum int32) bool {
94 | if atomic.CompareAndSwapInt32(&session._RoomNumOfEntering, -1, roomNum) == false {
95 | return false
96 | }
97 |
98 | return true
99 | }
100 |
101 | func (session *session) setRoomNumber(sessionUniqueId uint64, roomNum int32, curTimeSec int64) bool {
102 | if roomNum == -1 {
103 | atomic.StoreInt32(&session._RoomNum, roomNum)
104 | atomic.StoreInt32(&session._RoomNumOfEntering, roomNum)
105 | return true
106 | }
107 |
108 | if sessionUniqueId != 0 && session.validNetworkUniqueID(sessionUniqueId) == false {
109 | return false
110 |
111 | }
112 | // 입력이 -1이 아닌경우 -1이 아닐 때만 compareswap으로 변경한다. 실패하면 채널 입장도 실패이다.
113 | if atomic.CompareAndSwapInt32(&session._RoomNum, -1, roomNum) == false {
114 | return false
115 | }
116 |
117 | atomic.StoreInt32(&session._RoomNumOfEntering, roomNum)
118 | return true
119 | }
120 |
121 | func (session *session) getRoomNumber() (int32, int32) {
122 | roomNum := atomic.LoadInt32(&session._RoomNum)
123 | roomNumOfEntering := atomic.LoadInt32(&session._RoomNum)
124 | return roomNum, roomNumOfEntering
125 | }
126 |
--------------------------------------------------------------------------------
/chatServer/connectedSessions/sessionManager.go:
--------------------------------------------------------------------------------
1 | package connectedSessions
2 |
3 | import (
4 | "sync"
5 | "sync/atomic"
6 | "time"
7 | )
8 |
9 | // 스레드 세이프 해야 한다.
10 | type Manager struct {
11 | _UserIDsessionMap *sync.Map
12 |
13 | _maxSessionCount int32
14 | _sessionList []*session
15 |
16 | _maxUserCount int32
17 |
18 | _currentLoginUserCount int32
19 | }
20 |
21 | var _manager Manager
22 |
23 | func Init(maxSessionCount int, maxUserCount int32) bool {
24 | _manager._UserIDsessionMap = new(sync.Map)
25 | _manager._maxUserCount = maxUserCount
26 |
27 | _manager._maxSessionCount = int32(maxSessionCount)
28 | _manager._sessionList = make([]*session, maxSessionCount)
29 |
30 | for i := 0; i < maxSessionCount; i++ {
31 | _manager._sessionList[i] = new(session)
32 |
33 | index := int32(i)
34 | _manager._sessionList[i].Init(index)
35 | }
36 |
37 | return true
38 | }
39 |
40 | func AddSession(sessionIndex int32, sessionUniqueID uint64) bool {
41 | if _validSessionIndex(sessionIndex) == false {
42 | return false
43 | }
44 |
45 | if _manager._sessionList[sessionIndex].GetConnectTimeSec() > 0 {
46 | return false
47 | }
48 |
49 | // 방어적인 목적으로 한번 더 Clear 한다
50 | _manager._sessionList[sessionIndex].Clear()
51 |
52 | _manager._sessionList[sessionIndex].SetConnectTimeSec(time.Now().Unix(), sessionUniqueID)
53 | return true
54 | }
55 |
56 | func RemoveSession(sessionIndex int32, isLoginedUser bool) bool {
57 | if _validSessionIndex(sessionIndex) == false {
58 | return false
59 | }
60 |
61 | if isLoginedUser {
62 | atomic.AddInt32(&_manager._currentLoginUserCount, -1)
63 |
64 | userID := string(_manager._sessionList[sessionIndex].getUserID())
65 | _manager._UserIDsessionMap.Delete(userID)
66 | }
67 |
68 | _manager._sessionList[sessionIndex].Clear()
69 |
70 | return true
71 | }
72 |
73 | func _validSessionIndex(index int32) bool {
74 | if index < 0 || index >= _manager._maxSessionCount {
75 | return false
76 | }
77 | return true
78 | }
79 |
80 | func GetNetworkUniqueID(sessionIndex int32) uint64 {
81 | if _validSessionIndex(sessionIndex) == false {
82 | return 0
83 | }
84 |
85 | return _manager._sessionList[sessionIndex].GetNetworkUniqueID()
86 | }
87 |
88 | func GetUserID(sessionIndex int32) ([]byte, bool) {
89 | if _validSessionIndex(sessionIndex) == false {
90 | return nil, false
91 | }
92 |
93 | return _manager._sessionList[sessionIndex].getUserID(), true
94 | }
95 |
96 | func SetLogin(sessionIndex int32, sessionUniqueId uint64, userID []byte, curTimeSec int64) bool {
97 | if _validSessionIndex(sessionIndex) == false {
98 | return false
99 | }
100 |
101 | newUserID := string(userID)
102 | if _, ok := _manager._UserIDsessionMap.Load(newUserID); ok {
103 | return false
104 | }
105 |
106 | _manager._sessionList[sessionIndex].SetUser(sessionUniqueId, userID, curTimeSec)
107 | _manager._UserIDsessionMap.Store(newUserID, _manager._sessionList[sessionIndex])
108 |
109 | atomic.AddInt32(&_manager._currentLoginUserCount, 1)
110 | return true
111 | }
112 |
113 | func IsLoginUser(sessionIndex int32) bool {
114 | if _validSessionIndex(sessionIndex) == false {
115 | return false
116 | }
117 |
118 | return _manager._sessionList[sessionIndex].IsAuth()
119 | }
120 |
121 | func SetRoomNumber(sessionIndex int32, sessionUniqueId uint64, roomNum int32, curTimeSec int64) bool {
122 | if _validSessionIndex(sessionIndex) == false {
123 | return false
124 | }
125 |
126 | return _manager._sessionList[sessionIndex].setRoomNumber(sessionUniqueId, roomNum, curTimeSec)
127 | }
128 |
129 | func GetRoomNumber(sessionIndex int32) (int32, int32) {
130 | if _validSessionIndex(sessionIndex) == false {
131 | return -1, -1
132 | }
133 | return _manager._sessionList[sessionIndex].getRoomNumber()
134 | }
135 |
--------------------------------------------------------------------------------
/chatServer/distributePacket.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "bytes"
5 | "main/connectedSessions"
6 | "time"
7 |
8 | . "gohipernetFake"
9 |
10 | "main/protocol"
11 | )
12 |
13 | func (server *ChatServer) DistributePacket(sessionIndex int32,
14 | sessionUniqueId uint64,
15 | packetData []byte,
16 | ) {
17 | packetID := protocol.PeekPacketID(packetData)
18 | bodySize, bodyData := protocol.PeekPacketBody(packetData)
19 |
20 |
21 | packet := protocol.Packet{Id: packetID}
22 | packet.UserSessionIndex = sessionIndex
23 | packet.UserSessionUniqueId = sessionUniqueId
24 | packet.Id = packetID
25 | packet.DataSize = bodySize
26 | packet.Data = make([]byte, packet.DataSize)
27 | copy(packet.Data, bodyData)
28 |
29 | server.PacketChan <- packet
30 | }
31 |
32 |
33 | func (server *ChatServer) PacketProcess_goroutine() {
34 | for {
35 | if server.PacketProcess_goroutine_Impl() {
36 | OutPutLog(LOG_LEVEL_INFO, "", 0, "Wanted Stop PacketProcess goroutine")
37 | break
38 | }
39 | }
40 |
41 | OutPutLog(LOG_LEVEL_INFO, "", 0,"Stop rooms PacketProcess goroutine")
42 | }
43 |
44 | func (server *ChatServer) PacketProcess_goroutine_Impl() bool {
45 | IsWantedTermination := false // 여기에서는 의미 없음. 서버 종료를 명시적으로 하는 경우만 유용
46 | defer PrintPanicStack()
47 |
48 |
49 | for {
50 | packet := <-server.PacketChan
51 | sessionIndex := packet.UserSessionIndex
52 | sessionUniqueId := packet.UserSessionUniqueId
53 | bodySize := packet.DataSize
54 | bodyData := packet.Data
55 |
56 | if packet.Id == protocol.PACKET_ID_LOGIN_REQ {
57 | ProcessPacketLogin(sessionIndex, sessionUniqueId, bodySize, bodyData)
58 | } else if packet.Id == protocol.PACKET_ID_SESSION_CLOSE_SYS {
59 | ProcessPacketSessionClosed(server, sessionIndex, sessionUniqueId)
60 | } else {
61 | roomNumber, _ := connectedSessions.GetRoomNumber(sessionIndex)
62 | server.RoomMgr.PacketProcess(roomNumber, packet)
63 | }
64 | }
65 |
66 | return IsWantedTermination
67 | }
68 |
69 | func ProcessPacketLogin(sessionIndex int32,
70 | sessionUniqueId uint64,
71 | bodySize int16,
72 | bodyData []byte ) {
73 | //DB와 연동하지 않으므로 중복 로그인만 아니면 다 성공으로 한다
74 | var request protocol.LoginReqPacket
75 | if (&request).Decoding(bodyData) == false {
76 | _sendLoginResult(sessionIndex, sessionUniqueId, protocol.ERROR_CODE_PACKET_DECODING_FAIL)
77 | return
78 | }
79 |
80 | userID := bytes.Trim(request.UserID[:], "\x00");
81 |
82 | if len(userID) <= 0 {
83 | _sendLoginResult(sessionIndex, sessionUniqueId, protocol.ERROR_CODE_LOGIN_USER_INVALID_ID)
84 | return
85 | }
86 |
87 | curTime := time.Now().Unix()
88 |
89 | if connectedSessions.SetLogin(sessionIndex, sessionUniqueId, userID, curTime) == false {
90 | _sendLoginResult(sessionIndex, sessionUniqueId, protocol.ERROR_CODE_LOGIN_USER_DUPLICATION)
91 | return
92 | }
93 |
94 | _sendLoginResult(sessionIndex, sessionUniqueId, protocol.ERROR_CODE_NONE)
95 | }
96 |
97 | func _sendLoginResult(sessionIndex int32, sessionUniqueId uint64, result int16) {
98 | var response protocol.LoginResPacket
99 | response.Result = result
100 | sendPacket, _ := response.EncodingPacket()
101 |
102 | NetLibIPostSendToClient(sessionIndex, sessionUniqueId, sendPacket)
103 | }
104 |
105 |
106 | func ProcessPacketSessionClosed(server *ChatServer, sessionIndex int32, sessionUniqueId uint64) {
107 | roomNumber, _ := connectedSessions.GetRoomNumber(sessionIndex)
108 |
109 | if roomNumber > -1 {
110 | packet := protocol.Packet{
111 | sessionIndex,
112 | sessionUniqueId,
113 | protocol.PACKET_ID_ROOM_LEAVE_REQ,
114 | 0,
115 | nil,
116 | }
117 |
118 | server.RoomMgr.PacketProcess(roomNumber, packet)
119 | }
120 |
121 | connectedSessions.RemoveSession(sessionIndex, true)
122 | }
123 |
124 |
125 |
--------------------------------------------------------------------------------
/chatServer/go.mod:
--------------------------------------------------------------------------------
1 | module main
2 |
3 | go 1.13
4 |
5 | require (
6 | github.com/davecgh/go-spew v1.1.1 // indirect
7 | go.uber.org/atomic v1.4.0 // indirect
8 | go.uber.org/multierr v1.1.0 // indirect
9 | go.uber.org/zap v1.10.0
10 | gohipernetFake v0.0.0
11 | gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
12 | )
13 |
14 | replace gohipernetFake v0.0.0 => ../gohipernetFake
15 |
--------------------------------------------------------------------------------
/chatServer/go.sum:
--------------------------------------------------------------------------------
1 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
2 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
3 | go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU=
4 | go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
5 | go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI=
6 | go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
7 | go.uber.org/zap v1.10.0 h1:ORx85nbTijNz8ljznvCMR1ZBIPKFn3jQrag10X2AsuM=
8 | go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
9 | gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=
10 | gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
11 |
--------------------------------------------------------------------------------
/chatServer/logger.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "encoding/json"
5 | "errors"
6 | "io/ioutil"
7 | "os"
8 | "path/filepath"
9 | "strings"
10 | "time"
11 |
12 | "go.uber.org/zap"
13 | "go.uber.org/zap/zapcore"
14 | "gopkg.in/natefinch/lumberjack.v2"
15 | )
16 |
17 | var (
18 | Logger, _ = zap.NewProduction()
19 | )
20 |
21 | type extendedZapConfig struct{
22 | MaxSize int `json:"maxSize"`
23 | MaxBackups int `json:"maxBackups"`
24 | MaxAge int `json:"maxAge"`
25 | zap.Config
26 | }
27 |
28 | func init_Log() {
29 | currentDir, err := filepath.Abs(filepath.Dir(os.Args[0]))
30 | if err != nil {
31 | panic(err)
32 | }
33 |
34 | configJson, err := ioutil.ReadFile(filepath.FromSlash(currentDir + "/" + "config_logger.json"))
35 | if err != nil {
36 | panic(err)
37 | }
38 |
39 | var myConfig extendedZapConfig
40 |
41 | if err := json.Unmarshal(configJson, &myConfig); err != nil {
42 | panic(err)
43 | }
44 |
45 | for index := range myConfig.ErrorOutputPaths{
46 | if myConfig.ErrorOutputPaths[index] != "stderr"{
47 | myConfig.ErrorOutputPaths[index], _ = _createFileName(myConfig.ErrorOutputPaths[index])
48 | }
49 | }
50 |
51 | enc := zapcore.NewJSONEncoder(myConfig.EncoderConfig)
52 | Logger = zap.New(zapcore.NewCore(enc, _combineSinkFromConfig(myConfig), myConfig.Level))
53 | }
54 |
55 | func _combineSinkFromConfig(myConfig extendedZapConfig) zapcore.WriteSyncer{
56 | var fileName string
57 | stdOutLogOn := false
58 | for index:= range myConfig.OutputPaths{
59 | if myConfig.OutputPaths[index] != "stdout"{ // 그 외는 텍스트 파일
60 | fileName = myConfig.OutputPaths[index]
61 | } else {
62 | stdOutLogOn = true // 설정파일에 stdout이 있을 경우
63 | }
64 | }
65 |
66 | sink := zapcore.AddSync(
67 | &lumberjack.Logger{
68 | Filename: fileName,
69 | MaxSize: myConfig.MaxSize, // MB 단위
70 | MaxBackups: myConfig.MaxBackups,
71 | MaxAge: myConfig.MaxAge, // 28일 단위
72 | },
73 | )
74 | var combineSink zapcore.WriteSyncer
75 | if stdOutLogOn {
76 | combineSink = zap.CombineWriteSyncers(sink, os.Stdout)
77 | } else {
78 | combineSink = sink
79 | }
80 | return combineSink
81 | }
82 |
83 | func _createFileName(outputName string) (string, error){
84 | currentTime := time.Now()
85 | formattedTime := currentTime.Format("20060102_150405")
86 | fileNameArr := strings.Split(outputName, ".")
87 | fileName := fileNameArr[0]
88 | fileExt := "." + fileNameArr[1]
89 | if len(fileNameArr) > 2{
90 | return "", errors.New("log ouput name Invalid")
91 | }
92 | return fileName + formattedTime + fileExt, nil
93 | }
94 |
95 |
96 | var IExportLog func(string, string) = _emptyExportLog
97 |
98 | func _emptyExportLog(level string, message string) {}
99 |
100 |
--------------------------------------------------------------------------------
/chatServer/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "flag"
5 | . "gohipernetFake"
6 | )
7 |
8 |
9 | func main() {
10 | NetLibInitLog(LOG_LEVEL_DEBUG, nil)
11 |
12 | netConfig, appConfig := parseAppConfig()
13 | netConfig.WriteNetworkConfig(true)
14 |
15 | // 아래 함수를 호출하면 강제적으로 종료 시킬 때까지 대기 상태가 된다.
16 | createAnsStartServer(netConfig, appConfig)
17 | }
18 |
19 | func parseAppConfig() (NetworkConfig, configAppServer) {
20 | OutPutLog(LOG_LEVEL_INFO,"", 0,"[[Setting NetworkConfig]]")
21 |
22 | //TODO flag 사용하기
23 | appConfig := configAppServer {
24 | "chatServer",
25 | 1000,
26 | 0,
27 | 4,
28 | }
29 |
30 |
31 | netConfig := NetworkConfig{}
32 |
33 | flag.BoolVar(&netConfig.IsTcp4Addr,"c_IsTcp4Addr", true, "bool flag")
34 | flag.StringVar(&netConfig.BindAddress,"c_BindAddress", "127.0.0.1:11021", "string flag")
35 | flag.IntVar(&netConfig.MaxSessionCount,"c_MaxSessionCount", 0, "int flag")
36 | flag.IntVar(&netConfig.MaxPacketSize,"c_MaxPacketSize", 0, "int flag")
37 |
38 | flag.Parse()
39 | return netConfig, appConfig
40 | }
41 |
42 |
--------------------------------------------------------------------------------
/chatServer/protocol/errorcode.go:
--------------------------------------------------------------------------------
1 | package protocol
2 |
3 | const (
4 | ERROR_CODE_NONE = 1
5 |
6 | ERROR_CODE_PACKET_DECODING_FAIL = 51
7 | ERROR_CODE_PACKET_NOT_LOGIN_USER = 52
8 | ERROR_CODE_ROOM_NOT_REGISTED_PACKET_ID = 53
9 | ERROR_CODE_USER_NOT_IN_ROOM = 54
10 |
11 | ERROR_CODE_DISCONNECT_UNAUTHENTICATED_USER = 61
12 |
13 | ERROR_CODE_LOGIN_USER_DUPLICATION = 111
14 | ERROR_CODE_LOGIN_USER_INVALID_ID = 112
15 |
16 | ERROR_CODE_ROOM_NOT_IN_USER = 121
17 | ERROR_CODE_ROOM_INVALIDE_NUMBER = 122
18 |
19 | ERROR_CODE_ENTER_ROOM_ALREADY = 131
20 | ERROR_CODE_ENTER_ROOM_PREV_WORKING = 132
21 | ERROR_CODE_ENTER_ROOM_INVALID_USER_ID = 133
22 | ERROR_CODE_ENTER_ROOM_USER_FULL = 134
23 | ERROR_CODE_ENTER_ROOM_DUPLCATION_USER = 135
24 | ERROR_CODE_ENTER_ROOM_INVALID_SESSION_STATE = 136
25 | ERROR_CODE_ENTER_ROOM_AUTO_ROOM_NUMBER = 137
26 |
27 | ERROR_CODE_LEAVE_ROOM_INTERNAL_INVALID_USER = 141
28 |
29 | ERROR_CODE_ROOM_CHAT_CHAT_MSG_LEN = 151
30 |
31 | ERROR_CODE_ROOM_RELAY_FAIL_DECPDING = 161
32 |
33 | ERROR_CODE_ROOM_NOT_REGISTED_INTERNAL_PACKET_ID = 252 // 번역 필요없음
34 |
35 |
36 | )
37 |
--------------------------------------------------------------------------------
/chatServer/protocol/packetID.go:
--------------------------------------------------------------------------------
1 | package protocol
2 |
3 |
4 | const (
5 | PACKET_ID_PING_REQ = 201
6 | PACKET_ID_PING_RES = 202
7 |
8 | PACKET_ID_ERROR_NTF = 203
9 |
10 | PACKET_ID_SESSION_CLOSE_SYS = 211
11 |
12 |
13 | PACKET_ID_LOGIN_REQ = 701
14 | PACKET_ID_LOGIN_RES = 702
15 |
16 | PACKET_ID_ROOM_ENTER_REQ = 721
17 | PACKET_ID_ROOM_ENTER_RES = 722
18 | PACKET_ID_ROOM_USER_LIST_NTF = 723
19 | PACKET_ID_ROOM_NEW_USER_NTF = 724
20 |
21 | PACKET_ID_ROOM_LEAVE_REQ = 726
22 | PACKET_ID_ROOM_LEAVE_RES = 727
23 | PACKET_ID_ROOM_LEAVE_USER_NTF = 728
24 |
25 | PACKET_ID_ROOM_CHAT_REQ = 731
26 | PACKET_ID_ROOM_CHAT_RES = 732
27 | PACKET_ID_ROOM_CHAT_NOTIFY = 733
28 |
29 | PACKET_ID_ROOM_RELAY_REQ = 741
30 | PACKET_ID_ROOM_RELAY_NTF = 742
31 |
32 |
33 | INTERNAL_PACKET_ID_DISCONNECTED_USER_TO_ROOM = 1602
34 | )
35 |
36 |
37 |
--------------------------------------------------------------------------------
/chatServer/roomPkg/define.go:
--------------------------------------------------------------------------------
1 | package roomPkg
2 |
3 | import "main/protocol"
4 |
5 | type RoomConfig struct {
6 | StartRoomNumber int32
7 | MaxRoomCount int32
8 | MaxUserCount int32
9 | }
10 |
11 | type roomUser struct {
12 | netSessionIndex int32
13 | netSessionUniqueId uint64
14 |
15 | // <<< 다른 유저에게 알려줘야 하는 정보
16 | RoomUniqueId uint64
17 | IDLen int8
18 | ID [protocol.MAX_USER_ID_BYTE_LENGTH]byte
19 | // >>> 다른 유저에게 알려줘야 하는 정보
20 | packetDataSize int16 // 다른 유저에게 알려줘야 하는 정보 의 크기
21 | }
22 |
23 | func (user *roomUser) init(userID []byte, uniqueId uint64) {
24 | idlen := len(userID)
25 |
26 | user.IDLen = int8(idlen)
27 | copy(user.ID[:], userID)
28 |
29 | user.RoomUniqueId = uniqueId
30 | }
31 |
32 | func (user *roomUser) SetNetworkInfo(sessionIndex int32, sessionUniqueId uint64) {
33 | user.netSessionIndex = sessionIndex
34 | user.netSessionUniqueId = sessionUniqueId
35 | }
36 |
37 | func (user *roomUser) PacketDataSize() int16 {
38 | return int16(1) + int16(user.IDLen) + 8
39 | }
40 |
41 | type addRoomUserInfo struct {
42 | userID []byte
43 |
44 | netSessionIndex int32
45 | netSessionUniqueId uint64
46 | }
47 |
--------------------------------------------------------------------------------
/chatServer/roomPkg/roomManager.go:
--------------------------------------------------------------------------------
1 | package roomPkg
2 |
3 | import (
4 | "main/protocol"
5 | )
6 |
7 | type RoomManager struct {
8 | _roomStartNum int32
9 | _maxRoomCount int32
10 | _roomCountList []int16
11 | _roomList []baseRoom
12 | }
13 |
14 | func NewRoomManager(config RoomConfig) *RoomManager {
15 | roomManager := new(RoomManager)
16 | roomManager._initialize(config)
17 | return roomManager
18 | }
19 |
20 | func (roomMgr *RoomManager) _initialize(config RoomConfig) {
21 | roomMgr._roomStartNum = config.StartRoomNumber
22 | roomMgr._maxRoomCount = config.MaxRoomCount
23 | roomMgr._roomCountList = make([]int16, config.MaxRoomCount)
24 | roomMgr._roomList = make([]baseRoom, config.MaxRoomCount)
25 |
26 | for i := int32(0); i < roomMgr._maxRoomCount; i++ {
27 | roomMgr._roomList[i].initialize(i, config)
28 | roomMgr._roomList[i].settingPacketFunction()
29 | }
30 | }
31 |
32 | func (roomMgr *RoomManager) GetAllChannelUserCount() []int16 {
33 | maxRoomCount := roomMgr._maxRoomCount
34 | for i := int32(0); i < maxRoomCount; i++ {
35 | roomMgr._roomCountList[i] = (int16)(roomMgr._getRoomUserCount(i))
36 | }
37 |
38 | return roomMgr._roomCountList
39 | }
40 |
41 | func (roomMgr *RoomManager) getRoomByNumber(roomNumber int32) *baseRoom {
42 | roomIndex := roomNumber - roomMgr._roomStartNum
43 |
44 | if roomNumber < 0 || roomIndex >= roomMgr._maxRoomCount {
45 | return nil
46 | }
47 |
48 | return &roomMgr._roomList[roomIndex]
49 | }
50 |
51 | // 이 함수를 호출할 때의 채널 인덱스는 꼭 호출자가 유효범위인 것을 보증해야 한다.
52 | func (roomMgr *RoomManager) _getRoomUserCount(roomId int32) int32 {
53 | return roomMgr._roomList[roomId].getCurUserCount()
54 | }
55 |
56 | func (roomMgr *RoomManager) PacketProcess(roomNumber int32, packet protocol.Packet) {
57 | isRoomEnterReq := false
58 |
59 | if roomNumber == -1 && packet.Id == protocol.PACKET_ID_ROOM_ENTER_REQ {
60 | isRoomEnterReq = true
61 |
62 | var requestPacket protocol.RoomEnterReqPacket
63 | (&requestPacket).Decoding(packet.Data)
64 |
65 | roomNumber = requestPacket.RoomNumber
66 | }
67 |
68 | room := roomMgr.getRoomByNumber(roomNumber)
69 | if room == nil {
70 | protocol.NotifyErrorPacket(packet.UserSessionIndex, packet.UserSessionUniqueId,
71 | protocol.ERROR_CODE_ROOM_INVALIDE_NUMBER)
72 | return
73 | }
74 |
75 | user := room.getUser(packet.UserSessionUniqueId)
76 | if user == nil && isRoomEnterReq == false {
77 | protocol.NotifyErrorPacket(packet.UserSessionIndex, packet.UserSessionUniqueId,
78 | protocol.ERROR_CODE_ROOM_NOT_IN_USER)
79 | return
80 | }
81 |
82 | funcCount := len(room._funcPackeIdlist)
83 | for i := 0; i < funcCount; i++ {
84 | if room._funcPackeIdlist[i] != packet.Id {
85 | continue
86 | }
87 |
88 | room._funclist[i](user, packet)
89 | return
90 | }
91 | }
92 |
93 |
--------------------------------------------------------------------------------
/chatServer/roomPkg/room_Packet.go:
--------------------------------------------------------------------------------
1 | package roomPkg
2 |
3 | import (
4 | "main/protocol"
5 | )
6 |
7 | func (room *baseRoom) _packetProcess_Relay(user *roomUser, packet protocol.Packet) int16 {
8 | var relayNotify protocol.RoomRelayNtfPacket
9 | relayNotify.RoomUserUniqueId = user.RoomUniqueId
10 | relayNotify.Data = packet.Data
11 | notifySendBuf, packetSize := relayNotify.EncodingPacket(packet.DataSize)
12 | room.broadcastPacket(packetSize, notifySendBuf, 0)
13 |
14 | return protocol.ERROR_CODE_NONE
15 | }
16 |
--------------------------------------------------------------------------------
/chatServer/roomPkg/room_PacketChat.go:
--------------------------------------------------------------------------------
1 | package roomPkg
2 |
3 | import (
4 | . "gohipernetFake"
5 |
6 | "main/protocol"
7 | )
8 |
9 | func (room *baseRoom) _packetProcess_Chat(user *roomUser, packet protocol.Packet) int16 {
10 | sessionIndex := packet.UserSessionIndex
11 | sessionUniqueId := packet.UserSessionUniqueId
12 |
13 | var chatPacket protocol.RoomChatReqPacket
14 | if chatPacket.Decoding(packet.Data) == false {
15 | _sendRoomChatResult(sessionIndex, sessionUniqueId, protocol.ERROR_CODE_PACKET_DECODING_FAIL)
16 | return protocol.ERROR_CODE_PACKET_DECODING_FAIL
17 | }
18 |
19 | // 채팅 최대길이 제한
20 | msgLen := len(chatPacket.Msgs)
21 | if msgLen < 1 || msgLen > protocol.MAX_CHAT_MESSAGE_BYTE_LENGTH {
22 | _sendRoomChatResult(sessionIndex, sessionUniqueId, protocol.ERROR_CODE_ROOM_CHAT_CHAT_MSG_LEN)
23 | return protocol.ERROR_CODE_ROOM_CHAT_CHAT_MSG_LEN
24 | }
25 |
26 | var chatNotifyResponse protocol.RoomChatNtfPacket
27 | chatNotifyResponse.RoomUserUniqueId = user.RoomUniqueId
28 | chatNotifyResponse.MsgLen = int16(msgLen)
29 | chatNotifyResponse.Msg = chatPacket.Msgs
30 | notifySendBuf, packetSize := chatNotifyResponse.EncodingPacket()
31 | room.broadcastPacket(packetSize, notifySendBuf, 0)
32 |
33 | _sendRoomChatResult(sessionIndex, sessionUniqueId, protocol.ERROR_CODE_NONE)
34 |
35 | return protocol.ERROR_CODE_NONE
36 | }
37 |
38 | func _sendRoomChatResult(sessionIndex int32, sessionUniqueId uint64, result int16) {
39 | response := protocol.RoomChatResPacket{result}
40 | sendPacket, _ := response.EncodingPacket()
41 | NetLibIPostSendToClient(sessionIndex, sessionUniqueId, sendPacket)
42 | }
43 |
--------------------------------------------------------------------------------
/chatServer/roomPkg/room_PacketEnter.go:
--------------------------------------------------------------------------------
1 | package roomPkg
2 |
3 | import (
4 | "time"
5 |
6 | . "gohipernetFake"
7 |
8 | "main/connectedSessions"
9 | "main/protocol"
10 | )
11 |
12 | func (room *baseRoom) _packetProcess_EnterUser(inValidUser *roomUser, packet protocol.Packet) int16 {
13 | curTime := time.Now().Unix()
14 | sessionIndex := packet.UserSessionIndex
15 | sessionUniqueId := packet.UserSessionUniqueId
16 |
17 | var requestPacket protocol.RoomEnterReqPacket
18 | (&requestPacket).Decoding(packet.Data)
19 |
20 | userID, ok := connectedSessions.GetUserID(sessionIndex)
21 | if ok == false {
22 | _sendRoomEnterResult(sessionIndex, sessionUniqueId, 0, 0, protocol.ERROR_CODE_ENTER_ROOM_INVALID_USER_ID)
23 | return protocol.ERROR_CODE_ENTER_ROOM_INVALID_USER_ID
24 | }
25 |
26 | userInfo := addRoomUserInfo{
27 | userID,
28 | sessionIndex,
29 | sessionUniqueId,
30 | }
31 | newUser, addResult := room.addUser(userInfo)
32 |
33 | if addResult != protocol.ERROR_CODE_NONE {
34 | _sendRoomEnterResult(sessionIndex, sessionUniqueId, 0, 0, addResult)
35 | return addResult
36 | }
37 |
38 | if connectedSessions.SetRoomNumber(sessionIndex, sessionUniqueId, room.getNumber(), curTime) == false {
39 | _sendRoomEnterResult(sessionIndex, sessionUniqueId, 0, 0, protocol.ERROR_CODE_ENTER_ROOM_INVALID_SESSION_STATE)
40 | return protocol.ERROR_CODE_ENTER_ROOM_INVALID_SESSION_STATE
41 | }
42 |
43 | if room.getCurUserCount() > 1 {
44 | //룸의 다른 유저에게 통보한다.
45 | room._sendNewUserInfoPacket(newUser)
46 |
47 | // 지금 들어온 유저에게 이미 채널에 있는 유저들의 정보를 보낸다
48 | room._sendUserInfoListPacket(newUser)
49 | }
50 |
51 | roomNumebr := room.getNumber()
52 | _sendRoomEnterResult(sessionIndex, sessionUniqueId, roomNumebr, newUser.RoomUniqueId, protocol.ERROR_CODE_NONE)
53 | return protocol.ERROR_CODE_NONE
54 | }
55 |
56 | func _sendRoomEnterResult(sessionIndex int32, sessionUniqueId uint64, roomNumber int32, userUniqueId uint64, result int16) {
57 | response := protocol.RoomEnterResPacket{
58 | result,
59 | roomNumber,
60 | userUniqueId,
61 | }
62 | sendPacket, _ := response.EncodingPacket()
63 | NetLibIPostSendToClient(sessionIndex, sessionUniqueId, sendPacket)
64 | }
65 |
66 | func (room *baseRoom) _sendUserInfoListPacket(user *roomUser) {
67 | userCount, userInfoListSize, userInfoListBuffer := room.allocAllUserInfo(user.netSessionUniqueId)
68 |
69 | var response protocol.RoomUserListNtfPacket
70 | response.UserCount = userCount
71 | response.UserList = userInfoListBuffer
72 | sendBuf, _ := response.EncodingPacket(userInfoListSize)
73 | NetLibIPostSendToClient(user.netSessionIndex, user.netSessionUniqueId, sendBuf)
74 | }
75 |
76 | func (room *baseRoom) _sendNewUserInfoPacket(user *roomUser) {
77 | userInfoSize, userInfoListBuffer := room._allocUserInfo(user)
78 |
79 | var response protocol.RoomNewUserNtfPacket
80 | response.User = userInfoListBuffer
81 | sendBuf, packetSize := response.EncodingPacket(userInfoSize)
82 | room.broadcastPacket(int16(packetSize), sendBuf, user.netSessionUniqueId) // 자신을 제외하고 모든 유저에게 Send
83 | }
84 |
--------------------------------------------------------------------------------
/chatServer/roomPkg/room_PacketLeave.go:
--------------------------------------------------------------------------------
1 | package roomPkg
2 |
3 | import (
4 | "time"
5 |
6 | . "gohipernetFake"
7 |
8 | "main/connectedSessions"
9 | "main/protocol"
10 | )
11 |
12 | func (room *baseRoom) _packetProcess_LeaveUser(user *roomUser, packet protocol.Packet) int16 {
13 | room._leaveUserProcess(user)
14 |
15 | sessionIndex := packet.UserSessionIndex
16 | sessionUniqueId := packet.UserSessionUniqueId
17 | _sendRoomLeaveResult(sessionIndex, sessionUniqueId, protocol.ERROR_CODE_NONE)
18 | return protocol.ERROR_CODE_NONE
19 | }
20 |
21 | func (room *baseRoom) _leaveUserProcess(user *roomUser) {
22 | roomUserUniqueId := user.RoomUniqueId
23 | userSessionIndex := user.netSessionIndex
24 | userSessionUniqueId := user.netSessionUniqueId
25 |
26 | room._removeUser(user)
27 |
28 | room._sendRoomLeaveUserNotify(roomUserUniqueId, userSessionUniqueId)
29 |
30 | curTime := time.Now().Unix()
31 | connectedSessions.SetRoomNumber(userSessionIndex, userSessionUniqueId, -1, curTime)
32 | }
33 |
34 | func _sendRoomLeaveResult(sessionIndex int32, sessionUniqueId uint64, result int16) {
35 | response := protocol.RoomLeaveResPacket{result}
36 | sendPacket, _ := response.EncodingPacket()
37 | NetLibIPostSendToClient(sessionIndex, sessionUniqueId, sendPacket)
38 | }
39 |
40 | func (room *baseRoom) _sendRoomLeaveUserNotify(roomUserUniqueId uint64, userSessionUniqueId uint64) {
41 | notifyPacket := protocol.RoomLeaveUserNtfPacket{roomUserUniqueId}
42 | sendBuf, packetSize := notifyPacket.EncodingPacket()
43 | room.broadcastPacket(int16(packetSize), sendBuf, userSessionUniqueId)
44 | }
45 |
--------------------------------------------------------------------------------
/chatServer2/chatServer.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "encoding/binary"
5 | "strconv"
6 | "strings"
7 | "time"
8 |
9 | "go.uber.org/zap"
10 |
11 | . "gohipernetFake"
12 | "main/connectedSessions"
13 | "main/protocol"
14 | "main/roomPkg"
15 | )
16 |
17 | type ChatServer struct {
18 | ServerIndex int
19 | IP string
20 | Port int
21 |
22 | appConfig configAppServer
23 |
24 | _roomMgr *roomPkg.RoomManager
25 |
26 | //_timerScheduler *TimerScheduler //현재는 사용하지 않음
27 | }
28 |
29 | func createServer(netConfig NetworkConfig, appConfig configAppServer) {
30 | NTELIB_LOG_INFO("CreateServer !!!")
31 |
32 | if _checkConfig(netConfig, appConfig) == false {
33 | return
34 | }
35 |
36 | var server ChatServer
37 |
38 | if server.setIPAddress(netConfig.BindAddress) == false {
39 | NTELIB_LOG_ERROR("fail. server address")
40 | return
41 | }
42 |
43 | protocol.Init_packet();
44 |
45 | server.init(int32(netConfig.MaxSessionCount), appConfig)
46 |
47 | networkFunctor := SessionNetworkFunctors{}
48 | networkFunctor.OnConnect = server.OnConnect
49 | networkFunctor.OnReceive = server.OnReceive
50 | networkFunctor.OnReceiveBufferedData = nil
51 | networkFunctor.OnClose = server.OnClose
52 | networkFunctor.PacketTotalSizeFunc = PacketTotalSize
53 | networkFunctor.PacketHeaderSize = PACKET_HEADER_SIZE
54 | networkFunctor.IsClientSession = true
55 |
56 | // 실습에서는 아래 코드 호출하여도 적용 되자 않음
57 | NetLibInitNetwork(protocol.ClientHeaderSize(), protocol.ServerHeaderSize())
58 |
59 | NetLibStartNetwork(&netConfig, networkFunctor)
60 |
61 | server.Stop()
62 | }
63 |
64 | func (server *ChatServer) setIPAddress(ipAddress string) bool {
65 | results := strings.Split(ipAddress, ":")
66 | if len(results) != 2 {
67 | return false
68 | }
69 |
70 | server.IP = results[0]
71 | server.Port, _ = strconv.Atoi(results[1])
72 |
73 | NTELIB_LOG_INFO("Server Address", zap.String("IP", server.IP), zap.Int("Port", server.Port))
74 | return true
75 | }
76 |
77 | func (server *ChatServer) init(maxClientSessionCount int32, appConfig configAppServer) bool {
78 | server.appConfig = appConfig
79 |
80 | maxUserCount := int32((appConfig.RoomMaxCount * appConfig.RoomMaxUserCount) + 3) // 3은 관리자 수
81 | checkStateConfig := connectedSessions.CheckSessionStateConfig{
82 | appConfig.CheckCountAtOnce,
83 | appConfig.CheckReriodMillSec,
84 | appConfig.LoginWaitTimeSec,
85 | appConfig.DisConnectWaitTimeSec,
86 | appConfig.RoomEnterWaitTimeSec,
87 | appConfig.PingWaitTimeSec,
88 | appConfig.MaxRequestCountPerSecond}
89 | connectedSessions.Init(maxClientSessionCount, maxUserCount, checkStateConfig)
90 | connectedSessions.Start()
91 |
92 | config := roomPkg.RoomConfig{int32(appConfig.RoomStartNum),
93 | int32(appConfig.RoomMaxCount),
94 | int32(appConfig.RoomMaxUserCount),
95 | int32(appConfig.RoomCountByGoroutine),
96 | int32(appConfig.RoomMaxProcessBufferCount),
97 | int32(appConfig.RoomInternalPacketChanBufferCount) }
98 |
99 | server._roomMgr = roomPkg.NewRoomManager(config)
100 | server._roomMgr.Start()
101 |
102 | //server._init_TimerScheduler()
103 | return true
104 | }
105 |
106 | /*func (server *ChatServer) _init_TimerScheduler() {
107 | NTELIB_LOG_INFO("Start main TimerScheduler")
108 |
109 | server._timerScheduler = new(TimerScheduler)
110 | server._timerScheduler.Start()
111 | }*/
112 |
113 | func (server *ChatServer) PacketTotalSize(data []byte) int16 {
114 | totalsize := binary.LittleEndian.Uint16(data)
115 | return int16(totalsize)
116 | }
117 |
118 | func (server *ChatServer) Stop() {
119 | NTELIB_LOG_INFO("chatServer Stop !!!")
120 |
121 | server._roomMgr.Stop()
122 |
123 | NTELIB_LOG_INFO("chatServer Stop Waitting...")
124 | time.Sleep(1 * time.Second)
125 | }
126 |
127 |
128 | func _checkConfig(netConfig NetworkConfig, appConfig configAppServer) bool {
129 | userCount := appConfig.RoomMaxUserCount * appConfig.RoomMaxCount
130 |
131 | if netConfig.MaxSessionCount < userCount {
132 | NTELIB_LOG_ERROR("userCount less than netConfig.MaxSessionCount", zap.Int("userCount", userCount), zap.Int("MaxSessionCount", netConfig.MaxSessionCount))
133 | return false
134 | }
135 | return true
136 | }
137 |
--------------------------------------------------------------------------------
/chatServer2/clientSessionEvent.go:
--------------------------------------------------------------------------------
1 | // 클라이언트 세션에 대한 네트워크 이벤트 처리
2 | package main
3 |
4 | import (
5 | "go.uber.org/zap"
6 |
7 | "main/connectedSessions"
8 | . "gohipernetFake"
9 | )
10 |
11 | func (server *ChatServer) OnConnect(sessionIndex int32, sessionUniqueID uint64) {
12 | NTELIB_LOG_INFO("client OnConnect", zap.Int32("sessionIndex",sessionIndex), zap.Uint64("sessionUniqueId",sessionUniqueID))
13 |
14 | connectedSessions.AddSession(sessionIndex, sessionUniqueID)
15 | }
16 |
17 | func (server *ChatServer) OnReceive(sessionIndex int32, sessionUniqueID uint64, data []byte) bool {
18 | server._distributePacket(sessionIndex, sessionUniqueID, data)
19 | return true
20 | }
21 |
22 | func (server *ChatServer) OnClose(sessionIndex int32, sessionUniqueID uint64) {
23 | NTELIB_LOG_INFO("client OnCloseClientSession", zap.Int32("sessionIndex", sessionIndex), zap.Uint64("sessionUniqueId", sessionUniqueID))
24 |
25 | server.disConnectClient(sessionIndex, sessionUniqueID)
26 | }
27 |
28 |
29 |
30 | func (server *ChatServer) disConnectClient(sessionIndex int32, sessionUniqueId uint64) {
31 | // 로그인도 안한 유저라면 그냥 여기서 처리한다.
32 | if connectedSessions.IsLoginUser(sessionIndex) == false {
33 | NTELIB_LOG_INFO("DisConnectClient - Not Login User", zap.Int32("sessionIndex", sessionIndex))
34 | connectedSessions.RemoveSession(sessionIndex, false)
35 | return
36 | }
37 |
38 | connectedTime := connectedSessions.GetConnectTimeSec(sessionIndex)
39 | if connectedTime == 0 {
40 | NTELIB_LOG_INFO("DisConnectClient - getConnectTimeSec is 0!")
41 | } else {
42 | //DB.WriteUserLastLoginTime(connectedTime, userID)
43 | }
44 |
45 |
46 | roomNum, roomNumOfEntering := connectedSessions.GetRoomNumber(sessionIndex)
47 |
48 | connectedSessions.RemoveSession(sessionIndex, true)
49 |
50 | if roomNum > -1 {
51 | server._roomMgr.DisConnectedUser(sessionUniqueId, roomNum)
52 | }
53 |
54 | // 현재 방에 들어가고 있는 중이므로 방에서 유저를 뺀다.
55 | if roomNumOfEntering > -1 && roomNum != roomNumOfEntering {
56 | server._roomMgr.DisConnectedUser(sessionUniqueId, roomNumOfEntering)
57 | }
58 |
59 | // 해당 세션을 초기화 한다. 메모리를 지우고, redis도 지운다
60 | NTELIB_LOG_INFO("DisConnectClient - Login User", zap.Int32("sessionIndex", sessionIndex))
61 | }
--------------------------------------------------------------------------------
/chatServer2/configAppServer.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | . "gohipernetFake"
5 | )
6 |
7 | type configAppServer struct {
8 | GameName string
9 |
10 | RoomMaxCount int
11 | RoomStartNum int
12 | RoomMaxUserCount int
13 | RoomMaxProcessBufferCount int
14 | RoomCountByGoroutine int
15 | RoomInternalPacketChanBufferCount int
16 |
17 | CheckCountAtOnce int
18 | CheckReriodMillSec int
19 | LoginWaitTimeSec int
20 | DisConnectWaitTimeSec int
21 | RoomEnterWaitTimeSec int
22 | PingWaitTimeSec int
23 | MaxRequestCountPerSecond int
24 | }
25 |
26 | func (config configAppServer) writeServerConfig() {
27 | NTELIB_LOG_INFO("writeServerConfig")
28 | /*NTELIB_LOG_INFO("writeServerConfig - " + config.GameName,
29 | zap.Int("RoomMaxCount", config.RoomMaxCount),
30 | zap.Int("RoomStartNum", config.RoomStartNum),
31 | zap.Int("RoomMaxUserCount", config.RoomMaxUserCount),
32 | zap.Int("RoomMaxProcessBufferCount", config.RoomMaxProcessBufferCount),
33 | zap.Int("RoomCountByGoroutine", config.RoomCountByGoroutine),
34 | zap.Int("RoomInternalPacketChanBufferCount", config.RoomInternalPacketChanBufferCount),
35 | zap.Int("CheckCountAtOnce", config.CheckCountAtOnce),
36 | zap.Int("CheckReriodMillSec", config.CheckReriodMillSec),
37 | zap.Int("LoginWaitTimeSec", config.LoginWaitTimeSec),
38 | zap.Int("DisConnectWaitTimeSec", config.DisConnectWaitTimeSec),
39 | zap.Int("RoomEnterWaitTimeSec", config.RoomEnterWaitTimeSec),
40 | zap.Int("PingWaitTimeSec", config.PingWaitTimeSec),
41 | zap.Int("MaxRequestCountPerSecond", config.MaxRequestCountPerSecond))*/
42 | }
--------------------------------------------------------------------------------
/chatServer2/go.mod:
--------------------------------------------------------------------------------
1 | module main
2 |
3 | go 1.13
4 |
5 | require (
6 | github.com/davecgh/go-spew v1.1.1 // indirect
7 | go.uber.org/atomic v1.4.0 // indirect
8 | go.uber.org/multierr v1.1.0 // indirect
9 | go.uber.org/zap v1.10.0
10 | gohipernetFake v0.0.0
11 | gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
12 | )
13 |
14 | replace gohipernetFake v0.0.0 => ../gohipernetFake
15 |
--------------------------------------------------------------------------------
/chatServer2/go.sum:
--------------------------------------------------------------------------------
1 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
2 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
3 | go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU=
4 | go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
5 | go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI=
6 | go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
7 | go.uber.org/zap v1.10.0 h1:ORx85nbTijNz8ljznvCMR1ZBIPKFn3jQrag10X2AsuM=
8 | go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
9 | gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=
10 | gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
11 |
--------------------------------------------------------------------------------
/chatServer2/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "flag"
5 |
6 | "go.uber.org/zap"
7 |
8 | . "gohipernetFake"
9 | "main/protocol"
10 | )
11 |
12 | func main() {
13 | NetLibInitLog()
14 |
15 | netConfig, appConfig := parseAppConfig()
16 | appConfig.writeServerConfig()
17 | netConfig.WriteNetworkConfig(true)
18 |
19 |
20 | protocol.Init_packet()
21 |
22 | NTELIB_LOG_INFO("[[protocolHeaderSize]]",
23 | zap.Int16("ClientHeaderSize", protocol.ClientHeaderSize()),
24 | zap.Int16("ServerHeaderSize", protocol.ServerHeaderSize()))
25 |
26 |
27 | // 아래 함수를 호출하면 강제적으로 종료 시킬 때까지 대기 상태가 된다.
28 | createServer(netConfig, appConfig)
29 | }
30 |
31 | func parseAppConfig() (NetworkConfig, configAppServer) {
32 | client := NetworkConfig{}
33 | appConfig := configAppServer{}
34 |
35 | flag.BoolVar(&client.IsTcp4Addr,"c_IsTcp4Addr", true, "bool flag")
36 | flag.StringVar(&client.BindAddress,"c_BindAddress", "127.0.0.1:11021", "string flag")
37 | flag.IntVar(&client.MaxSessionCount,"c_MaxSessionCount", 0, "int flag")
38 | flag.IntVar(&client.MaxPacketSize,"c_MaxPacketSize", 0, "int flag")
39 | flag.IntVar(&client.MaxReceiveBufferSize,"c_MaxReceiveBufferSize", 0, "int flag")
40 |
41 |
42 | //
43 | flag.StringVar(&appConfig.GameName,"GameName", "default", "string flag")
44 | flag.IntVar(&appConfig.RoomMaxCount,"RoomMaxCount", 0, "int flag")
45 | flag.IntVar(&appConfig.RoomStartNum,"RoomStartNum", 0, "int flag")
46 | flag.IntVar(&appConfig.RoomMaxUserCount,"RoomMaxUserCount", 0, "RoomMaxUserCount flag")
47 | flag.IntVar(&appConfig.RoomMaxProcessBufferCount,"RoomMaxProcessBufferCount", 0, "int flag")
48 | flag.IntVar(&appConfig.RoomCountByGoroutine,"RoomCountByGoroutine", 0, "int flag")
49 | flag.IntVar(&appConfig.RoomInternalPacketChanBufferCount,"RoomInternalPacketChanBufferCount", 0, "int flag")
50 |
51 | flag.IntVar(&appConfig.CheckCountAtOnce,"CheckCountAtOnce", 0, "int flag")
52 | flag.IntVar(&appConfig.CheckReriodMillSec,"CheckReriodMillSec", 0, "int flag")
53 | flag.IntVar(&appConfig.LoginWaitTimeSec,"LoginWaitTimeSec", 0, "int flag")
54 | flag.IntVar(&appConfig.DisConnectWaitTimeSec,"DisConnectWaitTimeSec", 0, "int flag")
55 | flag.IntVar(&appConfig.RoomEnterWaitTimeSec,"RoomEnterWaitTimeSec", 0, "int flag")
56 | flag.IntVar(&appConfig.PingWaitTimeSec,"PingWaitTimeSec", 0, "int flag")
57 | flag.IntVar(&appConfig.MaxRequestCountPerSecond,"MaxRequestCountPerSecond", 0, "int flag")
58 |
59 | flag.Parse()
60 | return client, appConfig
61 | }
--------------------------------------------------------------------------------
/chatServer2/protocol/errorcode.go:
--------------------------------------------------------------------------------
1 | package protocol
2 |
3 | const (
4 | ERROR_CODE_NONE = 1
5 |
6 | ERROR_CODE_PACKET_DECODING_FAIL = 51
7 | ERROR_CODE_PACKET_NOT_LOGIN_USER = 52
8 | ERROR_CODE_ROOM_NOT_REGISTED_PACKET_ID = 53
9 | ERROR_CODE_USER_NOT_IN_ROOM = 54
10 |
11 | ERROR_CODE_DISCONNECT_UNAUTHENTICATED_USER = 61
12 |
13 | ERROR_CODE_LOGIN_USER_DUPLICATION = 111
14 | ERROR_CODE_LOGIN_USER_INVALID_ID = 112
15 |
16 | ERROR_CODE_ROOM_NOT_IN_USER = 121
17 | ERROR_CODE_ROOM_INVALIDE_NUMBER = 122
18 |
19 | ERROR_CODE_ENTER_ROOM_ALREADY = 131
20 | ERROR_CODE_ENTER_ROOM_PREV_WORKING = 132
21 | ERROR_CODE_ENTER_ROOM_INVALID_USER_ID = 133
22 | ERROR_CODE_ENTER_ROOM_USER_FULL = 134
23 | ERROR_CODE_ENTER_ROOM_DUPLCATION_USER = 135
24 | ERROR_CODE_ENTER_ROOM_INVALID_SESSION_STATE = 136
25 | ERROR_CODE_ENTER_ROOM_AUTO_ROOM_NUMBER = 137
26 |
27 | ERROR_CODE_LEAVE_ROOM_INTERNAL_INVALID_USER = 141
28 |
29 | ERROR_CODE_ROOM_CHAT_CHAT_MSG_LEN = 151
30 |
31 | ERROR_CODE_ROOM_RELAY_FAIL_DECPDING = 161
32 |
33 | ERROR_CODE_ROOM_NOT_REGISTED_INTERNAL_PACKET_ID = 252 // 번역 필요없음
34 |
35 |
36 | )
37 |
--------------------------------------------------------------------------------
/chatServer2/protocol/internalPacket.go:
--------------------------------------------------------------------------------
1 | // 내부에서 사용하는 패킷
2 | package protocol
3 |
4 | import (
5 | . "gohipernetFake"
6 | )
7 |
8 | type InternalPacket struct {
9 | RoomIndex int32
10 | Id int16
11 | DataSize int16
12 | Data []byte
13 | }
14 |
15 |
16 | type InternalPacketDisConnectedUserToRoom struct{
17 | SessionUniqueId uint64
18 | RoomNum int32
19 | }
20 |
21 | func (packet *InternalPacketDisConnectedUserToRoom ) Encoding() ([]byte, int16) {
22 | totalSize := int16(8 + 4)
23 | sendBuf := make([]byte, totalSize)
24 |
25 | writer := MakeWriter(sendBuf, true)
26 | writer.WriteU64(packet.SessionUniqueId)
27 | writer.WriteS32(packet.RoomNum)
28 | return sendBuf, totalSize
29 | }
30 |
31 | func (packet *InternalPacketDisConnectedUserToRoom) Decoding(Data []byte) bool {
32 | reader := MakeReader(Data, true)
33 |
34 | packet.SessionUniqueId, _ = reader.ReadU64()
35 | packet.RoomNum, _ = reader.ReadS32()
36 | return true
37 | }
--------------------------------------------------------------------------------
/chatServer2/protocol/packetID.go:
--------------------------------------------------------------------------------
1 | package protocol
2 |
3 |
4 | const (
5 | PACKET_ID_DEV_ECHO_REQ = 192
6 | PACKET_ID_DEV_ECHO_RES = 193
7 |
8 | PACKET_ID_PING_REQ = 201
9 | PACKET_ID_PING_RES = 201
10 | PACKET_ID_ERROR_NTF = 203
11 |
12 |
13 | PACKET_ID_LOGIN_REQ = 701
14 | PACKET_ID_LOGIN_RES = 702
15 |
16 | PACKET_ID_ROOM_ENTER_REQ = 721
17 | PACKET_ID_ROOM_ENTER_RES = 722
18 | PACKET_ID_ROOM_USER_LIST_NTF = 723
19 | PACKET_ID_ROOM_NEW_USER_NTF = 724
20 |
21 | PACKET_ID_ROOM_LEAVE_REQ = 726
22 | PACKET_ID_ROOM_LEAVE_RES = 727
23 | PACKET_ID_ROOM_LEAVE_USER_NTF = 728
24 |
25 | PACKET_ID_ROOM_CHAT_REQ = 731
26 | PACKET_ID_ROOM_CHAT_RES = 732
27 | PACKET_ID_ROOM_CHAT_NOTIFY = 733
28 |
29 | PACKET_ID_ROOM_RELAY_REQ = 741
30 | PACKET_ID_ROOM_RELAY_NTF = 742
31 |
32 |
33 | INTERNAL_PACKET_ID_DISCONNECTED_USER_TO_ROOM = 1602
34 | )
35 |
36 |
37 |
--------------------------------------------------------------------------------
/chatServer2/roomPkg/define.go:
--------------------------------------------------------------------------------
1 | package roomPkg
2 |
3 | import "main/protocol"
4 |
5 | type RoomConfig struct {
6 | StartRoomNumber int32
7 | MaxRoomCount int32
8 | MaxUserCount int32
9 |
10 | RoomCountByGoroutine int32
11 | ChanPacketBufferCount int32
12 | InternalPacketChanBufferCount int32
13 | }
14 |
15 |
16 | type roomUser struct {
17 | netSessionIndex int32
18 | netSessionUniqueId uint64
19 |
20 | // <<< 다른 유저에게 알려줘야 하는 정보
21 | RoomUniqueId uint64
22 | IDLen int8
23 | ID [protocol.MAX_USER_ID_BYTE_LENGTH]byte
24 | // >>> 다른 유저에게 알려줘야 하는 정보
25 |
26 | packetDataSize int16
27 | }
28 |
29 | func (user *roomUser) init(userID []byte, uniqueId uint64) {
30 | idlen := len(userID)
31 |
32 | user.IDLen = int8(idlen)
33 | copy(user.ID[:], userID)
34 |
35 | user.RoomUniqueId = uniqueId
36 | }
37 |
38 | func (user *roomUser) SetNetworkInfo(sessionIndex int32, sessionUniqueId uint64) {
39 | user.netSessionIndex = sessionIndex
40 | user.netSessionUniqueId = sessionUniqueId
41 | }
42 |
43 | func (user *roomUser) PacketDataSize() int16 {
44 | return int16(1) + int16(user.IDLen) + 8
45 | }
46 |
47 |
48 |
49 | type RoomMemberPacket struct {
50 | RoomIndex int
51 |
52 | UserID []byte
53 | SessionIndex int32
54 | SessionUniqueId uint64
55 | }
56 |
57 |
58 |
59 | type userNetworkInfo struct {
60 | sessionIndex int32
61 | sessionUniqueId uint64
62 | }
63 |
64 | type addRoomUserInfo struct {
65 | userID []byte
66 |
67 | netSessionIndex int32
68 | netSessionUniqueId uint64
69 | }
70 |
--------------------------------------------------------------------------------
/chatServer2/roomPkg/room_Packet.go:
--------------------------------------------------------------------------------
1 | package roomPkg
2 |
3 | import (
4 | "go.uber.org/zap"
5 |
6 | "main/protocol"
7 | . "gohipernetFake"
8 | )
9 |
10 | func (room *baseRoom) _packetProcess_Relay(user *roomUser, packet protocol.Packet) int16 {
11 | var relayNotify protocol.RoomRelayNtfPacket
12 | relayNotify.RoomUserUniqueId = user.RoomUniqueId
13 | relayNotify.Data = packet.Data
14 | notifySendBuf, packetSize := relayNotify.EncodingPacket(packet.DataSize)
15 | room.broadcastPacket(packetSize, notifySendBuf, 0)
16 |
17 | NTELIB_LOG_DEBUG("Room Relay", zap.String("Sender", string(user.ID[:])))
18 | return protocol.ERROR_CODE_NONE
19 | }
--------------------------------------------------------------------------------
/chatServer2/roomPkg/room_PacketChat.go:
--------------------------------------------------------------------------------
1 | package roomPkg
2 |
3 | import (
4 | "go.uber.org/zap"
5 |
6 | "main/protocol"
7 | . "gohipernetFake"
8 | )
9 |
10 |
11 | func (room *baseRoom) _packetProcess_Chat(user *roomUser, packet protocol.Packet) int16 {
12 | sessionIndex := packet.UserSessionIndex
13 | sessionUniqueId := packet.UserSessionUniqueId
14 |
15 | var chatPacket protocol.RoomChatReqPacket
16 | if chatPacket.Decoding(packet.Data) == false {
17 | _sendRoomChatResult(sessionIndex, sessionUniqueId, protocol.ERROR_CODE_PACKET_DECODING_FAIL)
18 | return protocol.ERROR_CODE_PACKET_DECODING_FAIL
19 | }
20 |
21 | // 채팅 최대길이 제한
22 | msgLen := len(chatPacket.Msgs)
23 | if msgLen < 1 || msgLen > protocol.MAX_CHAT_MESSAGE_BYTE_LENGTH {
24 | _sendRoomChatResult(sessionIndex, sessionUniqueId, protocol.ERROR_CODE_ROOM_CHAT_CHAT_MSG_LEN)
25 | return protocol.ERROR_CODE_ROOM_CHAT_CHAT_MSG_LEN
26 | }
27 |
28 |
29 | var chatNotifyResponse protocol.RoomChatNtfPacket
30 | chatNotifyResponse.RoomUserUniqueId = user.RoomUniqueId
31 | chatNotifyResponse.MsgLen = int16(msgLen)
32 | chatNotifyResponse.Msg = chatPacket.Msgs
33 | notifySendBuf, packetSize := chatNotifyResponse.EncodingPacket()
34 | room.broadcastPacket(packetSize, notifySendBuf, 0)
35 |
36 |
37 | _sendRoomChatResult(sessionIndex, sessionUniqueId, protocol.ERROR_CODE_NONE)
38 |
39 | NTELIB_LOG_DEBUG("ParkChannel Chat Notify Function", zap.String("Sender", string(user.ID[:])),
40 | zap.String("Message", string(chatPacket.Msgs)))
41 |
42 | return protocol.ERROR_CODE_NONE
43 | }
44 |
45 | func _sendRoomChatResult(sessionIndex int32, sessionUniqueId uint64, result int16) {
46 | response := protocol.RoomChatResPacket{ result }
47 | sendPacket, _ := response.EncodingPacket()
48 | NetLibIPostSendToClient(sessionIndex, sessionUniqueId, sendPacket)
49 | }
--------------------------------------------------------------------------------
/chatServer2/timerScheduler.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "time"
5 |
6 | . "gohipernetFake"
7 | )
8 |
9 | type TimerScheduler struct {
10 | onDone chan struct{}
11 | }
12 |
13 | func (scheduler *TimerScheduler) Start() {
14 | scheduler.onDone = make(chan struct{})
15 | go scheduler._periodicLoop_goroutine()
16 | }
17 |
18 | func (scheduler *TimerScheduler) End() {
19 | close(scheduler.onDone)
20 | }
21 |
22 | func (scheduler *TimerScheduler) _periodicLoop_goroutine() {
23 | NTELIB_LOG_INFO("Start TimerScheduler goroutine !!!")
24 |
25 | for {
26 | if scheduler._periodicLoop_goroutine_Impl() {
27 | NTELIB_LOG_INFO("Wanted Stop TimerScheduler goroutine !!!")
28 | break
29 | }
30 | }
31 |
32 | NTELIB_LOG_INFO("Stop TimerScheduler goroutine !!!")
33 | }
34 |
35 | func (scheduler *TimerScheduler) _periodicLoop_goroutine_Impl() bool {
36 | IsWantedTermination := false
37 |
38 | secondTimeticker := time.NewTicker(time.Second)
39 |
40 | time.Sleep(2 * time.Second) // 순서 종속성으로 인해 2초 뒤 시작한다.
41 | defer PrintPanicStack()
42 | defer secondTimeticker.Stop()
43 |
44 | for {
45 | select {
46 | /*case secondTime := <-secondTimeticker.C:
47 | {
48 | NetLibSetCurrnetUnixTime(secondTime.Unix())
49 | }*/
50 | case <-scheduler.onDone:
51 | {
52 | IsWantedTermination = true
53 | break
54 | }
55 | }
56 | }
57 |
58 | return IsWantedTermination
59 | }
60 |
--------------------------------------------------------------------------------
/chatServer_msgpack/chatServer.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | . "gohipernetFake"
6 | "strconv"
7 | "strings"
8 |
9 | "main/connectedSessions"
10 | "main/protocol"
11 | "main/roomPkg"
12 | )
13 |
14 | type configAppServer struct {
15 | GameName string
16 |
17 | RoomMaxCount int32
18 | RoomStartNum int32
19 | RoomMaxUserCount int32
20 | }
21 |
22 | type ChatServer struct {
23 | ServerIndex int
24 | IP string
25 | Port int
26 |
27 | PacketChan chan protocol.Packet
28 |
29 | RoomMgr *roomPkg.RoomManager
30 | }
31 |
32 | func createAnsStartServer(netConfig NetworkConfig, appConfig configAppServer) {
33 | OutPutLog(LOG_LEVEL_INFO,"", 0,"CreateServer !!!")
34 |
35 | var server ChatServer
36 |
37 | if server.setIPAddress(netConfig.BindAddress) == false {
38 | OutPutLog(LOG_LEVEL_ERROR,"", 0,"fail. server address")
39 | return
40 | }
41 |
42 | protocol.Init_packet();
43 |
44 | maxUserCount := appConfig.RoomMaxCount * appConfig.RoomMaxUserCount
45 | connectedSessions.Init(netConfig.MaxSessionCount, maxUserCount)
46 |
47 | server.PacketChan = make(chan protocol.Packet, 256)
48 |
49 | roomConfig := roomPkg.RoomConfig{
50 | appConfig.RoomStartNum,
51 | appConfig.RoomMaxCount,
52 | appConfig.RoomMaxUserCount,
53 | }
54 | server.RoomMgr = roomPkg.NewRoomManager(roomConfig)
55 |
56 |
57 | go server.PacketProcess_goroutine()
58 |
59 |
60 | networkFunctor := SessionNetworkFunctors{}
61 | networkFunctor.OnConnect = server.OnConnect
62 | networkFunctor.OnReceive = server.OnReceive
63 | networkFunctor.OnReceiveBufferedData = nil
64 | networkFunctor.OnClose = server.OnClose
65 | networkFunctor.PacketTotalSizeFunc = PacketTotalSize
66 | networkFunctor.PacketHeaderSize = PACKET_HEADER_SIZE
67 | networkFunctor.IsClientSession = true
68 |
69 |
70 | NetLibStartNetwork(&netConfig, networkFunctor)
71 | }
72 |
73 | func (server *ChatServer) setIPAddress(ipAddress string) bool {
74 | results := strings.Split(ipAddress, ":")
75 | if len(results) != 2 {
76 | return false
77 | }
78 |
79 | server.IP = results[0]
80 | server.Port, _ = strconv.Atoi(results[1])
81 |
82 | return true
83 | }
84 |
85 | func (server *ChatServer) OnConnect(sessionIndex int32, sessionUniqueID uint64) {
86 | OutPutLog(LOG_LEVEL_INFO,"", 0,fmt.Sprintf("[OnConnect] sessionIndex: %d", sessionIndex))
87 |
88 | connectedSessions.AddSession(sessionIndex, sessionUniqueID)
89 | }
90 |
91 | func (server *ChatServer) OnReceive(sessionIndex int32, sessionUniqueID uint64, data []byte) bool {
92 | server.DistributePacket(sessionIndex, sessionUniqueID, data)
93 | return true
94 | }
95 |
96 | func (server *ChatServer) OnClose(sessionIndex int32, sessionUniqueID uint64) {
97 | OutPutLog(LOG_LEVEL_INFO,"", 0,fmt.Sprintf("[OnConnect] sessionIndex: %d", sessionIndex))
98 |
99 | server.disConnectClient(sessionIndex, sessionUniqueID)
100 | }
101 |
102 | func (server *ChatServer) disConnectClient(sessionIndex int32, sessionUniqueId uint64) {
103 | // 로그인도 안한 유저라면 그냥 여기서 처리한다.
104 | // 방 입장을 안한 유저라면 여기서 처리해도 괜찮지만 아래로 넘긴다.
105 | if connectedSessions.IsLoginUser(sessionIndex) == false {
106 | connectedSessions.RemoveSession(sessionIndex, false)
107 | return
108 | }
109 |
110 |
111 | packet := protocol.Packet {
112 | sessionIndex,
113 | sessionUniqueId,
114 | protocol.PACKET_ID_SESSION_CLOSE_SYS,
115 | 0,
116 | nil,
117 | }
118 |
119 | server.PacketChan <- packet
120 | }
121 |
--------------------------------------------------------------------------------
/chatServer_msgpack/connectedSessions/session.go:
--------------------------------------------------------------------------------
1 | package connectedSessions
2 |
3 | import (
4 | "sync/atomic"
5 |
6 | "main/protocol"
7 | )
8 |
9 | type session struct {
10 | _index int32
11 |
12 | _networkUniqueID uint64 //네트워크 세션의 유니크 ID
13 |
14 | _userID [protocol.MAX_USER_ID_BYTE_LENGTH]byte
15 | _userIDLength int8
16 |
17 | _connectTimeSec int64 // 연결된 시간
18 | _RoomNum int32 //
19 | _RoomNumOfEntering int32 // 현재 입장 중인 룸의 번호
20 | }
21 |
22 | func (session *session) Init(index int32) {
23 | session._index = index
24 | session.Clear()
25 | }
26 |
27 | func (session *session) _ClearUserId() {
28 | session._userIDLength = 0
29 | }
30 |
31 | func (session *session) Clear() {
32 | session._ClearUserId()
33 | session.setRoomNumber(0, -1, 0)
34 | session.SetConnectTimeSec(0, 0)
35 | }
36 |
37 | func (session *session) GetIndex() int32 {
38 | return session._index
39 | }
40 |
41 | func (session *session) GetNetworkUniqueID() uint64 {
42 | return atomic.LoadUint64(&session._networkUniqueID)
43 | }
44 |
45 | func (session *session) validNetworkUniqueID(uniqueId uint64) bool {
46 | return atomic.LoadUint64(&session._networkUniqueID) == uniqueId
47 | }
48 |
49 | func (session *session) GetNetworkInfo() (int32, uint64) {
50 | index := session.GetIndex()
51 | uniqueID := atomic.LoadUint64(&session._networkUniqueID)
52 | return index, uniqueID
53 | }
54 |
55 | func (session *session) setUserID(userID []byte) {
56 | session._userIDLength = int8(len(userID))
57 | copy(session._userID[:], userID)
58 | }
59 |
60 | func (session *session) getUserID() []byte {
61 | return session._userID[0:session._userIDLength]
62 | }
63 |
64 | func (session *session) getUserIDLength() int8 {
65 | return session._userIDLength
66 | }
67 |
68 | func (session *session) SetConnectTimeSec(timeSec int64, uniqueID uint64) {
69 | atomic.StoreInt64(&session._connectTimeSec, timeSec)
70 | atomic.StoreUint64(&session._networkUniqueID, uniqueID)
71 | }
72 |
73 | func (session *session) GetConnectTimeSec() int64 {
74 | return atomic.LoadInt64(&session._connectTimeSec)
75 | }
76 |
77 | func (session *session) SetUser(sessionUniqueId uint64,
78 | userID []byte,
79 | curTimeSec int64,
80 | ) {
81 | session.setUserID(userID)
82 | session.setRoomNumber(sessionUniqueId, -1, curTimeSec) // 방어적인 목적으로 채널 번호 초기화
83 | }
84 |
85 | func (session *session) IsAuth() bool {
86 | if session._userIDLength > 0 {
87 | return true
88 | }
89 |
90 | return false
91 | }
92 |
93 | func (session *session) setRoomEntering(roomNum int32) bool {
94 | if atomic.CompareAndSwapInt32(&session._RoomNumOfEntering, -1, roomNum) == false {
95 | return false
96 | }
97 |
98 | return true
99 | }
100 |
101 | func (session *session) setRoomNumber(sessionUniqueId uint64, roomNum int32, curTimeSec int64) bool {
102 | if roomNum == -1 {
103 | atomic.StoreInt32(&session._RoomNum, roomNum)
104 | atomic.StoreInt32(&session._RoomNumOfEntering, roomNum)
105 | return true
106 | }
107 |
108 | if sessionUniqueId != 0 && session.validNetworkUniqueID(sessionUniqueId) == false {
109 | return false
110 |
111 | }
112 | // 입력이 -1이 아닌경우 -1이 아닐 때만 compareswap으로 변경한다. 실패하면 채널 입장도 실패이다.
113 | if atomic.CompareAndSwapInt32(&session._RoomNum, -1, roomNum) == false {
114 | return false
115 | }
116 |
117 | atomic.StoreInt32(&session._RoomNumOfEntering, roomNum)
118 | return true
119 | }
120 |
121 | func (session *session) getRoomNumber() (int32, int32) {
122 | roomNum := atomic.LoadInt32(&session._RoomNum)
123 | roomNumOfEntering := atomic.LoadInt32(&session._RoomNum)
124 | return roomNum, roomNumOfEntering
125 | }
126 |
--------------------------------------------------------------------------------
/chatServer_msgpack/connectedSessions/sessionManager.go:
--------------------------------------------------------------------------------
1 | package connectedSessions
2 |
3 | import (
4 | "sync"
5 | "sync/atomic"
6 | "time"
7 | )
8 |
9 | // 스레드 세이프 해야 한다.
10 | type Manager struct {
11 | _UserIDsessionMap *sync.Map
12 |
13 | _maxSessionCount int32
14 | _sessionList []*session
15 |
16 | _maxUserCount int32
17 |
18 | _currentLoginUserCount int32
19 | }
20 |
21 | var _manager Manager
22 |
23 | func Init(maxSessionCount int, maxUserCount int32) bool {
24 | _manager._UserIDsessionMap = new(sync.Map)
25 | _manager._maxUserCount = maxUserCount
26 |
27 | _manager._maxSessionCount = int32(maxSessionCount)
28 | _manager._sessionList = make([]*session, maxSessionCount)
29 |
30 | for i := 0; i < maxSessionCount; i++ {
31 | _manager._sessionList[i] = new(session)
32 |
33 | index := int32(i)
34 | _manager._sessionList[i].Init(index)
35 | }
36 |
37 | return true
38 | }
39 |
40 | func AddSession(sessionIndex int32, sessionUniqueID uint64) bool {
41 | if _validSessionIndex(sessionIndex) == false {
42 | return false
43 | }
44 |
45 | if _manager._sessionList[sessionIndex].GetConnectTimeSec() > 0 {
46 | return false
47 | }
48 |
49 | // 방어적인 목적으로 한번 더 Clear 한다
50 | _manager._sessionList[sessionIndex].Clear()
51 |
52 | _manager._sessionList[sessionIndex].SetConnectTimeSec(time.Now().Unix(), sessionUniqueID)
53 | return true
54 | }
55 |
56 | func RemoveSession(sessionIndex int32, isLoginedUser bool) bool {
57 | if _validSessionIndex(sessionIndex) == false {
58 | return false
59 | }
60 |
61 | if isLoginedUser {
62 | atomic.AddInt32(&_manager._currentLoginUserCount, -1)
63 |
64 | userID := string(_manager._sessionList[sessionIndex].getUserID())
65 | _manager._UserIDsessionMap.Delete(userID)
66 | }
67 |
68 | _manager._sessionList[sessionIndex].Clear()
69 |
70 | return true
71 | }
72 |
73 | func _validSessionIndex(index int32) bool {
74 | if index < 0 || index >= _manager._maxSessionCount {
75 | return false
76 | }
77 | return true
78 | }
79 |
80 | func GetNetworkUniqueID(sessionIndex int32) uint64 {
81 | if _validSessionIndex(sessionIndex) == false {
82 | return 0
83 | }
84 |
85 | return _manager._sessionList[sessionIndex].GetNetworkUniqueID()
86 | }
87 |
88 | func GetUserID(sessionIndex int32) ([]byte, bool) {
89 | if _validSessionIndex(sessionIndex) == false {
90 | return nil, false
91 | }
92 |
93 | return _manager._sessionList[sessionIndex].getUserID(), true
94 | }
95 |
96 | func SetLogin(sessionIndex int32, sessionUniqueId uint64, userID []byte, curTimeSec int64) bool {
97 | if _validSessionIndex(sessionIndex) == false {
98 | return false
99 | }
100 |
101 | newUserID := string(userID)
102 | if _, ok := _manager._UserIDsessionMap.Load(newUserID); ok {
103 | return false
104 | }
105 |
106 | _manager._sessionList[sessionIndex].SetUser(sessionUniqueId, userID, curTimeSec)
107 | _manager._UserIDsessionMap.Store(newUserID, _manager._sessionList[sessionIndex])
108 |
109 | atomic.AddInt32(&_manager._currentLoginUserCount, 1)
110 | return true
111 | }
112 |
113 | func IsLoginUser(sessionIndex int32) bool {
114 | if _validSessionIndex(sessionIndex) == false {
115 | return false
116 | }
117 |
118 | return _manager._sessionList[sessionIndex].IsAuth()
119 | }
120 |
121 | func SetRoomNumber(sessionIndex int32, sessionUniqueId uint64, roomNum int32, curTimeSec int64) bool {
122 | if _validSessionIndex(sessionIndex) == false {
123 | return false
124 | }
125 |
126 | return _manager._sessionList[sessionIndex].setRoomNumber(sessionUniqueId, roomNum, curTimeSec)
127 | }
128 |
129 | func GetRoomNumber(sessionIndex int32) (int32, int32) {
130 | if _validSessionIndex(sessionIndex) == false {
131 | return -1, -1
132 | }
133 | return _manager._sessionList[sessionIndex].getRoomNumber()
134 | }
135 |
--------------------------------------------------------------------------------
/chatServer_msgpack/distributePacket.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "github.com/vmihailenco/msgpack/v4"
5 | "time"
6 |
7 | . "gohipernetFake"
8 |
9 | "main/connectedSessions"
10 | "main/protocol"
11 | )
12 |
13 | func (server *ChatServer) DistributePacket(sessionIndex int32,
14 | sessionUniqueId uint64,
15 | packetData []byte,
16 | ) {
17 | packetID := protocol.PeekPacketID(packetData)
18 | bodySize, bodyData := protocol.PeekPacketBody(packetData)
19 |
20 | packet := protocol.Packet{Id: packetID}
21 | packet.UserSessionIndex = sessionIndex
22 | packet.UserSessionUniqueId = sessionUniqueId
23 | packet.Id = packetID
24 | packet.DataSize = bodySize
25 | packet.Data = make([]byte, packet.DataSize)
26 | copy(packet.Data, bodyData)
27 |
28 | server.PacketChan <- packet
29 | }
30 |
31 |
32 | func (server *ChatServer) PacketProcess_goroutine() {
33 | for {
34 | if server.PacketProcess_goroutine_Impl() {
35 | OutPutLog(LOG_LEVEL_INFO,"", 0, "Wanted Stop PacketProcess goroutine")
36 | break
37 | }
38 | }
39 |
40 | OutPutLog(LOG_LEVEL_INFO,"", 0, "Stop rooms PacketProcess goroutine")
41 | }
42 |
43 | func (server *ChatServer) PacketProcess_goroutine_Impl() bool {
44 | IsWantedTermination := false // 여기에서는 의미 없음. 서버 종료를 명시적으로 하는 경우만 유용
45 | defer PrintPanicStack()
46 |
47 |
48 | for {
49 | packet := <-server.PacketChan
50 | sessionIndex := packet.UserSessionIndex
51 | sessionUniqueId := packet.UserSessionUniqueId
52 | bodySize := packet.DataSize
53 | bodyData := packet.Data
54 |
55 | if packet.Id == protocol.PACKET_ID_LOGIN_REQ {
56 | ProcessPacketLogin(sessionIndex, sessionUniqueId, bodySize, bodyData)
57 | } else if packet.Id == protocol.PACKET_ID_SESSION_CLOSE_SYS {
58 | ProcessPacketSessionClosed(server, sessionIndex, sessionUniqueId)
59 | } else {
60 | roomNumber, _ := connectedSessions.GetRoomNumber(sessionIndex)
61 | server.RoomMgr.PacketProcess(roomNumber, packet)
62 | }
63 | }
64 |
65 | return IsWantedTermination
66 | }
67 |
68 | func ProcessPacketLogin(sessionIndex int32,
69 | sessionUniqueId uint64,
70 | bodySize uint16,
71 | bodyData []byte ) {
72 | //DB와 연동하지 않으므로 중복 로그인만 아니면 다 성공으로 한다
73 | var request protocol.LoginReqPacket
74 | err := msgpack.Unmarshal(bodyData, &request)
75 | if err != nil {
76 | _sendLoginResult(sessionIndex, sessionUniqueId, protocol.ERROR_CODE_PACKET_DECODING_FAIL)
77 | return
78 | }
79 |
80 | userID := []byte(request.UserID)
81 | curTime := time.Now().Unix()
82 |
83 | if connectedSessions.SetLogin(sessionIndex, sessionUniqueId, userID, curTime) == false {
84 | _sendLoginResult(sessionIndex, sessionUniqueId, protocol.ERROR_CODE_LOGIN_USER_DUPLICATION)
85 | return
86 | }
87 |
88 | _sendLoginResult(sessionIndex, sessionUniqueId, protocol.ERROR_CODE_NONE)
89 | }
90 |
91 | func _sendLoginResult(sessionIndex int32, sessionUniqueId uint64, result int16) {
92 | var response protocol.LoginResPacket
93 | response.Result = int64(result)
94 |
95 | bodyData, err := msgpack.Marshal(response)
96 | if err != nil {
97 | panic(err)
98 | }
99 |
100 | sendPacket := protocol.EncodingPacketHeaderInfo(bodyData, uint16(protocol.PACKET_ID_LOGIN_RES), 0)
101 |
102 | NetLibIPostSendToClient(sessionIndex, sessionUniqueId, sendPacket)
103 | }
104 |
105 |
106 | func ProcessPacketSessionClosed(server *ChatServer, sessionIndex int32, sessionUniqueId uint64) {
107 | roomNumber, _ := connectedSessions.GetRoomNumber(sessionIndex)
108 |
109 | if roomNumber > -1 {
110 | packet := protocol.Packet{
111 | sessionIndex,
112 | sessionUniqueId,
113 | protocol.PACKET_ID_ROOM_LEAVE_REQ,
114 | 0,
115 | nil,
116 | }
117 |
118 | server.RoomMgr.PacketProcess(roomNumber, packet)
119 | }
120 |
121 | connectedSessions.RemoveSession(sessionIndex, true)
122 | }
123 |
124 |
125 |
--------------------------------------------------------------------------------
/chatServer_msgpack/go.mod:
--------------------------------------------------------------------------------
1 | module main
2 |
3 | go 1.13
4 |
5 | require (
6 | github.com/pkg/errors v0.8.1 // indirect
7 | github.com/stretchr/testify v1.4.0 // indirect
8 | github.com/vmihailenco/msgpack/v4 v4.2.1
9 | go.uber.org/atomic v1.4.0 // indirect
10 | go.uber.org/multierr v1.1.0 // indirect
11 | go.uber.org/zap v1.10.0
12 | gohipernetFake v0.0.0
13 | gopkg.in/yaml.v2 v2.2.7 // indirect
14 | )
15 |
16 | replace gohipernetFake v0.0.0 => ../gohipernetFake
17 |
--------------------------------------------------------------------------------
/chatServer_msgpack/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "flag"
5 | . "gohipernetFake"
6 | )
7 |
8 |
9 | func main() {
10 | netConfig, appConfig := parseAppConfig()
11 | netConfig.WriteNetworkConfig(true)
12 |
13 | // 아래 함수를 호출하면 강제적으로 종료 시킬 때까지 대기 상태가 된다.
14 | createAnsStartServer(netConfig, appConfig)
15 | }
16 |
17 | func parseAppConfig() (NetworkConfig, configAppServer) {
18 | appConfig := configAppServer {
19 | "chatServer",
20 | 1000,
21 | 0,
22 | 4,
23 | }
24 |
25 |
26 | netConfig := NetworkConfig{}
27 |
28 | flag.BoolVar(&netConfig.IsTcp4Addr,"c_IsTcp4Addr", true, "bool flag")
29 | flag.StringVar(&netConfig.BindAddress,"c_BindAddress", "127.0.0.1:11021", "string flag")
30 | flag.IntVar(&netConfig.MaxSessionCount,"c_MaxSessionCount", 0, "int flag")
31 | flag.IntVar(&netConfig.MaxPacketSize,"c_MaxPacketSize", 0, "int flag")
32 |
33 | flag.Parse()
34 | return netConfig, appConfig
35 | }
--------------------------------------------------------------------------------
/chatServer_msgpack/protocol/errorcode.go:
--------------------------------------------------------------------------------
1 | package protocol
2 |
3 | const (
4 | ERROR_CODE_NONE = 0
5 |
6 | ERROR_CODE_PACKET_DECODING_FAIL = 51
7 | ERROR_CODE_PACKET_ENCODING_FAIL = 52
8 | ERROR_CODE_PACKET_NOT_LOGIN_USER = 53
9 | ERROR_CODE_ROOM_NOT_REGISTED_PACKET_ID = 54
10 | ERROR_CODE_USER_NOT_IN_ROOM = 55
11 |
12 | ERROR_CODE_DISCONNECT_UNAUTHENTICATED_USER = 61
13 |
14 | ERROR_CODE_LOGIN_USER_DUPLICATION = 111
15 | ERROR_CODE_LOGIN_USER_INVALID_ID = 112
16 |
17 | ERROR_CODE_ROOM_NOT_IN_USER = 121
18 | ERROR_CODE_ROOM_INVALIDE_NUMBER = 122
19 |
20 | ERROR_CODE_ENTER_ROOM_ALREADY = 131
21 | ERROR_CODE_ENTER_ROOM_PREV_WORKING = 132
22 | ERROR_CODE_ENTER_ROOM_INVALID_USER_ID = 133
23 | ERROR_CODE_ENTER_ROOM_USER_FULL = 134
24 | ERROR_CODE_ENTER_ROOM_DUPLCATION_USER = 135
25 | ERROR_CODE_ENTER_ROOM_INVALID_SESSION_STATE = 136
26 | ERROR_CODE_ENTER_ROOM_AUTO_ROOM_NUMBER = 137
27 |
28 | ERROR_CODE_LEAVE_ROOM_INTERNAL_INVALID_USER = 141
29 |
30 | ERROR_CODE_ROOM_CHAT_CHAT_MSG_LEN = 151
31 |
32 | ERROR_CODE_ROOM_RELAY_FAIL_DECPDING = 161
33 |
34 | ERROR_CODE_ROOM_NOT_REGISTED_INTERNAL_PACKET_ID = 252 // 번역 필요없음
35 |
36 |
37 | )
38 |
--------------------------------------------------------------------------------
/chatServer_msgpack/protocol/packetID.go:
--------------------------------------------------------------------------------
1 | package protocol
2 |
3 |
4 | const (
5 | PACKET_ID_PING_REQ = 201
6 | PACKET_ID_PING_RES = 202
7 |
8 | PACKET_ID_ERROR_NTF = 203
9 |
10 | PACKET_ID_SESSION_CLOSE_SYS = 211
11 |
12 |
13 | PACKET_ID_LOGIN_REQ = 701
14 | PACKET_ID_LOGIN_RES = 702
15 |
16 | PACKET_ID_ROOM_ENTER_REQ = 721
17 | PACKET_ID_ROOM_ENTER_RES = 722
18 | PACKET_ID_ROOM_USER_LIST_NTF = 723
19 | PACKET_ID_ROOM_NEW_USER_NTF = 724
20 |
21 | PACKET_ID_ROOM_LEAVE_REQ = 726
22 | PACKET_ID_ROOM_LEAVE_RES = 727
23 | PACKET_ID_ROOM_LEAVE_USER_NTF = 728
24 |
25 | PACKET_ID_ROOM_CHAT_REQ = 731
26 | PACKET_ID_ROOM_CHAT_RES = 732
27 | PACKET_ID_ROOM_CHAT_NOTIFY = 733
28 |
29 | PACKET_ID_ROOM_RELAY_REQ = 741
30 | PACKET_ID_ROOM_RELAY_NTF = 742
31 |
32 |
33 | INTERNAL_PACKET_ID_DISCONNECTED_USER_TO_ROOM = 1602
34 | )
35 |
36 |
37 |
--------------------------------------------------------------------------------
/chatServer_msgpack/roomPkg/define.go:
--------------------------------------------------------------------------------
1 | package roomPkg
2 |
3 | import "main/protocol"
4 |
5 | type RoomConfig struct {
6 | StartRoomNumber int32
7 | MaxRoomCount int32
8 | MaxUserCount int32
9 | }
10 |
11 | type roomUser struct {
12 | netSessionIndex int32
13 | netSessionUniqueId uint64
14 |
15 | // <<< 다른 유저에게 알려줘야 하는 정보
16 | RoomUniqueId uint64
17 | IDLen int8
18 | ID [protocol.MAX_USER_ID_BYTE_LENGTH]byte
19 | // >>> 다른 유저에게 알려줘야 하는 정보
20 | packetDataSize int16 // 다른 유저에게 알려줘야 하는 정보 의 크기
21 | }
22 |
23 | func (user *roomUser) init(userID []byte, uniqueId uint64) {
24 | idlen := len(userID)
25 |
26 | user.IDLen = int8(idlen)
27 | copy(user.ID[:], userID)
28 |
29 | user.RoomUniqueId = uniqueId
30 | }
31 |
32 | func (user *roomUser) SetNetworkInfo(sessionIndex int32, sessionUniqueId uint64) {
33 | user.netSessionIndex = sessionIndex
34 | user.netSessionUniqueId = sessionUniqueId
35 | }
36 |
37 | func (user *roomUser) PacketDataSize() int16 {
38 | return int16(1) + int16(user.IDLen) + 8
39 | }
40 |
41 | type addRoomUserInfo struct {
42 | userID []byte
43 |
44 | netSessionIndex int32
45 | netSessionUniqueId uint64
46 | }
47 |
--------------------------------------------------------------------------------
/chatServer_msgpack/roomPkg/roomManager.go:
--------------------------------------------------------------------------------
1 | package roomPkg
2 |
3 | import (
4 | "github.com/vmihailenco/msgpack/v4"
5 |
6 | "main/protocol"
7 | )
8 |
9 | type RoomManager struct {
10 | _roomStartNum int32
11 | _maxRoomCount int32
12 | _roomCountList []int16
13 | _roomList []baseRoom
14 | }
15 |
16 | func NewRoomManager(config RoomConfig) *RoomManager {
17 | roomManager := new(RoomManager)
18 | roomManager._initialize(config)
19 | return roomManager
20 | }
21 |
22 | func (roomMgr *RoomManager) _initialize(config RoomConfig) {
23 | roomMgr._roomStartNum = config.StartRoomNumber
24 | roomMgr._maxRoomCount = config.MaxRoomCount
25 | roomMgr._roomCountList = make([]int16, config.MaxRoomCount)
26 | roomMgr._roomList = make([]baseRoom, config.MaxRoomCount)
27 |
28 | for i := int32(0); i < roomMgr._maxRoomCount; i++ {
29 | roomMgr._roomList[i].initialize(i, config)
30 | roomMgr._roomList[i].settingPacketFunction()
31 | }
32 | }
33 |
34 | func (roomMgr *RoomManager) GetAllChannelUserCount() []int16 {
35 | maxRoomCount := roomMgr._maxRoomCount
36 | for i := int32(0); i < maxRoomCount; i++ {
37 | roomMgr._roomCountList[i] = (int16)(roomMgr._getRoomUserCount(i))
38 | }
39 |
40 | return roomMgr._roomCountList
41 | }
42 |
43 | func (roomMgr *RoomManager) getRoomByNumber(roomNumber int32) *baseRoom {
44 | roomIndex := roomNumber - roomMgr._roomStartNum
45 |
46 | if roomNumber < 0 || roomIndex >= roomMgr._maxRoomCount {
47 | return nil
48 | }
49 |
50 | return &roomMgr._roomList[roomIndex]
51 | }
52 |
53 | // 이 함수를 호출할 때의 채널 인덱스는 꼭 호출자가 유효범위인 것을 보증해야 한다.
54 | func (roomMgr *RoomManager) _getRoomUserCount(roomId int32) int32 {
55 | return roomMgr._roomList[roomId].getCurUserCount()
56 | }
57 |
58 | func (roomMgr *RoomManager) PacketProcess(roomNumber int32, packet protocol.Packet) {
59 | isRoomEnterReq := false
60 |
61 | if roomNumber == -1 && packet.Id == protocol.PACKET_ID_ROOM_ENTER_REQ {
62 | isRoomEnterReq = true
63 |
64 | var requestPacket protocol.RoomEnterReqPacket
65 | err := msgpack.Unmarshal(packet.Data, &requestPacket)
66 | if err != nil {
67 | return
68 | }
69 |
70 | roomNumber = int32(requestPacket.RoomNumber)
71 | }
72 |
73 | room := roomMgr.getRoomByNumber(roomNumber)
74 | if room == nil {
75 | protocol.NotifyErrorPacket(packet.UserSessionIndex, packet.UserSessionUniqueId,
76 | protocol.ERROR_CODE_ROOM_INVALIDE_NUMBER)
77 | return
78 | }
79 |
80 | user := room.getUser(packet.UserSessionUniqueId)
81 | if user == nil && isRoomEnterReq == false {
82 | protocol.NotifyErrorPacket(packet.UserSessionIndex, packet.UserSessionUniqueId,
83 | protocol.ERROR_CODE_ROOM_NOT_IN_USER)
84 | return
85 | }
86 |
87 | funcCount := len(room._funcPackeIdlist)
88 | for i := 0; i < funcCount; i++ {
89 | if room._funcPackeIdlist[i] != packet.Id {
90 | continue
91 | }
92 |
93 | room._funclist[i](user, packet)
94 | return
95 | }
96 | }
97 |
98 |
--------------------------------------------------------------------------------
/chatServer_msgpack/roomPkg/room_Packet.go:
--------------------------------------------------------------------------------
1 | package roomPkg
2 |
3 | import (
4 | "main/protocol"
5 | )
6 |
7 | func (room *baseRoom) _packetProcess_Relay(user *roomUser, packet protocol.Packet) int16 {
8 | /*var relayNotify protocol.RoomRelayNtfPacket
9 | relayNotify.RoomUserUniqueId = user.RoomUniqueId
10 | relayNotify.Data = packet.Data
11 | notifySendBuf, packetSize := relayNotify.EncodingPacket(packet.DataSize)
12 | room.broadcastPacket(packetSize, notifySendBuf, 0)
13 |
14 | NTELIB_LOG_DEBUG("Room Relay", zap.String("Sender", string(user.ID[:])))*/
15 | return protocol.ERROR_CODE_NONE
16 | }
17 |
--------------------------------------------------------------------------------
/chatServer_msgpack/roomPkg/room_PacketChat.go:
--------------------------------------------------------------------------------
1 | package roomPkg
2 |
3 | import (
4 | "github.com/vmihailenco/msgpack/v4"
5 | . "gohipernetFake"
6 |
7 | "main/protocol"
8 | )
9 |
10 | func (room *baseRoom) _packetProcess_Chat(user *roomUser, packet protocol.Packet) int16 {
11 | sessionIndex := packet.UserSessionIndex
12 | sessionUniqueId := packet.UserSessionUniqueId
13 |
14 | var chatPacket protocol.RoomChatReqPacket
15 | err := msgpack.Unmarshal(packet.Data, &chatPacket)
16 | if err != nil {
17 | _sendRoomChatResult(sessionIndex, sessionUniqueId, protocol.ERROR_CODE_PACKET_DECODING_FAIL)
18 | return protocol.ERROR_CODE_PACKET_DECODING_FAIL
19 | }
20 |
21 | var chatNotifyResponse protocol.RoomChatNtfPacket
22 | chatNotifyResponse.UserUniqueId = user.RoomUniqueId
23 | chatNotifyResponse.Msg = chatPacket.Msg
24 | bodyData, err := msgpack.Marshal(chatNotifyResponse)
25 | if err != nil {
26 | return protocol.ERROR_CODE_PACKET_ENCODING_FAIL
27 | }
28 |
29 | notifySendBuf := protocol.EncodingPacketHeaderInfo(bodyData, uint16(protocol.PACKET_ID_ROOM_CHAT_NOTIFY), 0)
30 | packetSize := uint16(len(notifySendBuf))
31 | room.broadcastPacket(packetSize, notifySendBuf, 0)
32 |
33 | _sendRoomChatResult(sessionIndex, sessionUniqueId, protocol.ERROR_CODE_NONE)
34 |
35 | return protocol.ERROR_CODE_NONE
36 | }
37 |
38 | func _sendRoomChatResult(sessionIndex int32, sessionUniqueId uint64, result int16) {
39 | response := protocol.RoomChatResPacket{int64(result)}
40 | bodyData, err := msgpack.Marshal(response)
41 | if err != nil {
42 | panic(err)
43 | }
44 |
45 | sendPacket := protocol.EncodingPacketHeaderInfo(bodyData, uint16(protocol.PACKET_ID_ROOM_CHAT_RES), 0)
46 |
47 | NetLibIPostSendToClient(sessionIndex, sessionUniqueId, sendPacket)
48 | }
49 |
--------------------------------------------------------------------------------
/chatServer_msgpack/roomPkg/room_PacketEnter.go:
--------------------------------------------------------------------------------
1 | package roomPkg
2 |
3 | import (
4 | "github.com/vmihailenco/msgpack/v4"
5 | "time"
6 |
7 | . "gohipernetFake"
8 |
9 | "main/connectedSessions"
10 | "main/protocol"
11 | )
12 |
13 | func (room *baseRoom) _packetProcess_EnterUser(inValidUser *roomUser, packet protocol.Packet) int16 {
14 | curTime := time.Now().Unix()
15 | sessionIndex := packet.UserSessionIndex
16 | sessionUniqueId := packet.UserSessionUniqueId
17 |
18 | var requestPacket protocol.RoomEnterReqPacket
19 | err := msgpack.Unmarshal(packet.Data, &requestPacket)
20 | if err != nil {
21 | return protocol.ERROR_CODE_PACKET_DECODING_FAIL
22 | }
23 |
24 | userID, ok := connectedSessions.GetUserID(sessionIndex)
25 | if ok == false {
26 | _sendRoomEnterResult(sessionIndex, sessionUniqueId, 0, protocol.ERROR_CODE_ENTER_ROOM_INVALID_USER_ID)
27 | return protocol.ERROR_CODE_ENTER_ROOM_INVALID_USER_ID
28 | }
29 |
30 | userInfo := addRoomUserInfo{
31 | userID,
32 | sessionIndex,
33 | sessionUniqueId,
34 | }
35 | newUser, addResult := room.addUser(userInfo)
36 |
37 | if addResult != protocol.ERROR_CODE_NONE {
38 | _sendRoomEnterResult(sessionIndex, sessionUniqueId, 0, addResult)
39 | return addResult
40 | }
41 |
42 | if connectedSessions.SetRoomNumber(sessionIndex, sessionUniqueId, room.getNumber(), curTime) == false {
43 | _sendRoomEnterResult(sessionIndex, sessionUniqueId, 0, protocol.ERROR_CODE_ENTER_ROOM_INVALID_SESSION_STATE)
44 | return protocol.ERROR_CODE_ENTER_ROOM_INVALID_SESSION_STATE
45 | }
46 |
47 | if room.getCurUserCount() > 1 {
48 | //룸의 다른 유저에게 통보한다.
49 | room._sendNewUserInfoPacket(newUser)
50 |
51 | // 지금 들어온 유저에게 이미 채널에 있는 유저들의 정보를 보낸다
52 | room._sendUserInfoListPacket(newUser)
53 | }
54 |
55 | _sendRoomEnterResult(sessionIndex, sessionUniqueId, newUser.RoomUniqueId, protocol.ERROR_CODE_NONE)
56 | return protocol.ERROR_CODE_NONE
57 | }
58 |
59 | func _sendRoomEnterResult(sessionIndex int32, sessionUniqueId uint64, userUniqueId uint64, result int16) {
60 | response := protocol.RoomEnterResPacket{
61 | int64(result),
62 | userUniqueId,
63 | }
64 |
65 | bodyData, err := msgpack.Marshal(response)
66 | if err != nil {
67 | return
68 | }
69 |
70 | sendPacket := protocol.EncodingPacketHeaderInfo(bodyData, uint16(protocol.PACKET_ID_ROOM_ENTER_RES), 0)
71 | NetLibIPostSendToClient(sessionIndex, sessionUniqueId, sendPacket)
72 | }
73 |
74 | func (room *baseRoom) _sendUserInfoListPacket(user *roomUser) {
75 | userCount, uniqueIdList, idList := room.allocAllUserInfo(user.netSessionUniqueId)
76 |
77 | var response protocol.RoomUserListNtfPacket
78 | response.UserCount = int64(userCount)
79 | response.UniqueId = uniqueIdList
80 | response.ID = idList
81 | /*response.UniqueId = make([]uint64, 0, 0)
82 | response.ID = make([]string, 0, 0)
83 | for i := 0; i < 2; i++ {
84 | response.UniqueId = append(response.UniqueId, 1)
85 | response.ID = append(response.ID, "test1")
86 | }*/
87 |
88 | bodyData, err := msgpack.Marshal(response)
89 | if err != nil {
90 | return
91 | }
92 | sendPacket := protocol.EncodingPacketHeaderInfo(bodyData, uint16(protocol.PACKET_ID_ROOM_USER_LIST_NTF), 0)
93 |
94 | NetLibIPostSendToClient(user.netSessionIndex, user.netSessionUniqueId, sendPacket)
95 | }
96 |
97 | func (room *baseRoom) _sendNewUserInfoPacket(user *roomUser) {
98 | var response protocol.RoomNewUserNtfPacket
99 | response.ID = string(user.ID[0:user.IDLen])
100 | response.UniqueId = user.RoomUniqueId
101 |
102 | bodyData, err := msgpack.Marshal(response)
103 | if err != nil {
104 | panic(err)
105 | }
106 |
107 | sendPacket := protocol.EncodingPacketHeaderInfo(bodyData, uint16(protocol.PACKET_ID_ROOM_NEW_USER_NTF), 0)
108 | packetSize := uint16(len(sendPacket))
109 | room.broadcastPacket(packetSize, sendPacket, user.netSessionUniqueId) // 자신을 제외하고 모든 유저에게 Send
110 | }
111 |
--------------------------------------------------------------------------------
/chatServer_msgpack/roomPkg/room_PacketLeave.go:
--------------------------------------------------------------------------------
1 | package roomPkg
2 |
3 | import (
4 | "github.com/vmihailenco/msgpack/v4"
5 | "time"
6 |
7 | . "gohipernetFake"
8 |
9 | "main/connectedSessions"
10 | "main/protocol"
11 | )
12 |
13 | func (room *baseRoom) _packetProcess_LeaveUser(user *roomUser, packet protocol.Packet) int16 {
14 | room._leaveUserProcess(user)
15 |
16 | sessionIndex := packet.UserSessionIndex
17 | sessionUniqueId := packet.UserSessionUniqueId
18 | _sendRoomLeaveResult(sessionIndex, sessionUniqueId, protocol.ERROR_CODE_NONE)
19 | return protocol.ERROR_CODE_NONE
20 | }
21 |
22 | func (room *baseRoom) _leaveUserProcess(user *roomUser) {
23 | roomUserUniqueId := user.RoomUniqueId
24 | userSessionIndex := user.netSessionIndex
25 | userSessionUniqueId := user.netSessionUniqueId
26 |
27 | room._removeUser(user)
28 |
29 | room._sendRoomLeaveUserNotify(roomUserUniqueId, userSessionUniqueId)
30 |
31 | curTime := time.Now().Unix()
32 | connectedSessions.SetRoomNumber(userSessionIndex, userSessionUniqueId, -1, curTime)
33 | }
34 |
35 | func _sendRoomLeaveResult(sessionIndex int32, sessionUniqueId uint64, result int16) {
36 | response := protocol.RoomLeaveResPacket{int64(result)}
37 | bodyData, err := msgpack.Marshal(response)
38 | if err != nil {
39 | panic(err)
40 | }
41 |
42 | sendPacket := protocol.EncodingPacketHeaderInfo(bodyData, uint16(protocol.PACKET_ID_ROOM_LEAVE_RES), 0)
43 | NetLibIPostSendToClient(sessionIndex, sessionUniqueId, sendPacket)
44 | }
45 |
46 | func (room *baseRoom) _sendRoomLeaveUserNotify(roomUserUniqueId uint64, userSessionUniqueId uint64) {
47 | notifyPacket := protocol.RoomLeaveUserNtfPacket{roomUserUniqueId}
48 |
49 | bodyData, err := msgpack.Marshal(notifyPacket)
50 | if err != nil {
51 | return
52 | }
53 |
54 | sendPacket := protocol.EncodingPacketHeaderInfo(bodyData, uint16(protocol.PACKET_ID_ROOM_LEAVE_USER_NTF), 0)
55 | packetSize := uint16(len(sendPacket))
56 |
57 | room.broadcastPacket(packetSize, sendPacket, userSessionUniqueId)
58 | }
59 |
--------------------------------------------------------------------------------
/csharp_test_client/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/csharp_test_client/ClientSimpleTcp.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Net.Sockets;
3 | using System.Net;
4 |
5 | namespace csharp_test_client
6 | {
7 | public class ClientSimpleTcp
8 | {
9 | public Socket Sock = null;
10 | public string LatestErrorMsg;
11 |
12 |
13 | //소켓연결
14 | public bool Connect(string ip, int port)
15 | {
16 | try
17 | {
18 | IPAddress serverIP = IPAddress.Parse(ip);
19 | int serverPort = port;
20 |
21 | Sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
22 | Sock.Connect(new IPEndPoint(serverIP, serverPort));
23 |
24 | if (Sock == null || Sock.Connected == false)
25 | {
26 | return false;
27 | }
28 |
29 | return true;
30 | }
31 | catch (Exception ex)
32 | {
33 | LatestErrorMsg = ex.Message;
34 | return false;
35 | }
36 | }
37 |
38 | public Tuple Receive()
39 | {
40 |
41 | try
42 | {
43 | byte[] ReadBuffer = new byte[2048];
44 | var nRecv = Sock.Receive(ReadBuffer, 0, ReadBuffer.Length, SocketFlags.None);
45 |
46 | if (nRecv == 0)
47 | {
48 | return null;
49 | }
50 |
51 | return Tuple.Create(nRecv,ReadBuffer);
52 | }
53 | catch (SocketException se)
54 | {
55 | LatestErrorMsg = se.Message;
56 | }
57 |
58 | return null;
59 | }
60 |
61 | //스트림에 쓰기
62 | public void Send(byte[] sendData)
63 | {
64 | try
65 | {
66 | if (Sock != null && Sock.Connected) //연결상태 유무 확인
67 | {
68 | Sock.Send(sendData, 0, sendData.Length, SocketFlags.None);
69 | }
70 | else
71 | {
72 | LatestErrorMsg = "먼저 채팅서버에 접속하세요!";
73 | }
74 | }
75 | catch (SocketException se)
76 | {
77 | LatestErrorMsg = se.Message;
78 | }
79 | }
80 |
81 | //소켓과 스트림 닫기
82 | public void Close()
83 | {
84 | if (Sock != null && Sock.Connected)
85 | {
86 | //Sock.Shutdown(SocketShutdown.Both);
87 | Sock.Close();
88 | }
89 | }
90 |
91 | public bool IsConnected() { return (Sock != null && Sock.Connected) ? true : false; }
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/csharp_test_client/DevLog.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | using System.Runtime.CompilerServices;
8 | using System.Threading;
9 |
10 | namespace csharp_test_client
11 | {
12 | public class DevLog
13 | {
14 | static System.Collections.Concurrent.ConcurrentQueue logMsgQueue = new System.Collections.Concurrent.ConcurrentQueue();
15 |
16 | static Int64 출력가능_로그레벨 = (Int64)LOG_LEVEL.TRACE;
17 |
18 |
19 |
20 | static public void Init(LOG_LEVEL logLevel)
21 | {
22 | ChangeLogLevel(logLevel);
23 | }
24 |
25 | static public void ChangeLogLevel(LOG_LEVEL logLevel)
26 | {
27 | Interlocked.Exchange(ref 출력가능_로그레벨, (int)logLevel);
28 | }
29 |
30 | public static LOG_LEVEL CurrentLogLevel()
31 | {
32 | var curLogLevel = (LOG_LEVEL)Interlocked.Read(ref 출력가능_로그레벨);
33 | return curLogLevel;
34 | }
35 |
36 | static public void Write(string msg, LOG_LEVEL logLevel = LOG_LEVEL.TRACE,
37 | [CallerFilePath] string fileName = "",
38 | [CallerMemberName] string methodName = "",
39 | [CallerLineNumber] int lineNumber = 0)
40 | {
41 | if (CurrentLogLevel() <= logLevel)
42 | {
43 | logMsgQueue.Enqueue(string.Format("{0}:{1}| {2}", DateTime.Now, methodName, msg));
44 | }
45 | }
46 |
47 | static public bool GetLog(out string msg)
48 | {
49 | if (logMsgQueue.TryDequeue(out msg))
50 | {
51 | return true;
52 | }
53 |
54 | return false;
55 | }
56 |
57 | }
58 |
59 |
60 | public enum LOG_LEVEL
61 | {
62 | TRACE,
63 | DEBUG,
64 | INFO,
65 | WARN,
66 | ERROR,
67 | DISABLE
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/csharp_test_client/PacketBufferManager.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace csharp_test_client
8 | {
9 | class PacketBufferManager
10 | {
11 | int BufferSize = 0;
12 | int ReadPos = 0;
13 | int WritePos = 0;
14 |
15 | int HeaderSize = 0;
16 | int MaxPacketSize = 0;
17 | byte[] PacketData;
18 | byte[] PacketDataTemp;
19 |
20 | public bool Init(int size, int headerSize, int maxPacketSize)
21 | {
22 | if (size < (maxPacketSize * 2) || size < 1 || headerSize < 1 || maxPacketSize < 1)
23 | {
24 | return false;
25 | }
26 |
27 | BufferSize = size;
28 | PacketData = new byte[size];
29 | PacketDataTemp = new byte[size];
30 | HeaderSize = headerSize;
31 | MaxPacketSize = maxPacketSize;
32 |
33 | return true;
34 | }
35 |
36 | public bool Write(byte[] data, int pos, int size)
37 | {
38 | if (data == null || (data.Length < (pos + size)))
39 | {
40 | return false;
41 | }
42 |
43 | var remainBufferSize = BufferSize - WritePos;
44 |
45 | if (remainBufferSize < size)
46 | {
47 | return false;
48 | }
49 |
50 | Buffer.BlockCopy(data, pos, PacketData, WritePos, size);
51 | WritePos += size;
52 |
53 | if (NextFree() == false)
54 | {
55 | BufferRelocate();
56 | }
57 | return true;
58 | }
59 |
60 | public ArraySegment Read()
61 | {
62 | var enableReadSize = WritePos - ReadPos;
63 |
64 | if (enableReadSize < HeaderSize)
65 | {
66 | return new ArraySegment();
67 | }
68 |
69 | var packetDataSize = BitConverter.ToInt16(PacketData, ReadPos);
70 | if (enableReadSize < packetDataSize)
71 | {
72 | return new ArraySegment();
73 | }
74 |
75 | var completePacketData = new ArraySegment(PacketData, ReadPos, packetDataSize);
76 | ReadPos += packetDataSize;
77 | return completePacketData;
78 | }
79 |
80 | bool NextFree()
81 | {
82 | var enableWriteSize = BufferSize - WritePos;
83 |
84 | if (enableWriteSize < MaxPacketSize)
85 | {
86 | return false;
87 | }
88 |
89 | return true;
90 | }
91 |
92 | void BufferRelocate()
93 | {
94 | var enableReadSize = WritePos - ReadPos;
95 |
96 | Buffer.BlockCopy(PacketData, ReadPos, PacketDataTemp, 0, enableReadSize);
97 | Buffer.BlockCopy(PacketDataTemp, 0, PacketData, 0, enableReadSize);
98 |
99 | ReadPos = 0;
100 | WritePos = enableReadSize;
101 | }
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/csharp_test_client/PacketDefine.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace csharp_test_client
8 | {
9 | class PacketDef
10 | {
11 | public const Int16 PACKET_HEADER_SIZE = 5;
12 | public const int MAX_USER_ID_BYTE_LENGTH = 16;
13 | public const int MAX_USER_PW_BYTE_LENGTH = 16;
14 | }
15 |
16 | public enum PACKET_ID : ushort
17 | {
18 | PACKET_ID_ECHO = 101,
19 |
20 | // Ping(Heart-beat)
21 | PACKET_ID_PING_REQ = 201,
22 | PACKET_ID_PING_RES = 202,
23 |
24 | PACKET_ID_ERROR_NTF = 203,
25 |
26 |
27 | // 로그인
28 | PACKET_ID_LOGIN_REQ = 701,
29 | PACKET_ID_LOGIN_RES = 702,
30 |
31 |
32 | PACKET_ID_ROOM_ENTER_REQ = 721,
33 | PACKET_ID_ROOM_ENTER_RES = 722,
34 | PACKET_ID_ROOM_USER_LIST_NTF = 723,
35 | PACKET_ID_ROOM_NEW_USER_NTF = 724,
36 |
37 | PACKET_ID_ROOM_LEAVE_REQ = 726,
38 | PACKET_ID_ROOM_LEAVE_RES = 727,
39 | PACKET_ID_ROOM_LEAVE_USER_NTF = 728,
40 |
41 | PACKET_ID_ROOM_CHAT_REQ = 731,
42 | PACKET_ID_ROOM_CHAT_RES = 732,
43 | PACKET_ID_ROOM_CHAT_NOTIFY = 733,
44 |
45 | PACKET_ID_ROOM_RELAY_REQ = 741,
46 | PACKET_ID_ROOM_RELAY_NTF = 742,
47 | }
48 |
49 |
50 | public enum ERROR_CODE : Int16
51 | {
52 | ERROR_NONE = 0,
53 |
54 |
55 |
56 | ERROR_CODE_USER_MGR_INVALID_USER_UNIQUEID = 112,
57 |
58 | ERROR_CODE_PUBLIC_CHANNEL_IN_USER = 114,
59 |
60 | ERROR_CODE_PUBLIC_CHANNEL_INVALIDE_NUMBER = 115,
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/csharp_test_client/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Runtime.Versioning;
5 | using System.Threading.Tasks;
6 | using System.Windows.Forms;
7 |
8 | namespace csharp_test_client
9 | {
10 | [SupportedOSPlatform("windows10.0.177630")]
11 | static class Program
12 | {
13 | ///
14 | /// 해당 응용 프로그램의 주 진입점입니다.
15 | ///
16 | [STAThread]
17 | static void Main()
18 | {
19 | Application.EnableVisualStyles();
20 | Application.SetCompatibleTextRenderingDefault(false);
21 | Application.Run(new mainForm());
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/csharp_test_client/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // 어셈블리에 대한 일반 정보는 다음 특성 집합을 통해
6 | // 제어됩니다. 어셈블리와 관련된 정보를 수정하려면
7 | // 이러한 특성 값을 변경하세요.
8 | [assembly: AssemblyTitle("csharp_test_client")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("csharp_test_client")]
13 | [assembly: AssemblyCopyright("Copyright © 2016")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // ComVisible을 false로 설정하면 이 어셈블리의 형식이 COM 구성 요소에
18 | // 표시되지 않습니다. COM에서 이 어셈블리의 형식에 액세스하려면
19 | // 해당 형식에 대해 ComVisible 특성을 true로 설정하세요.
20 | [assembly: ComVisible(false)]
21 |
22 | // 이 프로젝트가 COM에 노출되는 경우 다음 GUID는 typelib의 ID를 나타냅니다.
23 | [assembly: Guid("9e4b5e72-4e76-4e22-90b0-e53275a99018")]
24 |
25 | // 어셈블리의 버전 정보는 다음 네 가지 값으로 구성됩니다.
26 | //
27 | // 주 버전
28 | // 부 버전
29 | // 빌드 번호
30 | // 수정 버전
31 | //
32 | // 모든 값을 지정하거나 아래와 같이 '*'를 사용하여 빌드 번호 및 수정 번호가 자동으로
33 | // 지정되도록 할 수 있습니다.
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/csharp_test_client/Properties/Resources.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // 이 코드는 도구를 사용하여 생성되었습니다.
4 | // 런타임 버전:4.0.30319.42000
5 | //
6 | // 파일 내용을 변경하면 잘못된 동작이 발생할 수 있으며, 코드를 다시 생성하면
7 | // 이러한 변경 내용이 손실됩니다.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace csharp_test_client.Properties
12 | {
13 |
14 |
15 | ///
16 | /// 지역화된 문자열 등을 찾기 위한 강력한 형식의 리소스 클래스입니다.
17 | ///
18 | // 이 클래스는 ResGen 또는 Visual Studio와 같은 도구를 통해 StronglyTypedResourceBuilder
19 | // 클래스에서 자동으로 생성되었습니다.
20 | // 멤버를 추가하거나 제거하려면 .ResX 파일을 편집한 다음 /str 옵션을 사용하여
21 | // ResGen을 다시 실행하거나 VS 프로젝트를 다시 빌드하십시오.
22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
25 | internal class Resources
26 | {
27 |
28 | private static global::System.Resources.ResourceManager resourceMan;
29 |
30 | private static global::System.Globalization.CultureInfo resourceCulture;
31 |
32 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
33 | internal Resources()
34 | {
35 | }
36 |
37 | ///
38 | /// 이 클래스에서 사용하는 캐시된 ResourceManager 인스턴스를 반환합니다.
39 | ///
40 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
41 | internal static global::System.Resources.ResourceManager ResourceManager
42 | {
43 | get
44 | {
45 | if ((resourceMan == null))
46 | {
47 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("csharp_test_client.Properties.Resources", typeof(Resources).Assembly);
48 | resourceMan = temp;
49 | }
50 | return resourceMan;
51 | }
52 | }
53 |
54 | ///
55 | /// 이 강력한 형식의 리소스 클래스를 사용하여 모든 리소스 조회에 대해
56 | /// 현재 스레드의 CurrentUICulture 속성을 재정의합니다.
57 | ///
58 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
59 | internal static global::System.Globalization.CultureInfo Culture
60 | {
61 | get
62 | {
63 | return resourceCulture;
64 | }
65 | set
66 | {
67 | resourceCulture = value;
68 | }
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/csharp_test_client/Properties/Settings.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.42000
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace csharp_test_client.Properties
12 | {
13 |
14 |
15 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
16 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
17 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
18 | {
19 |
20 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
21 |
22 | public static Settings Default
23 | {
24 | get
25 | {
26 | return defaultInstance;
27 | }
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/csharp_test_client/Properties/Settings.settings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/csharp_test_client/csharp_test_client.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | net8.0-windows10.0.17763.0
4 | WinExe
5 | false
6 | true
7 | true
8 |
9 |
10 | ..\bin\
11 |
12 |
13 |
14 |
15 |
16 | all
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/csharp_test_client/csharp_test_client.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 14
4 | VisualStudioVersion = 14.0.25420.1
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "csharp_test_client", "csharp_test_client.csproj", "{9E4B5E72-4E76-4E22-90B0-E53275A99018}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Any CPU = Debug|Any CPU
11 | Release|Any CPU = Release|Any CPU
12 | EndGlobalSection
13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
14 | {9E4B5E72-4E76-4E22-90B0-E53275A99018}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15 | {9E4B5E72-4E76-4E22-90B0-E53275A99018}.Debug|Any CPU.Build.0 = Debug|Any CPU
16 | {9E4B5E72-4E76-4E22-90B0-E53275A99018}.Release|Any CPU.ActiveCfg = Release|Any CPU
17 | {9E4B5E72-4E76-4E22-90B0-E53275A99018}.Release|Any CPU.Build.0 = Release|Any CPU
18 | EndGlobalSection
19 | GlobalSection(SolutionProperties) = preSolution
20 | HideSolutionNode = FALSE
21 | EndGlobalSection
22 | EndGlobal
23 |
--------------------------------------------------------------------------------
/csharp_test_client_msgpack/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/csharp_test_client_msgpack/ClientSimpleTcp.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Net.Sockets;
3 | using System.Net;
4 |
5 | namespace csharp_test_client
6 | {
7 | public class ClientSimpleTcp
8 | {
9 | public Socket Sock = null;
10 | public string LatestErrorMsg;
11 |
12 |
13 | //소켓연결
14 | public bool Connect(string ip, int port)
15 | {
16 | try
17 | {
18 | IPAddress serverIP = IPAddress.Parse(ip);
19 | int serverPort = port;
20 |
21 | Sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
22 | Sock.Connect(new IPEndPoint(serverIP, serverPort));
23 |
24 | if (Sock == null || Sock.Connected == false)
25 | {
26 | return false;
27 | }
28 |
29 | return true;
30 | }
31 | catch (Exception ex)
32 | {
33 | LatestErrorMsg = ex.Message;
34 | return false;
35 | }
36 | }
37 |
38 | public Tuple Receive()
39 | {
40 |
41 | try
42 | {
43 | byte[] ReadBuffer = new byte[2048];
44 | var nRecv = Sock.Receive(ReadBuffer, 0, ReadBuffer.Length, SocketFlags.None);
45 |
46 | if (nRecv == 0)
47 | {
48 | return null;
49 | }
50 |
51 | return Tuple.Create(nRecv,ReadBuffer);
52 | }
53 | catch (SocketException se)
54 | {
55 | LatestErrorMsg = se.Message;
56 | }
57 |
58 | return null;
59 | }
60 |
61 | //스트림에 쓰기
62 | public void Send(byte[] sendData)
63 | {
64 | try
65 | {
66 | if (Sock != null && Sock.Connected) //연결상태 유무 확인
67 | {
68 | Sock.Send(sendData, 0, sendData.Length, SocketFlags.None);
69 | }
70 | else
71 | {
72 | LatestErrorMsg = "먼저 채팅서버에 접속하세요!";
73 | }
74 | }
75 | catch (SocketException se)
76 | {
77 | LatestErrorMsg = se.Message;
78 | }
79 | }
80 |
81 | //소켓과 스트림 닫기
82 | public void Close()
83 | {
84 | if (Sock != null && Sock.Connected)
85 | {
86 | //Sock.Shutdown(SocketShutdown.Both);
87 | Sock.Close();
88 | }
89 | }
90 |
91 | public bool IsConnected() { return (Sock != null && Sock.Connected) ? true : false; }
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/csharp_test_client_msgpack/DevLog.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | using System.Runtime.CompilerServices;
8 | using System.Threading;
9 |
10 | namespace csharp_test_client
11 | {
12 | public class DevLog
13 | {
14 | static System.Collections.Concurrent.ConcurrentQueue logMsgQueue = new System.Collections.Concurrent.ConcurrentQueue();
15 |
16 | static Int64 출력가능_로그레벨 = (Int64)LOG_LEVEL.TRACE;
17 |
18 |
19 |
20 | static public void Init(LOG_LEVEL logLevel)
21 | {
22 | ChangeLogLevel(logLevel);
23 | }
24 |
25 | static public void ChangeLogLevel(LOG_LEVEL logLevel)
26 | {
27 | Interlocked.Exchange(ref 출력가능_로그레벨, (int)logLevel);
28 | }
29 |
30 | public static LOG_LEVEL CurrentLogLevel()
31 | {
32 | var curLogLevel = (LOG_LEVEL)Interlocked.Read(ref 출력가능_로그레벨);
33 | return curLogLevel;
34 | }
35 |
36 | static public void Write(string msg, LOG_LEVEL logLevel = LOG_LEVEL.TRACE,
37 | [CallerFilePath] string fileName = "",
38 | [CallerMemberName] string methodName = "",
39 | [CallerLineNumber] int lineNumber = 0)
40 | {
41 | if (CurrentLogLevel() <= logLevel)
42 | {
43 | logMsgQueue.Enqueue(string.Format("{0}:{1}| {2}", DateTime.Now, methodName, msg));
44 | }
45 | }
46 |
47 | static public bool GetLog(out string msg)
48 | {
49 | if (logMsgQueue.TryDequeue(out msg))
50 | {
51 | return true;
52 | }
53 |
54 | return false;
55 | }
56 |
57 | }
58 |
59 |
60 | public enum LOG_LEVEL
61 | {
62 | TRACE,
63 | DEBUG,
64 | INFO,
65 | WARN,
66 | ERROR,
67 | DISABLE
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/csharp_test_client_msgpack/PacketBufferManager.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace csharp_test_client
8 | {
9 | class PacketBufferManager
10 | {
11 | int BufferSize = 0;
12 | int ReadPos = 0;
13 | int WritePos = 0;
14 |
15 | int HeaderSize = 0;
16 | int MaxPacketSize = 0;
17 | byte[] PacketData;
18 | byte[] PacketDataTemp;
19 |
20 | public bool Init(int size, int headerSize, int maxPacketSize)
21 | {
22 | if (size < (maxPacketSize * 2) || size < 1 || headerSize < 1 || maxPacketSize < 1)
23 | {
24 | return false;
25 | }
26 |
27 | BufferSize = size;
28 | PacketData = new byte[size];
29 | PacketDataTemp = new byte[size];
30 | HeaderSize = headerSize;
31 | MaxPacketSize = maxPacketSize;
32 |
33 | return true;
34 | }
35 |
36 | public bool Write(byte[] data, int pos, int size)
37 | {
38 | if (data == null || (data.Length < (pos + size)))
39 | {
40 | return false;
41 | }
42 |
43 | var remainBufferSize = BufferSize - WritePos;
44 |
45 | if (remainBufferSize < size)
46 | {
47 | return false;
48 | }
49 |
50 | Buffer.BlockCopy(data, pos, PacketData, WritePos, size);
51 | WritePos += size;
52 |
53 | if (NextFree() == false)
54 | {
55 | BufferRelocate();
56 | }
57 | return true;
58 | }
59 |
60 | public ArraySegment Read()
61 | {
62 | var enableReadSize = WritePos - ReadPos;
63 |
64 | if (enableReadSize < HeaderSize)
65 | {
66 | return new ArraySegment();
67 | }
68 |
69 | var packetDataSize = BitConverter.ToInt16(PacketData, ReadPos);
70 | if (enableReadSize < packetDataSize)
71 | {
72 | return new ArraySegment();
73 | }
74 |
75 | var completePacketData = new ArraySegment(PacketData, ReadPos, packetDataSize);
76 | ReadPos += packetDataSize;
77 | return completePacketData;
78 | }
79 |
80 | bool NextFree()
81 | {
82 | var enableWriteSize = BufferSize - WritePos;
83 |
84 | if (enableWriteSize < MaxPacketSize)
85 | {
86 | return false;
87 | }
88 |
89 | return true;
90 | }
91 |
92 | void BufferRelocate()
93 | {
94 | var enableReadSize = WritePos - ReadPos;
95 |
96 | Buffer.BlockCopy(PacketData, ReadPos, PacketDataTemp, 0, enableReadSize);
97 | Buffer.BlockCopy(PacketDataTemp, 0, PacketData, 0, enableReadSize);
98 |
99 | ReadPos = 0;
100 | WritePos = enableReadSize;
101 | }
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/csharp_test_client_msgpack/PacketDefine.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace csharp_test_client
8 | {
9 | class PacketDef
10 | {
11 | public const Int16 PACKET_HEADER_SIZE = 5;
12 | public const int MAX_USER_ID_BYTE_LENGTH = 16;
13 | public const int MAX_USER_PW_BYTE_LENGTH = 16;
14 | }
15 |
16 | public enum PACKET_ID : ushort
17 | {
18 | PACKET_ID_ECHO = 101,
19 |
20 | // Ping(Heart-beat)
21 | PACKET_ID_PING_REQ = 201,
22 | PACKET_ID_PING_RES = 202,
23 |
24 | PACKET_ID_ERROR_NTF = 203,
25 |
26 |
27 | // 로그인
28 | PACKET_ID_LOGIN_REQ = 701,
29 | PACKET_ID_LOGIN_RES = 702,
30 |
31 |
32 | PACKET_ID_ROOM_ENTER_REQ = 721,
33 | PACKET_ID_ROOM_ENTER_RES = 722,
34 | PACKET_ID_ROOM_USER_LIST_NTF = 723,
35 | PACKET_ID_ROOM_NEW_USER_NTF = 724,
36 |
37 | PACKET_ID_ROOM_LEAVE_REQ = 726,
38 | PACKET_ID_ROOM_LEAVE_RES = 727,
39 | PACKET_ID_ROOM_LEAVE_USER_NTF = 728,
40 |
41 | PACKET_ID_ROOM_CHAT_REQ = 731,
42 | PACKET_ID_ROOM_CHAT_RES = 732,
43 | PACKET_ID_ROOM_CHAT_NOTIFY = 733,
44 |
45 | PACKET_ID_ROOM_RELAY_REQ = 741,
46 | PACKET_ID_ROOM_RELAY_NTF = 742,
47 | }
48 |
49 |
50 | public enum ERROR_CODE : Int16
51 | {
52 | ERROR_NONE = 0,
53 |
54 |
55 |
56 | ERROR_CODE_USER_MGR_INVALID_USER_UNIQUEID = 112,
57 |
58 | ERROR_CODE_PUBLIC_CHANNEL_IN_USER = 114,
59 |
60 | ERROR_CODE_PUBLIC_CHANNEL_INVALIDE_NUMBER = 115,
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/csharp_test_client_msgpack/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using System.Windows.Forms;
6 |
7 | namespace csharp_test_client
8 | {
9 | static class Program
10 | {
11 | ///
12 | /// 해당 응용 프로그램의 주 진입점입니다.
13 | ///
14 | [STAThread]
15 | static void Main()
16 | {
17 | Application.EnableVisualStyles();
18 | Application.SetCompatibleTextRenderingDefault(false);
19 | Application.Run(new mainForm());
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/csharp_test_client_msgpack/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // 어셈블리에 대한 일반 정보는 다음 특성 집합을 통해
6 | // 제어됩니다. 어셈블리와 관련된 정보를 수정하려면
7 | // 이러한 특성 값을 변경하세요.
8 | [assembly: AssemblyTitle("csharp_test_client")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("csharp_test_client")]
13 | [assembly: AssemblyCopyright("Copyright © 2016")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // ComVisible을 false로 설정하면 이 어셈블리의 형식이 COM 구성 요소에
18 | // 표시되지 않습니다. COM에서 이 어셈블리의 형식에 액세스하려면
19 | // 해당 형식에 대해 ComVisible 특성을 true로 설정하세요.
20 | [assembly: ComVisible(false)]
21 |
22 | // 이 프로젝트가 COM에 노출되는 경우 다음 GUID는 typelib의 ID를 나타냅니다.
23 | [assembly: Guid("9e4b5e72-4e76-4e22-90b0-e53275a99018")]
24 |
25 | // 어셈블리의 버전 정보는 다음 네 가지 값으로 구성됩니다.
26 | //
27 | // 주 버전
28 | // 부 버전
29 | // 빌드 번호
30 | // 수정 버전
31 | //
32 | // 모든 값을 지정하거나 아래와 같이 '*'를 사용하여 빌드 번호 및 수정 번호가 자동으로
33 | // 지정되도록 할 수 있습니다.
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/csharp_test_client_msgpack/Properties/Resources.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // 이 코드는 도구를 사용하여 생성되었습니다.
4 | // 런타임 버전:4.0.30319.42000
5 | //
6 | // 파일 내용을 변경하면 잘못된 동작이 발생할 수 있으며, 코드를 다시 생성하면
7 | // 이러한 변경 내용이 손실됩니다.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace csharp_test_client.Properties
12 | {
13 |
14 |
15 | ///
16 | /// 지역화된 문자열 등을 찾기 위한 강력한 형식의 리소스 클래스입니다.
17 | ///
18 | // 이 클래스는 ResGen 또는 Visual Studio와 같은 도구를 통해 StronglyTypedResourceBuilder
19 | // 클래스에서 자동으로 생성되었습니다.
20 | // 멤버를 추가하거나 제거하려면 .ResX 파일을 편집한 다음 /str 옵션을 사용하여
21 | // ResGen을 다시 실행하거나 VS 프로젝트를 다시 빌드하십시오.
22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
25 | internal class Resources
26 | {
27 |
28 | private static global::System.Resources.ResourceManager resourceMan;
29 |
30 | private static global::System.Globalization.CultureInfo resourceCulture;
31 |
32 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
33 | internal Resources()
34 | {
35 | }
36 |
37 | ///
38 | /// 이 클래스에서 사용하는 캐시된 ResourceManager 인스턴스를 반환합니다.
39 | ///
40 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
41 | internal static global::System.Resources.ResourceManager ResourceManager
42 | {
43 | get
44 | {
45 | if ((resourceMan == null))
46 | {
47 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("csharp_test_client.Properties.Resources", typeof(Resources).Assembly);
48 | resourceMan = temp;
49 | }
50 | return resourceMan;
51 | }
52 | }
53 |
54 | ///
55 | /// 이 강력한 형식의 리소스 클래스를 사용하여 모든 리소스 조회에 대해
56 | /// 현재 스레드의 CurrentUICulture 속성을 재정의합니다.
57 | ///
58 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
59 | internal static global::System.Globalization.CultureInfo Culture
60 | {
61 | get
62 | {
63 | return resourceCulture;
64 | }
65 | set
66 | {
67 | resourceCulture = value;
68 | }
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/csharp_test_client_msgpack/Properties/Settings.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.42000
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace csharp_test_client.Properties
12 | {
13 |
14 |
15 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
16 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
17 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
18 | {
19 |
20 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
21 |
22 | public static Settings Default
23 | {
24 | get
25 | {
26 | return defaultInstance;
27 | }
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/csharp_test_client_msgpack/Properties/Settings.settings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/csharp_test_client_msgpack/csharp_test_client_msgpack.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | net8.0-windows
4 | WinExe
5 | csharp_test_client
6 | false
7 | true
8 | true
9 |
10 |
11 | ..\bin\
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | all
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/csharp_test_client_msgpack/csharp_test_client_msgpack.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.29519.87
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "csharp_test_client_msgpack", "csharp_test_client_msgpack.csproj", "{9E4B5E72-4E76-4E22-90B0-E53275A99018}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SimpleMsgPack", "..\thirdparty\SimpleMsgPack.Net\Source\SimpleMsgPack.csproj", "{53CED7AF-BCF5-453D-AC00-36247752EBA8}"
9 | EndProject
10 | Global
11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
12 | Debug|Any CPU = Debug|Any CPU
13 | Release|Any CPU = Release|Any CPU
14 | EndGlobalSection
15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
16 | {9E4B5E72-4E76-4E22-90B0-E53275A99018}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
17 | {9E4B5E72-4E76-4E22-90B0-E53275A99018}.Debug|Any CPU.Build.0 = Debug|Any CPU
18 | {9E4B5E72-4E76-4E22-90B0-E53275A99018}.Release|Any CPU.ActiveCfg = Release|Any CPU
19 | {9E4B5E72-4E76-4E22-90B0-E53275A99018}.Release|Any CPU.Build.0 = Release|Any CPU
20 | {53CED7AF-BCF5-453D-AC00-36247752EBA8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21 | {53CED7AF-BCF5-453D-AC00-36247752EBA8}.Debug|Any CPU.Build.0 = Debug|Any CPU
22 | {53CED7AF-BCF5-453D-AC00-36247752EBA8}.Release|Any CPU.ActiveCfg = Release|Any CPU
23 | {53CED7AF-BCF5-453D-AC00-36247752EBA8}.Release|Any CPU.Build.0 = Release|Any CPU
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | GlobalSection(ExtensibilityGlobals) = postSolution
29 | SolutionGuid = {617A86AA-2EF2-432C-8980-B03FF79E7A5A}
30 | EndGlobalSection
31 | EndGlobal
32 |
--------------------------------------------------------------------------------
/echoServer/echoServer.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | . "gohipernetFake"
6 | "strconv"
7 | "strings"
8 | )
9 |
10 |
11 | type EchoServer struct {
12 | ServerIndex int
13 | IP string
14 | Port int
15 | }
16 |
17 | func createServer(netConfig NetworkConfig) {
18 | OutPutLog(LOG_LEVEL_INFO,"", 0,"CreateServer !!!")
19 |
20 | var server EchoServer
21 |
22 | if server.setIPAddress(netConfig.BindAddress) == false {
23 | OutPutLog(LOG_LEVEL_ERROR,"", 0,"fail. server address")
24 | return
25 | }
26 |
27 |
28 | networkFunctor := SessionNetworkFunctors{}
29 | networkFunctor.OnConnect = server.OnConnect
30 | networkFunctor.OnReceive = server.OnReceive
31 | networkFunctor.OnReceiveBufferedData = nil
32 | networkFunctor.OnClose = server.OnClose
33 | networkFunctor.PacketTotalSizeFunc = PacketTotalSize
34 | networkFunctor.PacketHeaderSize = PACKET_HEADER_SIZE
35 | networkFunctor.IsClientSession = true
36 |
37 | NetLibStartNetwork(&netConfig, networkFunctor)
38 | }
39 |
40 | func (server *EchoServer) setIPAddress(ipAddress string) bool {
41 | results := strings.Split(ipAddress, ":")
42 | if len(results) != 2 {
43 | return false
44 | }
45 |
46 | server.IP = results[0]
47 | server.Port, _ = strconv.Atoi(results[1])
48 |
49 | return true
50 | }
51 |
52 | func (server *EchoServer) OnConnect(sessionIndex int32, sessionUniqueID uint64) {
53 | OutPutLog(LOG_LEVEL_INFO,"", 0,fmt.Sprintf("[OnConnect] sessionIndex: %d", sessionIndex))
54 | }
55 |
56 | func (server *EchoServer) OnReceive(sessionIndex int32, sessionUniqueID uint64, data []byte) bool {
57 | NetLibISendToClient(sessionIndex, sessionUniqueID, data)
58 | return true
59 | }
60 |
61 | func (server *EchoServer) OnClose(sessionIndex int32, sessionUniqueID uint64) {
62 | OutPutLog(LOG_LEVEL_INFO,"", 0,fmt.Sprintf("[OnClose] sessionIndex: %d", sessionIndex))
63 | }
64 |
65 |
66 |
--------------------------------------------------------------------------------
/echoServer/go.mod:
--------------------------------------------------------------------------------
1 | module main
2 |
3 | go 1.13
4 |
5 | require (
6 | github.com/davecgh/go-spew v1.1.1 // indirect
7 | go.uber.org/atomic v1.4.0 // indirect
8 | go.uber.org/multierr v1.1.0 // indirect
9 | go.uber.org/zap v1.10.0
10 |
11 | gohipernetFake v0.0.0
12 | gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
13 | )
14 |
15 | replace gohipernetFake v0.0.0 => ../gohipernetFake
16 |
--------------------------------------------------------------------------------
/echoServer/go.sum:
--------------------------------------------------------------------------------
1 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
2 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
3 | go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU=
4 | go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
5 | go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI=
6 | go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
7 | go.uber.org/zap v1.10.0 h1:ORx85nbTijNz8ljznvCMR1ZBIPKFn3jQrag10X2AsuM=
8 | go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
9 | gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=
10 | gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
11 |
--------------------------------------------------------------------------------
/echoServer/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "flag"
5 | . "gohipernetFake"
6 | )
7 |
8 |
9 | func main() {
10 | NetLibInitLog(LOG_LEVEL_DEBUG, nil)
11 |
12 | netConfigClient := parseAppConfig()
13 | netConfigClient.WriteNetworkConfig(true)
14 |
15 | // 아래 함수를 호출하면 강제적으로 종료 시킬 때까지 대기 상태가 된다.
16 | createServer(netConfigClient)
17 | }
18 |
19 | func parseAppConfig() NetworkConfig {
20 | client := NetworkConfig{}
21 |
22 | flag.BoolVar(&client.IsTcp4Addr,"c_IsTcp4Addr", true, "bool flag")
23 | flag.StringVar(&client.BindAddress,"c_BindAddress", "127.0.0.1:11021", "string flag")
24 | flag.IntVar(&client.MaxSessionCount,"c_MaxSessionCount", 0, "int flag")
25 | flag.IntVar(&client.MaxPacketSize,"c_MaxPacketSize", 0, "int flag")
26 |
27 | flag.Parse()
28 | return client
29 | }
30 |
31 |
--------------------------------------------------------------------------------
/gohipernetFake/TcpSession.go:
--------------------------------------------------------------------------------
1 | package gohipernetFake
2 |
3 | import (
4 | "net"
5 | )
6 |
7 |
8 |
9 | type TcpSession struct {
10 | Index int32
11 | SeqIndex uint64
12 | TcpConn net.Conn
13 | NetworkFunctor SessionNetworkFunctors
14 | }
15 |
16 | func (session *TcpSession) handleTcpRead(networkFunctor SessionNetworkFunctors) {
17 | session.NetworkFunctor.OnConnect(session.Index, session.SeqIndex)
18 |
19 |
20 | var startRecvPos int16
21 | var result int
22 | recviveBuff := make([]byte, MAX_RECEIVE_BUFFER_SIZE)
23 |
24 | for {
25 | recvBytes, err := session.TcpConn.Read(recviveBuff[startRecvPos:])
26 | if err != nil {
27 | //TODO 끊는 이유 남기기
28 | session.closeProcess()
29 | return
30 | }
31 |
32 | if recvBytes < PACKET_HEADER_SIZE {
33 | //TODO 끊는 이유 남기기
34 | session.closeProcess()
35 | return
36 | }
37 |
38 | readAbleByte := int16(startRecvPos) + int16(recvBytes)
39 | startRecvPos, result = session.makePacket(readAbleByte, recviveBuff)
40 | if result != NET_ERROR_NONE {
41 | //TODO 끊는 이유 남기기
42 | session.closeProcess()
43 | return
44 | }
45 |
46 | }
47 | }
48 |
49 | func (session *TcpSession) makePacket(readAbleByte int16, recviveBuff []byte) (int16, int) {
50 | sessionIndex := session.Index
51 | sessionUnique := session.SeqIndex
52 |
53 | PacketHeaderSize := session.NetworkFunctor.PacketHeaderSize
54 | PacketTotalSizeFunc := session.NetworkFunctor.PacketTotalSizeFunc
55 | var startRecvPos int16 = 0
56 | var readPos int16
57 |
58 | for {
59 | if readAbleByte < PacketHeaderSize {
60 | break
61 | }
62 |
63 | requireDataSize := PacketTotalSizeFunc(recviveBuff[readPos:])
64 |
65 | if requireDataSize > readAbleByte {
66 | break
67 | }
68 |
69 | if requireDataSize > MAX_PACKET_SIZE {
70 | return startRecvPos, NET_ERROR_RECV_MAKE_PACKET_TOO_LARGE_PACKET_SIZE
71 | }
72 |
73 | ltvPacket := recviveBuff[readPos:(readPos + requireDataSize)]
74 | readPos += requireDataSize
75 | readAbleByte -= requireDataSize
76 |
77 |
78 | session.NetworkFunctor.OnReceive(sessionIndex, sessionUnique, ltvPacket)
79 | }
80 |
81 |
82 | if readAbleByte > 0 {
83 | copy(recviveBuff, recviveBuff[readPos:(readPos+readAbleByte)])
84 | }
85 |
86 | startRecvPos = readAbleByte
87 | return startRecvPos, NET_ERROR_NONE
88 | }
89 |
90 | func (session *TcpSession) closeProcess() {
91 | session.TcpConn.Close()
92 | session.NetworkFunctor.OnClose(session.Index, session.SeqIndex)
93 |
94 | _tcpSessionManager.removeSession(session.Index, session.SeqIndex)
95 | }
96 |
97 | // Send bytes to client
98 | func (session *TcpSession) sendPacket(b []byte) error {
99 | _, err := session.TcpConn.Write(b)
100 | return err
101 | }
102 |
103 | func (session *TcpSession) close() error {
104 | return session.TcpConn.Close()
105 | }
--------------------------------------------------------------------------------
/gohipernetFake/clientSessionManager.go:
--------------------------------------------------------------------------------
1 | package gohipernetFake
2 |
3 | import (
4 | "sync"
5 | "sync/atomic"
6 | )
7 |
8 | type tcpClientSessionManager struct {
9 | _networkFunctor SessionNetworkFunctors
10 |
11 | _sessionMap sync.Map
12 | _curSessionCount int32 // 멀티스레드에서 호출된다
13 |
14 | sessionIndexPool *Deque
15 | }
16 |
17 | func newClientSessionManager(config *NetworkConfig,
18 | networkFunctor SessionNetworkFunctors) *tcpClientSessionManager {
19 | sessionMgr := new(tcpClientSessionManager)
20 | sessionMgr._networkFunctor = networkFunctor
21 | sessionMgr._sessionMap = sync.Map{}
22 |
23 | sessionMgr._createSessionIndexPool(config.MaxSessionCount)
24 |
25 | return sessionMgr
26 | }
27 |
28 | func (sessionMgr *tcpClientSessionManager) _createSessionIndexPool(poolSize int) {
29 | sessionMgr.sessionIndexPool = NewCappedDeque(poolSize)
30 |
31 | for i := 0; i < poolSize; i++ {
32 | sessionMgr.sessionIndexPool.Append(int32(i))
33 | }
34 | }
35 |
36 | func (sessionMgr *tcpClientSessionManager) _allocSessionIndex() int32 {
37 | index := sessionMgr.sessionIndexPool.Shift()
38 |
39 | if index == nil {
40 | return -1
41 | }
42 |
43 | return index.(int32)
44 | }
45 |
46 | func (sessionMgr *tcpClientSessionManager) _freeSessionIndex(sessionIndex int32) {
47 | sessionMgr.sessionIndexPool.Append(sessionIndex)
48 | }
49 |
50 | func (sessionMgr *tcpClientSessionManager) addSession(session *TcpSession) bool {
51 | sessionUniqueId := session.SeqIndex
52 | sessionIndex := sessionMgr._allocSessionIndex()
53 |
54 | if sessionIndex == -1 {
55 | return false
56 | }
57 |
58 | _, result := sessionMgr._findSession(sessionIndex, sessionUniqueId)
59 | if result {
60 | return false
61 | }
62 |
63 | session.Index = sessionIndex
64 | sessionMgr._sessionMap.Store(sessionUniqueId, session)
65 | return true
66 | }
67 |
68 | func (sessionMgr *tcpClientSessionManager) removeSession(sessionIndex int32, sessionUniqueId uint64) {
69 | sessionMgr._freeSessionIndex(sessionIndex)
70 | sessionMgr._sessionMap.Delete(sessionUniqueId)
71 | }
72 |
73 | func (sessionMgr *tcpClientSessionManager) sendPacket(sessionIndex int32,
74 | sessionUniqueId uint64,
75 | sendData []byte) bool {
76 | session, result := sessionMgr._findSession(sessionIndex, sessionUniqueId)
77 | if result == false {
78 | return false
79 | }
80 |
81 | session.sendPacket(sendData)
82 | return true
83 | }
84 |
85 | func (sessionMgr *tcpClientSessionManager) sendPacketAllClient(sendData []byte) {
86 | sessionMgr._sessionMap.Range(func(_, value interface{}) bool {
87 | value.(*TcpSession).sendPacket(sendData)
88 | return true
89 | })
90 | }
91 |
92 | func (sessionMgr *tcpClientSessionManager) _connectedessionCount() int32 {
93 | count := atomic.LoadInt32(&sessionMgr._curSessionCount)
94 | return count
95 | }
96 |
97 | func (sessionMgr *tcpClientSessionManager) _IncConnectedessionCount() {
98 | atomic.AddInt32(&sessionMgr._curSessionCount, 1)
99 | }
100 |
101 | func (sessionMgr *tcpClientSessionManager) _DecConnectedessionCount() {
102 | atomic.AddInt32(&sessionMgr._curSessionCount, -1)
103 | }
104 |
105 | func (sessionMgr *tcpClientSessionManager) _findSession(sessionIndex int32,
106 | sessionUniqueId uint64,
107 | ) (*TcpSession, bool) {
108 | if session, ok := sessionMgr._sessionMap.Load(sessionUniqueId); ok {
109 | return session.(*TcpSession), true
110 | }
111 |
112 | return nil, false
113 | }
114 |
115 | func (sessionMgr *tcpClientSessionManager) forceDisconnectClient(sessionIndex int32,
116 | sessionUniqueId uint64) bool {
117 |
118 | session, resut := sessionMgr._findSession(sessionIndex, sessionUniqueId)
119 | if resut == false {
120 | return false
121 | }
122 |
123 | session.closeProcess()
124 | return true
125 | }
126 |
127 | func (sessionMgr *tcpClientSessionManager) _forceCloseAllSession() {
128 | sessionMgr._sessionMap.Range(func(_, value interface{}) bool {
129 | value.(*TcpSession).closeProcess()
130 | return true
131 | })
132 | }
133 |
--------------------------------------------------------------------------------
/gohipernetFake/configNetwork.go:
--------------------------------------------------------------------------------
1 | package gohipernetFake
2 |
3 | import (
4 | "fmt"
5 | )
6 |
7 |
8 | type NetworkConfig struct {
9 | IsTcp4Addr bool
10 | BindAddress string // 예) localhost:19999
11 | MaxSessionCount int // 최대 클라이언트 세션 수. 넉넉하게 많이 해도 괜찮다
12 | MaxPacketSize int // 최대 패킷 크기
13 | MaxReceiveBufferSize int // 받기 버퍼 크기. 최소 MaxPacketSize 2배 이상 추천.
14 |
15 | }
16 |
17 | func (config NetworkConfig) WriteNetworkConfig(isClientSide bool) {
18 | logInfo("", 0, fmt.Sprintf("config - isClientSide: %t", isClientSide))
19 | logInfo("", 0, fmt.Sprintf("config - IsTcp4Addr: %t", config.IsTcp4Addr))
20 | logInfo("", 0, fmt.Sprintf("config - ClientAddress: %s", config.BindAddress))
21 | logInfo("", 0, fmt.Sprintf("config - MaxSessionCount: %d", config.MaxSessionCount))
22 | logInfo("", 0, fmt.Sprintf("config - MaxPacketSize: %d", config.MaxPacketSize))
23 | logInfo("", 0, fmt.Sprintf("config - MaxReceiveBufferSize: %d", config.MaxReceiveBufferSize))
24 | }
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/gohipernetFake/define.go:
--------------------------------------------------------------------------------
1 | package gohipernetFake
2 |
3 |
4 | const (
5 | MAX_RECEIVE_BUFFER_SIZE = 8012
6 | PACKET_HEADER_SIZE = 5
7 | MAX_PACKET_SIZE = 1024
8 | )
9 |
10 | const (
11 | NET_ERROR_NONE = 0
12 | NET_ERROR_RECV_MAKE_PACKET_TOO_LARGE_PACKET_SIZE = 1
13 |
14 | )
15 | const (
16 | NET_CLOSE_REMOTE = 1
17 | NET_CLOSE_RECV_TOO_SMALL_RECV_DATA = 2
18 | )
19 |
20 |
21 |
22 | type SessionNetworkFunctors struct {
23 | OnConnect func(int32, uint64)
24 |
25 | OnClose func(int32, uint64)
26 |
27 | // 데이터 도착 이벤트
28 | OnReceive func(int32, uint64, []byte) bool
29 |
30 | // 데이터 도착 이벤트. []byte가 링버퍼에 저장되어 있다
31 | OnReceiveBufferedData func(int32, uint64, []byte) bool
32 |
33 |
34 | // 데이터를 분석하여 패킷 크기를 반환한다.
35 | PacketTotalSizeFunc func([]byte) int16
36 |
37 | // 패킷 헤더의 크기
38 | PacketHeaderSize int16
39 |
40 | // true 이면 client와 연결한 세션이다.
41 | IsClientSession bool
42 | }
--------------------------------------------------------------------------------
/gohipernetFake/go.mod:
--------------------------------------------------------------------------------
1 | module gohipernetFake
2 |
3 | go 1.13
4 |
5 | require (
6 | github.com/davecgh/go-spew v1.1.1
7 | )
8 |
--------------------------------------------------------------------------------
/gohipernetFake/go.sum:
--------------------------------------------------------------------------------
1 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
2 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
3 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
4 | github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
5 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
6 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
7 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
8 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
9 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
10 | github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
11 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
12 | go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
13 | go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
14 | go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
15 | go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
16 | go.uber.org/zap v1.17.0 h1:MTjgFu6ZLKvY6Pvaqk97GlxNBuMpV4Hy/3P6tRGlI2U=
17 | go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
18 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
19 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
20 | gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
21 | gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
22 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
23 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
24 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
25 |
--------------------------------------------------------------------------------
/gohipernetFake/goHiperNet.go:
--------------------------------------------------------------------------------
1 | // 애플리케이션에서 네트워크 라이브러리에 접근할 함수는 모두 여기에만 정의한다.
2 | package gohipernetFake
3 |
4 |
5 |
6 | func NetLibInitLog(loglevel int, logFunc func(int, string, uint64, string)) {
7 | _logLevel = loglevel
8 |
9 | if logFunc != nil {
10 | OutPutLog = logFunc
11 | }
12 | }
13 |
14 | // 네트워크 시작
15 | func NetLibStartNetwork(clientConfig *NetworkConfig, networkFunctor SessionNetworkFunctors) {
16 | start_Network_Impl(clientConfig, networkFunctor)
17 | }
18 |
19 | func NetLibStopListen() {
20 | stopListen_impl()
21 | }
22 |
23 | // 특정 클라이언트에게 데이터를 보낸다
24 | var NetLibISendToClient func(int32, uint64, []byte) bool
25 | // 접속된 모든 클라이언트에게 데이터를 보낸다.
26 | var NetLibISendToAllClient func([]byte)
27 |
28 | var NetLibIPostSendToAllClient func([]byte)
29 | var NetLibIPostSendToClient func(int32, uint64, []byte) bool
30 |
31 |
32 | // 클라이언트 접속을 강제로 짜른다.
33 | func NetLibForceDisconnectClient(sessionIndex int32, sessionUnqiueID uint64) {
34 | _tcpSessionManager.forceDisconnectClient(sessionIndex, sessionUnqiueID)
35 | }
--------------------------------------------------------------------------------
/gohipernetFake/goHiperNet_Impl.go:
--------------------------------------------------------------------------------
1 | package gohipernetFake
2 |
3 | import (
4 | "log"
5 | "net"
6 | "sync/atomic"
7 | )
8 |
9 |
10 | func start_Network_Impl(clientConfig *NetworkConfig, networkFunctor SessionNetworkFunctors) {
11 | defer PrintPanicStack()
12 |
13 | // 아래 함수가 호출되면 무한 대기에 들어간다
14 | _tcpSessionManager = newClientSessionManager(clientConfig, networkFunctor)
15 | _start_TCPServer_block(clientConfig, networkFunctor)
16 | }
17 |
18 | func stopListen_impl() {
19 | _ = _mClientListener.Close()
20 | }
21 |
22 | func _start_TCPServer_block(config *NetworkConfig, networkFunctor SessionNetworkFunctors) {
23 | defer PrintPanicStack()
24 | logInfo("", 0, "tcpServerStart - Start")
25 |
26 | var err error
27 | tcpAddr, _ := net.ResolveTCPAddr("tcp", config.BindAddress)
28 | _mClientListener, err = net.ListenTCP("tcp", tcpAddr)
29 |
30 | if err != nil {
31 | log.Fatal("Error starting TCP server.")
32 | }
33 | defer _mClientListener.Close()
34 |
35 | log.Println("Server Listen ...")
36 |
37 | for {
38 | conn, _ := _mClientListener.Accept()
39 | client := &TcpSession{
40 | SeqIndex: SeqNumIncrement(),
41 | TcpConn: conn,
42 | NetworkFunctor: networkFunctor,
43 | }
44 |
45 | _tcpSessionManager.addSession(client)
46 |
47 | go client.handleTcpRead(networkFunctor)
48 | }
49 |
50 | logInfo("", 0, "tcpServerStart - End")
51 | }
52 |
53 | // 보내기 함수(선언만 있는. 일종의 인터페이스)에 실제 동작함수를 연결한다
54 | func _InitNetworkSendFunction() {
55 | NetLibISendToClient = sendToClient
56 | NetLibISendToAllClient = sendToAllClient
57 | NetLibIPostSendToAllClient = postSendToAllClient
58 | NetLibIPostSendToClient = postSendToClient
59 |
60 | logInfo("", 0, "call _InitNetworkSendFunction")
61 | }
62 |
63 | func sendToClient(sessionIndex int32, sessionUniqueID uint64, data []byte) bool {
64 | result := _tcpSessionManager.sendPacket(sessionIndex, sessionUniqueID, data)
65 | return result
66 | }
67 |
68 | func sendToAllClient(sendData []byte) {
69 | _tcpSessionManager.sendPacketAllClient(sendData)
70 | }
71 |
72 | func postSendToClient(sessionIndex int32, sessionUniqueID uint64, data []byte) bool {
73 | return sendToClient(sessionIndex, sessionUniqueID, data)
74 | }
75 |
76 | func postSendToAllClient(sendData []byte) {
77 | _tcpSessionManager.sendPacketAllClient(sendData)
78 | }
79 |
80 | func sendPacketToServer(sessionIndex int32, data []byte) bool {
81 | return false
82 | }
83 |
84 | func postSendPacketToServer(sessionIndex int32, data []byte) bool {
85 | return false
86 | }
87 |
88 |
89 |
90 | var _seqNumber uint64 // 절대 이것을 바로 사용하면 안 된다!!!
91 |
92 | func SeqNumIncrement() uint64 {
93 | newValue := atomic.AddUint64(&_seqNumber, 1)
94 | return newValue
95 | }
96 |
97 | var _tcpSessionManager *tcpClientSessionManager
98 | var _mClientListener *net.TCPListener
99 |
--------------------------------------------------------------------------------
/gohipernetFake/log.go:
--------------------------------------------------------------------------------
1 | package gohipernetFake
2 |
3 |
4 | import (
5 | "fmt"
6 | "os"
7 | )
8 |
9 | const (
10 | LOG_LEVEL_TRACE = 0
11 | LOG_LEVEL_DEBUG = 1
12 | LOG_LEVEL_INFO = 2
13 | LOG_LEVEL_WARN = 3
14 | LOG_LEVEL_ERROR = 4
15 | LOG_LEVEL_FATAL = 5
16 | )
17 |
18 | var logLevelStr = [6]string{"trace", "debug", "info", "warn", "error", "fatal"}
19 |
20 | var (
21 | OutPutLog = _emptyExportLog
22 | )
23 |
24 | func logTrace(userID string, sessionUID uint64, msg string) {
25 | OutPutLog(LOG_LEVEL_TRACE, userID, sessionUID, msg)
26 | }
27 | func logDebug(userID string, sessionUID uint64, msg string) {
28 | OutPutLog(LOG_LEVEL_DEBUG, userID, sessionUID, msg)
29 | }
30 | func logInfo(userID string, sessionUID uint64, msg string) {
31 | OutPutLog(LOG_LEVEL_INFO, userID, sessionUID, msg)
32 | }
33 | func logError(userID string, sessionUID uint64, msg string) {
34 | OutPutLog(LOG_LEVEL_ERROR, userID, sessionUID, msg)
35 | }
36 |
37 | // 비공개 함수
38 | func _emptyExportLog(level int, userID string, sessionUID uint64, msg string) {
39 | if level < _logLevel {
40 | return
41 | }
42 |
43 | fmt.Fprintf(os.Stdout, "[ %s ] %s\n", logLevelStr[level], msg)
44 | }
45 |
46 | var _logLevel int
47 |
--------------------------------------------------------------------------------
/gohipernetFake/utilDeque.go:
--------------------------------------------------------------------------------
1 | package gohipernetFake
2 |
3 | import (
4 | "container/list"
5 | "sync"
6 | )
7 |
8 | //이 라이브러리의 출처(https://github.com/oleiade/lane)
9 | // Deque is a head-tail linked list data structure implementation.
10 | // It is based on a doubly linked list container, so that every
11 | // operations time complexity is O(1).
12 | //
13 | // every operations over an instiated Deque are synchronized and
14 | // safe for concurrent usage.
15 | type Deque struct {
16 | sync.RWMutex
17 | container *list.List
18 | capacity int
19 | }
20 |
21 | // NewDeque creates a Deque.
22 | func NewDeque() *Deque {
23 | return NewCappedDeque(-1)
24 | }
25 |
26 | // NewCappedDeque creates a Deque with the specified capacity limit.
27 | func NewCappedDeque(capacity int) *Deque {
28 | return &Deque{
29 | container: list.New(),
30 | capacity: capacity,
31 | }
32 | }
33 |
34 | //원소를 뒤에 넣는다
35 | // Append inserts element at the back of the Deque in a O(1) time complexity,
36 | // returning true if successful or false if the deque is at capacity.
37 | func (s *Deque) Append(item interface{}) (int, bool) {
38 | s.Lock()
39 | defer s.Unlock()
40 |
41 | count := s.container.Len()
42 | if s.capacity < 0 || count < s.capacity {
43 | s.container.PushBack(item)
44 | count += 1
45 | return count, true
46 | }
47 |
48 | return 0, false
49 | }
50 |
51 | // 앞에 원소를 넣는다
52 | // Prepend inserts element at the Deques front in a O(1) time complexity,
53 | // returning true if successful or false if the deque is at capacity.
54 | func (s *Deque) Prepend(item interface{}) (int, bool) {
55 | s.Lock()
56 | defer s.Unlock()
57 |
58 | count := s.container.Len()
59 | if s.capacity < 0 || count < s.capacity {
60 | s.container.PushFront(item)
61 | count += 1
62 | return count, true
63 | }
64 |
65 | return 0, false
66 | }
67 |
68 | // 제일 마지막에 넣은 원소를 뺀다
69 | // Pop removes the last element of the deque in a O(1) time complexity
70 | func (s *Deque) Pop() interface{} {
71 | s.Lock()
72 | defer s.Unlock()
73 |
74 | var item interface{} = nil
75 | var lastContainerItem *list.Element = nil
76 |
77 | lastContainerItem = s.container.Back()
78 | if lastContainerItem != nil {
79 | item = s.container.Remove(lastContainerItem)
80 | }
81 |
82 | return item
83 | }
84 |
85 | // 앞에 넣은 원소를 뺀다
86 | // Shift removes the first element of the deque in a O(1) time complexity
87 | func (s *Deque) Shift() interface{} {
88 | s.Lock()
89 | defer s.Unlock()
90 |
91 | var item interface{} = nil
92 | var firstContainerItem *list.Element = nil
93 |
94 | firstContainerItem = s.container.Front()
95 | if firstContainerItem != nil {
96 | item = s.container.Remove(firstContainerItem)
97 | }
98 |
99 | return item
100 | }
101 |
102 | // First returns the first value stored in the deque in a O(1) time complexity
103 | func (s *Deque) First() interface{} {
104 | s.RLock()
105 | defer s.RUnlock()
106 |
107 | item := s.container.Front()
108 | if item != nil {
109 | return item.Value
110 | } else {
111 | return nil
112 | }
113 | }
114 |
115 | // Last returns the last value stored in the deque in a O(1) time complexity
116 | func (s *Deque) Last() interface{} {
117 | s.RLock()
118 | defer s.RUnlock()
119 |
120 | item := s.container.Back()
121 | if item != nil {
122 | return item.Value
123 | } else {
124 | return nil
125 | }
126 | }
127 |
128 | // Size returns the actual deque size
129 | func (s *Deque) Size() int {
130 | s.RLock()
131 | defer s.RUnlock()
132 |
133 | return s.container.Len()
134 | }
135 |
136 | // Capacity returns the capacity of the deque, or -1 if unlimited
137 | func (s *Deque) Capacity() int {
138 | s.RLock()
139 | defer s.RUnlock()
140 | return s.capacity
141 | }
142 |
143 | // Empty checks if the deque is empty
144 | func (s *Deque) Empty() bool {
145 | s.RLock()
146 | defer s.RUnlock()
147 |
148 | return s.container.Len() == 0
149 | }
150 |
151 | // Full checks if the deque is full
152 | func (s *Deque) Full() bool {
153 | s.RLock()
154 | defer s.RUnlock()
155 |
156 | return s.capacity >= 0 && s.container.Len() >= s.capacity
157 | }
158 |
--------------------------------------------------------------------------------
/gohipernetFake/utilPrintPanicStack.go:
--------------------------------------------------------------------------------
1 | package gohipernetFake
2 |
3 | import (
4 | "fmt"
5 | "runtime"
6 |
7 | "github.com/davecgh/go-spew/spew"
8 | )
9 |
10 | func PrintPanicStack(extras ...interface{}) {
11 | if x := recover(); x != nil {
12 | logError("", 0, fmt.Sprintf("%v", x))
13 |
14 | i := 0
15 | funcName, file, line, ok := runtime.Caller(i)
16 |
17 | for ok {
18 | msg := fmt.Sprintf("PrintPanicStack. [func]: %s, [file]: %s, [line]: %d\n", runtime.FuncForPC(funcName).Name(), file, line)
19 | logError("", 0, msg)
20 | i++
21 | funcName, file, line, ok = runtime.Caller(i)
22 | }
23 |
24 | for k := range extras {
25 | msg := fmt.Sprintf("EXRAS#%v DATA:%v\n", k, spew.Sdump(extras[k]))
26 | logError("", 0, msg)
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/lib_opensource/1m-go-tcp-server-master.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jacking75/edu_GolangSocketGameServer/ff8782cfbf0bd5a321ffbe3fe6716de2f6c80e4e/lib_opensource/1m-go-tcp-server-master.zip
--------------------------------------------------------------------------------
/lib_opensource/1m-go-websockets-master.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jacking75/edu_GolangSocketGameServer/ff8782cfbf0bd5a321ffbe3fe6716de2f6c80e4e/lib_opensource/1m-go-websockets-master.zip
--------------------------------------------------------------------------------
/lib_opensource/gnet-dev.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jacking75/edu_GolangSocketGameServer/ff8782cfbf0bd5a321ffbe3fe6716de2f6c80e4e/lib_opensource/gnet-dev.zip
--------------------------------------------------------------------------------
/thirdparty/SimpleMsgPack.Net/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.sln.docstates
8 |
9 | # Build results
10 | [Dd]ebug/
11 | [Dd]ebugPublic/
12 | [Rr]elease/
13 | [Rr]eleases/
14 | x64/
15 | x86/
16 | build/
17 | bld/
18 | [Bb]in/
19 | [Oo]bj/
20 |
21 | # Roslyn cache directories
22 | *.ide/
23 |
24 | # MSTest test Results
25 | [Tt]est[Rr]esult*/
26 | [Bb]uild[Ll]og.*
27 |
28 | #NUNIT
29 | *.VisualState.xml
30 | TestResult.xml
31 |
32 | # Build Results of an ATL Project
33 | [Dd]ebugPS/
34 | [Rr]eleasePS/
35 | dlldata.c
36 |
37 | *_i.c
38 | *_p.c
39 | *_i.h
40 | *.ilk
41 | *.meta
42 | *.obj
43 | *.pch
44 | *.pdb
45 | *.pgc
46 | *.pgd
47 | *.rsp
48 | *.sbr
49 | *.tlb
50 | *.tli
51 | *.tlh
52 | *.tmp
53 | *.tmp_proj
54 | *.log
55 | *.vspscc
56 | *.vssscc
57 | .builds
58 | *.pidb
59 | *.svclog
60 | *.scc
61 |
62 | # Chutzpah Test files
63 | _Chutzpah*
64 |
65 | # Visual C++ cache files
66 | ipch/
67 | *.aps
68 | *.ncb
69 | *.opensdf
70 | *.sdf
71 | *.cachefile
72 |
73 | # Visual Studio profiler
74 | *.psess
75 | *.vsp
76 | *.vspx
77 |
78 | # TFS 2012 Local Workspace
79 | $tf/
80 |
81 | # Guidance Automation Toolkit
82 | *.gpState
83 |
84 | # ReSharper is a .NET coding add-in
85 | _ReSharper*/
86 | *.[Rr]e[Ss]harper
87 | *.DotSettings.user
88 |
89 | # JustCode is a .NET coding addin-in
90 | .JustCode
91 |
92 | # TeamCity is a build add-in
93 | _TeamCity*
94 |
95 | # DotCover is a Code Coverage Tool
96 | *.dotCover
97 |
98 | # NCrunch
99 | _NCrunch_*
100 | .*crunch*.local.xml
101 |
102 | # MightyMoose
103 | *.mm.*
104 | AutoTest.Net/
105 |
106 | # Web workbench (sass)
107 | .sass-cache/
108 |
109 | # Installshield output folder
110 | [Ee]xpress/
111 |
112 | # DocProject is a documentation generator add-in
113 | DocProject/buildhelp/
114 | DocProject/Help/*.HxT
115 | DocProject/Help/*.HxC
116 | DocProject/Help/*.hhc
117 | DocProject/Help/*.hhk
118 | DocProject/Help/*.hhp
119 | DocProject/Help/Html2
120 | DocProject/Help/html
121 |
122 | # Click-Once directory
123 | publish/
124 |
125 | # Publish Web Output
126 | *.[Pp]ublish.xml
127 | *.azurePubxml
128 | # TODO: Comment the next line if you want to checkin your web deploy settings
129 | # but database connection strings (with potential passwords) will be unencrypted
130 | *.pubxml
131 | *.publishproj
132 |
133 | # NuGet Packages
134 | *.nupkg
135 | # The packages folder can be ignored because of Package Restore
136 | **/packages/*
137 | # except build/, which is used as an MSBuild target.
138 | !**/packages/build/
139 | # If using the old MSBuild-Integrated Package Restore, uncomment this:
140 | #!**/packages/repositories.config
141 |
142 | # Windows Azure Build Output
143 | csx/
144 | *.build.csdef
145 |
146 | # Windows Store app package directory
147 | AppPackages/
148 |
149 | # Others
150 | sql/
151 | *.Cache
152 | ClientBin/
153 | [Ss]tyle[Cc]op.*
154 | ~$*
155 | *~
156 | *.dbmdl
157 | *.dbproj.schemaview
158 | *.pfx
159 | *.publishsettings
160 | node_modules/
161 |
162 | # RIA/Silverlight projects
163 | Generated_Code/
164 |
165 | # Backup & report files from converting an old project file
166 | # to a newer Visual Studio version. Backup files are not needed,
167 | # because we have git ;-)
168 | _UpgradeReport_Files/
169 | Backup*/
170 | UpgradeLog*.XML
171 | UpgradeLog*.htm
172 |
173 | # SQL Server files
174 | *.mdf
175 | *.ldf
176 |
177 | # Business Intelligence projects
178 | *.rdl.data
179 | *.bim.layout
180 | *.bim_*.settings
181 |
182 | # Microsoft Fakes
183 | FakesAssemblies/
184 |
--------------------------------------------------------------------------------
/thirdparty/SimpleMsgPack.Net/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2014, ymofen
2 | All rights reserved.
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions are met:
6 |
7 | * Redistributions of source code must retain the above copyright notice, this
8 | list of conditions and the following disclaimer.
9 |
10 | * Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 |
14 | * Neither the name of SimpleMsgPack.Net nor the names of its
15 | contributors may be used to endorse or promote products derived from
16 | this software without specific prior written permission.
17 |
18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 |
29 |
--------------------------------------------------------------------------------
/thirdparty/SimpleMsgPack.Net/README.md:
--------------------------------------------------------------------------------
1 | SimpleMsgPack.Net
2 | =================
3 |
4 | MessagePack implementation for C# / msgpack.org[C#]
5 |
6 | Binary files distributed via the NuGet package [SimpleMsgPack](http://www.nuget.org/packages/SimpleMsgPack/).
7 |
8 | It's like JSON but small and fast.
9 |
10 | ```
11 | unit Owner: D10.Mofen
12 | contact:
13 | qq:185511468,
14 | email:ymofen@diocp.org
15 | homepage:www.diocp.org
16 | if you find any bug, please contact me!
17 | ```
18 |
19 | Works with
20 | --------
21 | .NET Framework 4.x
22 |
23 |
24 | ### Code Example
25 | ```C#
26 |
27 | MsgPack msgpack = new MsgPack();
28 | msgpack.ForcePathObject("p.name").AsString = "张三";
29 | msgpack.ForcePathObject("p.age").AsInteger = 25;
30 | msgpack.ForcePathObject("p.datas").AsArray.Add(90);
31 | msgpack.ForcePathObject("p.datas").AsArray.Add(80);
32 | msgpack.ForcePathObject("p.datas").AsArray.Add("李四");
33 | msgpack.ForcePathObject("p.datas").AsArray.Add(3.1415926);
34 |
35 | // pack file
36 | msgpack.ForcePathObject("p.filedata").LoadFileAsBytes("C:\\a.png");
37 |
38 | // pack msgPack binary
39 | byte[] packData = msgpack.Encode2Bytes();
40 |
41 | MsgPack unpack_msgpack = new MsgPack();
42 |
43 | // unpack msgpack
44 | unpack_msgpack.DecodeFromBytes(packData);
45 |
46 | System.Console.WriteLine("name:{0}, age:{1}",
47 | unpack_msgpack.ForcePathObject("p.name").AsString,
48 | unpack_msgpack.ForcePathObject("p.age").AsInteger);
49 |
50 | Console.WriteLine("==================================");
51 | System.Console.WriteLine("use index property, Length{0}:{1}",
52 | unpack_msgpack.ForcePathObject("p.datas").AsArray.Length,
53 | unpack_msgpack.ForcePathObject("p.datas").AsArray[0].AsString
54 | );
55 |
56 | Console.WriteLine("==================================");
57 | Console.WriteLine("use foreach statement:");
58 | foreach (MsgPack item in unpack_msgpack.ForcePathObject("p.datas"))
59 | {
60 | Console.WriteLine(item.AsString);
61 | }
62 |
63 | // unpack filedata
64 | unpack_msgpack.ForcePathObject("p.filedata").SaveBytesToFile("C:\\b.png");
65 | Console.Read();
66 |
--------------------------------------------------------------------------------
/thirdparty/SimpleMsgPack.Net/Samples/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/thirdparty/SimpleMsgPack.Net/Samples/Program.cs:
--------------------------------------------------------------------------------
1 | using SimpleMsgPack;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.IO;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace SimpleMsgPackTester
10 | {
11 | class Program
12 | {
13 | static void Test1()
14 | {
15 | MsgPack msgpack = new MsgPack();
16 | msgpack.ForcePathObject("p.name").AsString = "张三一二三四五六七八九十";
17 | msgpack.ForcePathObject("p.age").AsInteger = 132123456874125;
18 | msgpack.ForcePathObject("p.datas").AsArray.Add(90);
19 | msgpack.ForcePathObject("p.datas").AsArray.Add(80);
20 | msgpack.ForcePathObject("p.datas").AsArray.Add("李四");
21 | msgpack.ForcePathObject("p.datas").AsArray.Add(3.1415926);
22 | msgpack.ForcePathObject("Game.iGameID").AsInteger = 1;
23 |
24 | // 可以直接打包文件数据
25 | // msgpack.ForcePathObject("p.filedata").LoadFileAsBytes("C:\\a.png");
26 |
27 | // 打包成msgPack协议格式数据
28 | byte[] packData = msgpack.Encode2Bytes();
29 |
30 | FileStream fs = new FileStream("d:\\simplemsgpack.dat", FileMode.Append);
31 | fs.Write(packData, 0, packData.Length);
32 | fs.Close();
33 |
34 | //Console.WriteLine("msgpack序列化数据:\n{0}", BytesTools.BytesAsHexString(packData));
35 |
36 | MsgPack unpack_msgpack = new MsgPack();
37 | // 从msgPack协议格式数据中还原
38 | unpack_msgpack.DecodeFromBytes(packData);
39 |
40 | System.Console.WriteLine("name:{0}, age:{1}",
41 | unpack_msgpack.ForcePathObject("p.name").AsString,
42 | unpack_msgpack.ForcePathObject("p.age").AsInteger);
43 |
44 | Console.WriteLine("==================================");
45 | System.Console.WriteLine("use index property, Length{0}:{1}",
46 | unpack_msgpack.ForcePathObject("p.datas").AsArray.Length,
47 | unpack_msgpack.ForcePathObject("p.datas").AsArray[0].AsString
48 | );
49 |
50 | Console.WriteLine("==================================");
51 | Console.WriteLine("use foreach statement:");
52 | foreach (MsgPack item in unpack_msgpack.ForcePathObject("p.datas"))
53 | {
54 | Console.WriteLine(item.AsString);
55 | }
56 |
57 | Console.WriteLine(unpack_msgpack.ForcePathObject("Game.iGameID").AsInteger);
58 |
59 | // unpack filedata
60 | //unpack_msgpack.ForcePathObject("p.filedata").SaveBytesToFile("C:\\b.png");
61 | Console.Read();
62 | }
63 |
64 | static void Test2()
65 | {
66 | MsgPack msgpack = new MsgPack();
67 | msgpack.AsString = "张三一二三四五六七八九十";
68 |
69 | // 打包成msgPack协议格式数据
70 | byte[] packData = msgpack.Encode2Bytes();
71 |
72 | FileStream fs = new FileStream("d:\\simplemsgpack11.dat", FileMode.Append);
73 | fs.Write(packData, 0, packData.Length);
74 | fs.Close();
75 |
76 | }
77 |
78 | static void Test3()
79 | {
80 | MsgPack msgpack = new MsgPack();
81 | msgpack.SetAsUInt64(UInt64.MaxValue - 1);
82 |
83 | // 打包成msgPack协议格式数据
84 | byte[] packData = msgpack.Encode2Bytes();
85 |
86 | MsgPack unpack_msgpack = new MsgPack();
87 | // 从msgPack协议格式数据中还原
88 | unpack_msgpack.DecodeFromBytes(packData);
89 |
90 | Console.WriteLine(unpack_msgpack.GetAsUInt64());
91 |
92 | Console.Read();
93 | }
94 | static void Main(string[] args)
95 | {
96 |
97 | Test3();
98 | }
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/thirdparty/SimpleMsgPack.Net/Samples/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // 有关程序集的常规信息通过以下
6 | // 特性集控制。更改这些特性值可修改
7 | // 与程序集关联的信息。
8 | [assembly: AssemblyTitle("SimpleMsgPackTester")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("Microsoft")]
12 | [assembly: AssemblyProduct("SimpleMsgPackTester")]
13 | [assembly: AssemblyCopyright("Copyright © Microsoft 2014")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // 将 ComVisible 设置为 false 使此程序集中的类型
18 | // 对 COM 组件不可见。 如果需要从 COM 访问此程序集中的类型,
19 | // 则将该类型上的 ComVisible 特性设置为 true。
20 | [assembly: ComVisible(false)]
21 |
22 | // 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
23 | [assembly: Guid("a94a604b-38b5-404c-ae67-04ff837d1b14")]
24 |
25 | // 程序集的版本信息由下面四个值组成:
26 | //
27 | // 主版本
28 | // 次版本
29 | // 生成号
30 | // 修订号
31 | //
32 | // 可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值,
33 | // 方法是按如下所示使用“*”:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/thirdparty/SimpleMsgPack.Net/Samples/SimpleMsgPackTester.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {1A73BD27-0B50-4E31-92F7-602EBFCA6941}
8 | Exe
9 | Properties
10 | SimpleMsgPackTester
11 | SimpleMsgPackTester
12 | v4.5
13 | 512
14 |
15 |
16 | AnyCPU
17 | true
18 | full
19 | false
20 | bin\Debug\
21 | DEBUG;TRACE
22 | prompt
23 | 4
24 |
25 |
26 | AnyCPU
27 | pdbonly
28 | true
29 | bin\Release\
30 | TRACE
31 | prompt
32 | 4
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 | {53ced7af-bcf5-453d-ac00-36247752eba8}
53 | SimpleMsgPack
54 |
55 |
56 |
57 |
64 |
--------------------------------------------------------------------------------
/thirdparty/SimpleMsgPack.Net/SimpleMsgPack.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 2013
4 | VisualStudioVersion = 12.0.21005.1
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SimpleMsgPack", "Source\SimpleMsgPack.csproj", "{53CED7AF-BCF5-453D-AC00-36247752EBA8}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SimpleMsgPackTester", "Samples\SimpleMsgPackTester.csproj", "{1A73BD27-0B50-4E31-92F7-602EBFCA6941}"
9 | EndProject
10 | Global
11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
12 | Debug|Any CPU = Debug|Any CPU
13 | Release|Any CPU = Release|Any CPU
14 | EndGlobalSection
15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
16 | {53CED7AF-BCF5-453D-AC00-36247752EBA8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
17 | {53CED7AF-BCF5-453D-AC00-36247752EBA8}.Debug|Any CPU.Build.0 = Debug|Any CPU
18 | {53CED7AF-BCF5-453D-AC00-36247752EBA8}.Release|Any CPU.ActiveCfg = Release|Any CPU
19 | {53CED7AF-BCF5-453D-AC00-36247752EBA8}.Release|Any CPU.Build.0 = Release|Any CPU
20 | {1A73BD27-0B50-4E31-92F7-602EBFCA6941}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21 | {1A73BD27-0B50-4E31-92F7-602EBFCA6941}.Debug|Any CPU.Build.0 = Debug|Any CPU
22 | {1A73BD27-0B50-4E31-92F7-602EBFCA6941}.Release|Any CPU.ActiveCfg = Release|Any CPU
23 | {1A73BD27-0B50-4E31-92F7-602EBFCA6941}.Release|Any CPU.Build.0 = Release|Any CPU
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | EndGlobal
29 |
--------------------------------------------------------------------------------
/thirdparty/SimpleMsgPack.Net/Source/BytesTools.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace SimpleMsgPack
8 | {
9 | public class BytesTools
10 | {
11 | static UTF8Encoding utf8Encode = new UTF8Encoding();
12 |
13 | public static byte[] GetUtf8Bytes(String s)
14 | {
15 |
16 | return utf8Encode.GetBytes(s);
17 | }
18 |
19 | public static String GetString(byte[] utf8Bytes)
20 | {
21 | return utf8Encode.GetString(utf8Bytes);
22 | }
23 |
24 | public static String BytesAsString(byte[] bytes)
25 | {
26 | StringBuilder sb = new StringBuilder();
27 | foreach (byte b in bytes)
28 | {
29 | sb.Append(String.Format("{0:D3} ", b));
30 | }
31 | return sb.ToString();
32 | }
33 |
34 |
35 | public static String BytesAsHexString(byte[] bytes)
36 | {
37 | StringBuilder sb = new StringBuilder();
38 | foreach (byte b in bytes)
39 | {
40 | sb.Append(String.Format("{0:X2} ", b));
41 | }
42 | return sb.ToString();
43 | }
44 |
45 | ///
46 | /// 交换byte数组数据
47 | /// 可用于高低数据交换
48 | ///
49 | /// 要交换的byte数组
50 | /// 返回交换后的数据
51 | public static byte[] SwapBytes(byte[] v)
52 | {
53 | byte[] r = new byte[v.Length];
54 | int j = v.Length - 1;
55 | for (int i = 0; i < r.Length; i++)
56 | {
57 | r[i] = v[j];
58 | j--;
59 | }
60 | return r;
61 | }
62 |
63 | public static byte[] SwapInt64(Int64 v)
64 | {
65 | //byte[] r = new byte[8];
66 | //r[7] = (byte)v;
67 | //r[6] = (byte)(v >> 8);
68 | //r[5] = (byte)(v >> 16);
69 | //r[4] = (byte)(v >> 24);
70 | //r[3] = (byte)(v >> 32);
71 | //r[2] = (byte)(v >> 40);
72 | //r[1] = (byte)(v >> 48);
73 | //r[0] = (byte)(v >> 56);
74 | return SwapBytes(BitConverter.GetBytes(v));
75 | }
76 |
77 | public static byte[] SwapInt32(Int32 v)
78 | {
79 | byte[] r = new byte[4];
80 | r[3] = (byte)v;
81 | r[2] = (byte)(v >> 8);
82 | r[1] = (byte)(v >> 16);
83 | r[0] = (byte)(v >> 24);
84 | return r;
85 | }
86 |
87 |
88 | public static byte[] SwapInt16(Int16 v)
89 | {
90 | byte[] r = new byte[2];
91 | r[1] = (byte)v;
92 | r[0] = (byte)(v >> 8);
93 | return r;
94 | }
95 |
96 | public static byte[] SwapDouble(Double v)
97 | {
98 | return SwapBytes(BitConverter.GetBytes(v));
99 | }
100 |
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/thirdparty/SimpleMsgPack.Net/Source/Consts.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace SimpleMsgPack
8 | {
9 | public enum MsgPackType
10 | {
11 | Unknown = 0,
12 | Null = 1,
13 | Map = 2,
14 | Array = 3,
15 | String = 4,
16 | Integer = 5,
17 | UInt64 = 6,
18 | Boolean = 7,
19 | Float = 8,
20 | Single = 9,
21 | DateTime= 10,
22 | Binary = 11
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/thirdparty/SimpleMsgPack.Net/Source/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace SimpleMsgPack
8 | {
9 | class Program
10 | {
11 | static void Main(string[] args)
12 | {
13 |
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/thirdparty/SimpleMsgPack.Net/Source/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // 有关程序集的常规信息通过以下
6 | // 特性集控制。更改这些特性值可修改
7 | // 与程序集关联的信息。
8 | [assembly: AssemblyTitle("SimpleMsgPack")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("Microsoft")]
12 | [assembly: AssemblyProduct("SimpleMsgPack")]
13 | [assembly: AssemblyCopyright("Copyright © Microsoft 2014")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // 将 ComVisible 设置为 false 使此程序集中的类型
18 | // 对 COM 组件不可见。 如果需要从 COM 访问此程序集中的类型,
19 | // 则将该类型上的 ComVisible 特性设置为 true。
20 | [assembly: ComVisible(false)]
21 |
22 | // 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
23 | [assembly: Guid("a14687ba-e7ef-4b8a-abc9-8d99b4763b02")]
24 |
25 | // 程序集的版本信息由下面四个值组成:
26 | //
27 | // 主版本
28 | // 次版本
29 | // 生成号
30 | // 修订号
31 | //
32 | // 可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值,
33 | // 方法是按如下所示使用“*”:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/thirdparty/SimpleMsgPack.Net/Source/ReadTools.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace SimpleMsgPack
9 | {
10 | class ReadTools
11 | {
12 | public static String ReadString(Stream ms, int len)
13 | {
14 | byte[] rawBytes = new byte[len];
15 | ms.Read(rawBytes, 0, len);
16 | return BytesTools.GetString(rawBytes);
17 | }
18 |
19 | public static String ReadString(Stream ms)
20 | {
21 | byte strFlag =(byte)ms.ReadByte();
22 | return ReadString(strFlag, ms);
23 | }
24 |
25 | public static String ReadString(byte strFlag, Stream ms)
26 | {
27 | //
28 | //fixstr stores a byte array whose length is upto 31 bytes:
29 | //+--------+========+
30 | //|101XXXXX| data |
31 | //+--------+========+
32 | //
33 | //str 8 stores a byte array whose length is upto (2^8)-1 bytes:
34 | //+--------+--------+========+
35 | //| 0xd9 |YYYYYYYY| data |
36 | //+--------+--------+========+
37 | //
38 | //str 16 stores a byte array whose length is upto (2^16)-1 bytes:
39 | //+--------+--------+--------+========+
40 | //| 0xda |ZZZZZZZZ|ZZZZZZZZ| data |
41 | //+--------+--------+--------+========+
42 | //
43 | //str 32 stores a byte array whose length is upto (2^32)-1 bytes:
44 | //+--------+--------+--------+--------+--------+========+
45 | //| 0xdb |AAAAAAAA|AAAAAAAA|AAAAAAAA|AAAAAAAA| data |
46 | //+--------+--------+--------+--------+--------+========+
47 | //
48 | //where
49 | //* XXXXX is a 5-bit unsigned integer which represents N
50 | //* YYYYYYYY is a 8-bit unsigned integer which represents N
51 | //* ZZZZZZZZ_ZZZZZZZZ is a 16-bit big-endian unsigned integer which represents N
52 | //* AAAAAAAA_AAAAAAAA_AAAAAAAA_AAAAAAAA is a 32-bit big-endian unsigned integer which represents N
53 | //* N is the length of data
54 |
55 | byte[] rawBytes = null;
56 | int len = 0;
57 | if ((strFlag >= 0xA0)&&(strFlag<=0xBF))
58 | {
59 | len = strFlag - 0xA0;
60 | }else if (strFlag == 0xD9)
61 | {
62 | len = ms.ReadByte();
63 | }
64 | else if (strFlag == 0xDA)
65 | {
66 | rawBytes = new byte[2];
67 | ms.Read(rawBytes, 0, 2);
68 | rawBytes = BytesTools.SwapBytes(rawBytes);
69 | len = BitConverter.ToInt16(rawBytes, 0);
70 | }
71 | else if (strFlag == 0xDB)
72 | {
73 | rawBytes = new byte[4];
74 | ms.Read(rawBytes, 0, 4);
75 | rawBytes = BytesTools.SwapBytes(rawBytes);
76 | len = BitConverter.ToInt32(rawBytes, 0);
77 | }
78 | rawBytes = new byte[len];
79 | ms.Read(rawBytes, 0, len);
80 | return BytesTools.GetString(rawBytes);
81 | }
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/thirdparty/SimpleMsgPack.Net/changes.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jacking75/edu_GolangSocketGameServer/ff8782cfbf0bd5a321ffbe3fe6716de2f6c80e4e/thirdparty/SimpleMsgPack.Net/changes.txt
--------------------------------------------------------------------------------