This commit is contained in:
aixianling
2025-01-09 17:45:40 +08:00
commit 5c9f1dae4a
3482 changed files with 1146531 additions and 0 deletions

BIN
Gateway/gateway/.DS_Store vendored Normal file

Binary file not shown.

View File

@@ -0,0 +1,62 @@
cmake_minimum_required (VERSION 2.8.12.2)
#项目名
project (gate)
#cmake_policy(SET CMP0015 OLD)
#头文件
include_directories(
./
)
# 源文件及头文件
file(GLOB_RECURSE Gate_CODELIST "${PROJECT_SOURCE_DIR}/*.cc" "${PROJECT_SOURCE_DIR}/*.h")
# 代码分组
#group_by_dir(${PROJECT_SOURCE_DIR}/gateway ${Gate_CODELIST})
#链接库
link_directories( ${Libs_Dir} )
if(MSVC)
set(GAME_LIBRARIES
ws2_32
srv
Mswsock
Dbghelp
Winmm
libmysql
mysqlclient
common
)
else()
set(GAME_LIBRARIES
rt
pthread
mysqlclient
#lua
srv
common
)
endif(MSVC)
# Gate输出目录
SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${PROJECT_SOURCE_DIR}/../../Exec/Gateway)
SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${PROJECT_SOURCE_DIR}/../../Exec/Gateway)
if ( ${CMAKE_BUILD_TYPE} STREQUAL "Release" )
set( _DEBUG 0 )
else ()
set( _DEBUG 1 )
endif()
if ( _DEBUG )
set( EXE_NAME gateway_d )
else()
set( EXE_NAME gateway_r )
endif()
add_executable(${EXE_NAME} ${Gate_CODELIST})
add_dependencies(${EXE_NAME} common)
target_link_libraries(${EXE_NAME} ${GAME_LIBRARIES})

View File

@@ -0,0 +1,2 @@
#include "StdAfx.h"

81
Gateway/gateway/StdAfx.h Normal file
View File

@@ -0,0 +1,81 @@
#define USE_EPOLL false
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "os_def.h"
#include <_ast.h>
#ifndef _MSC_VER
#include <netinet/in.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <sys/errno.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#endif
#include <x_thread.h>
#include <net/base_socket.h>
#include <x_lock.h>
#include <x_tick.h>
#include <container/queue_list.h>
#include "share_util.h"
#include "memory/buffer_allocator.h"
#include "memory/memory_container.hpp"
#include "appitnmsg.h"
#include "data_packet.hpp"
#include "data_packet_reader.hpp"
#include "net/send_packet_pool.h"
#include "net/work_socket.h"
#include "net/net_client.h"
#include "net/server_socket.h"
#include "server_def.h"
#include "gate/gate_proto.h"
#include <stream.h>
#ifdef _MSC_VER
#include "statistic/time_stat.h"
#endif
#include "encrypt/CRC.h"
#include "encrypt/Encrypt.h"
#include "flog/file_logger.h"
#include "second_time.h"
#include "container/static_hash_table.h"
#include <ref_class.hpp>
#include <ref_string.hpp>
#include <time.h>
#include "encrypt/EDPass.h"
extern "C"
{
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
}
#include "luabase/base_lua.h"
#include "luabase/base_lua_config.h"
#include "luabase/script_value.hpp"
#include "luabase/script_value_list.h"
#include "luabase/lua_pre_process.h"
#include "luabase/vsp_def.h"
#include "luabase/base_script.h"
#include "utils/fdop.h"
#include "gate_def.h"
#include "srv/socket_srv.h"
#include "gate_server.h"
#include "config/ws_gate_config.h"
#include "client/client.h"
#include "srv/game_client_mgr.h"
#include "gameworld/game_world_client.h"

View File

@@ -0,0 +1,590 @@
/*
* sha1.cpp
*
* Copyright (C) 1998, 2009
* Paul E. Jones <paulej@packetizer.com>
* All Rights Reserved.
*
*****************************************************************************
* $Id: sha1.cpp 12 2009-06-22 19:34:25Z paulej $
*****************************************************************************
*
* Description:
* This class implements the Secure Hashing Standard as defined
* in FIPS PUB 180-1 published April 17, 1995.
*
* The Secure Hashing Standard, which uses the Secure Hashing
* Algorithm (SHA), produces a 160-bit message digest for a
* given data stream. In theory, it is highly improbable that
* two messages will produce the same message digest. Therefore,
* this algorithm can serve as a means of providing a "fingerprint"
* for a message.
*
* Portability Issues:
* SHA-1 is defined in terms of 32-bit "words". This code was
* written with the expectation that the processor has at least
* a 32-bit machine word size. If the machine word size is larger,
* the code should still function properly. One caveat to that
* is that the input functions taking characters and character arrays
* assume that only 8 bits of information are stored in each character.
*
* Caveats:
* SHA-1 is designed to work with messages less than 2^64 bits long.
* Although SHA-1 allows a message digest to be generated for
* messages of any number of bits less than 2^64, this implementation
* only works with messages with a length that is a multiple of 8
* bits.
*
*/
#include "sha1.h"
/*
* SHA1
*
* Description:
* This is the constructor for the sha1 class.
*
* Parameters:
* None.
*
* Returns:
* Nothing.
*
* Comments:
*
*/
SHA1::SHA1()
{
Reset();
}
/*
* ~SHA1
*
* Description:
* This is the destructor for the sha1 class
*
* Parameters:
* None.
*
* Returns:
* Nothing.
*
* Comments:
*
*/
SHA1::~SHA1()
{
// The destructor does nothing
}
/*
* Reset
*
* Description:
* This function will initialize the sha1 class member variables
* in preparation for computing a new message digest.
*
* Parameters:
* None.
*
* Returns:
* Nothing.
*
* Comments:
*
*/
void SHA1::Reset()
{
Length_Low = 0;
Length_High = 0;
Message_Block_Index = 0;
H[0] = 0x67452301;
H[1] = 0xEFCDAB89;
H[2] = 0x98BADCFE;
H[3] = 0x10325476;
H[4] = 0xC3D2E1F0;
Computed = false;
Corrupted = false;
}
/*
* Result
*
* Description:
* This function will return the 160-bit message digest into the
* array provided.
*
* Parameters:
* message_digest_array: [out]
* This is an array of five unsigned integers which will be filled
* with the message digest that has been computed.
*
* Returns:
* True if successful, false if it failed.
*
* Comments:
*
*/
bool SHA1::Result(unsigned *message_digest_array)
{
int i; // Counter
if (Corrupted)
{
return false;
}
if (!Computed)
{
PadMessage();
Computed = true;
}
for(i = 0; i < 5; i++)
{
message_digest_array[i] = H[i];
}
return true;
}
/*
* Input
*
* Description:
* This function accepts an array of octets as the next portion of
* the message.
*
* Parameters:
* message_array: [in]
* An array of characters representing the next portion of the
* message.
*
* Returns:
* Nothing.
*
* Comments:
*
*/
void SHA1::Input( const unsigned char *message_array,
unsigned length)
{
if (!length)
{
return;
}
if (Computed || Corrupted)
{
Corrupted = true;
return;
}
while(length-- && !Corrupted)
{
Message_Block[Message_Block_Index++] = (*message_array & 0xFF);
Length_Low += 8;
Length_Low &= 0xFFFFFFFF; // Force it to 32 bits
if (Length_Low == 0)
{
Length_High++;
Length_High &= 0xFFFFFFFF; // Force it to 32 bits
if (Length_High == 0)
{
Corrupted = true; // Message is too long
}
}
if (Message_Block_Index == 64)
{
ProcessMessageBlock();
}
message_array++;
}
}
/*
* Input
*
* Description:
* This function accepts an array of octets as the next portion of
* the message.
*
* Parameters:
* message_array: [in]
* An array of characters representing the next portion of the
* message.
* length: [in]
* The length of the message_array
*
* Returns:
* Nothing.
*
* Comments:
*
*/
void SHA1::Input( const char *message_array,
unsigned length)
{
Input((unsigned char *) message_array, length);
}
/*
* Input
*
* Description:
* This function accepts a single octets as the next message element.
*
* Parameters:
* message_element: [in]
* The next octet in the message.
*
* Returns:
* Nothing.
*
* Comments:
*
*/
void SHA1::Input(unsigned char message_element)
{
Input(&message_element, 1);
}
/*
* Input
*
* Description:
* This function accepts a single octet as the next message element.
*
* Parameters:
* message_element: [in]
* The next octet in the message.
*
* Returns:
* Nothing.
*
* Comments:
*
*/
void SHA1::Input(char message_element)
{
Input((unsigned char *) &message_element, 1);
}
/*
* operator<<
*
* Description:
* This operator makes it convenient to provide character strings to
* the SHA1 object for processing.
*
* Parameters:
* message_array: [in]
* The character array to take as input.
*
* Returns:
* A reference to the SHA1 object.
*
* Comments:
* Each character is assumed to hold 8 bits of information.
*
*/
SHA1& SHA1::operator<<(const char *message_array)
{
const char *p = message_array;
while(*p)
{
Input(*p);
p++;
}
return *this;
}
/*
* operator<<
*
* Description:
* This operator makes it convenient to provide character strings to
* the SHA1 object for processing.
*
* Parameters:
* message_array: [in]
* The character array to take as input.
*
* Returns:
* A reference to the SHA1 object.
*
* Comments:
* Each character is assumed to hold 8 bits of information.
*
*/
SHA1& SHA1::operator<<(const unsigned char *message_array)
{
const unsigned char *p = message_array;
while(*p)
{
Input(*p);
p++;
}
return *this;
}
/*
* operator<<
*
* Description:
* This function provides the next octet in the message.
*
* Parameters:
* message_element: [in]
* The next octet in the message
*
* Returns:
* A reference to the SHA1 object.
*
* Comments:
* The character is assumed to hold 8 bits of information.
*
*/
SHA1& SHA1::operator<<(const char message_element)
{
Input((unsigned char *) &message_element, 1);
return *this;
}
/*
* operator<<
*
* Description:
* This function provides the next octet in the message.
*
* Parameters:
* message_element: [in]
* The next octet in the message
*
* Returns:
* A reference to the SHA1 object.
*
* Comments:
* The character is assumed to hold 8 bits of information.
*
*/
SHA1& SHA1::operator<<(const unsigned char message_element)
{
Input(&message_element, 1);
return *this;
}
/*
* ProcessMessageBlock
*
* Description:
* This function will process the next 512 bits of the message
* stored in the Message_Block array.
*
* Parameters:
* None.
*
* Returns:
* Nothing.
*
* Comments:
* Many of the variable names in this function, especially the single
* character names, were used because those were the names used
* in the publication.
*
*/
void SHA1::ProcessMessageBlock()
{
const unsigned K[] = { // Constants defined for SHA-1
0x5A827999,
0x6ED9EBA1,
0x8F1BBCDC,
0xCA62C1D6
};
int t; // Loop counter
unsigned temp; // Temporary word value
unsigned W[80]; // Word sequence
unsigned A, B, C, D, E; // Word buffers
/*
* Initialize the first 16 words in the array W
*/
for(t = 0; t < 16; t++)
{
W[t] = ((unsigned) Message_Block[t * 4]) << 24;
W[t] |= ((unsigned) Message_Block[t * 4 + 1]) << 16;
W[t] |= ((unsigned) Message_Block[t * 4 + 2]) << 8;
W[t] |= ((unsigned) Message_Block[t * 4 + 3]);
}
for(t = 16; t < 80; t++)
{
W[t] = CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);
}
A = H[0];
B = H[1];
C = H[2];
D = H[3];
E = H[4];
for(t = 0; t < 20; t++)
{
temp = CircularShift(5,A) + ((B & C) | ((~B) & D)) + E + W[t] + K[0];
temp &= 0xFFFFFFFF;
E = D;
D = C;
C = CircularShift(30,B);
B = A;
A = temp;
}
for(t = 20; t < 40; t++)
{
temp = CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1];
temp &= 0xFFFFFFFF;
E = D;
D = C;
C = CircularShift(30,B);
B = A;
A = temp;
}
for(t = 40; t < 60; t++)
{
temp = CircularShift(5,A) +
((B & C) | (B & D) | (C & D)) + E + W[t] + K[2];
temp &= 0xFFFFFFFF;
E = D;
D = C;
C = CircularShift(30,B);
B = A;
A = temp;
}
for(t = 60; t < 80; t++)
{
temp = CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3];
temp &= 0xFFFFFFFF;
E = D;
D = C;
C = CircularShift(30,B);
B = A;
A = temp;
}
H[0] = (H[0] + A) & 0xFFFFFFFF;
H[1] = (H[1] + B) & 0xFFFFFFFF;
H[2] = (H[2] + C) & 0xFFFFFFFF;
H[3] = (H[3] + D) & 0xFFFFFFFF;
H[4] = (H[4] + E) & 0xFFFFFFFF;
Message_Block_Index = 0;
}
/*
* PadMessage
*
* Description:
* According to the standard, the message must be padded to an even
* 512 bits. The first padding bit must be a '1'. The last 64 bits
* represent the length of the original message. All bits in between
* should be 0. This function will pad the message according to those
* rules by filling the message_block array accordingly. It will also
* call ProcessMessageBlock() appropriately. When it returns, it
* can be assumed that the message digest has been computed.
*
* Parameters:
* None.
*
* Returns:
* Nothing.
*
* Comments:
*
*/
void SHA1::PadMessage()
{
/*
* Check to see if the current message block is too small to hold
* the initial padding bits and length. If so, we will pad the
* block, process it, and then continue padding into a second block.
*/
if (Message_Block_Index > 55)
{
Message_Block[Message_Block_Index++] = 0x80;
while(Message_Block_Index < 64)
{
Message_Block[Message_Block_Index++] = 0;
}
ProcessMessageBlock();
while(Message_Block_Index < 56)
{
Message_Block[Message_Block_Index++] = 0;
}
}
else
{
Message_Block[Message_Block_Index++] = 0x80;
while(Message_Block_Index < 56)
{
Message_Block[Message_Block_Index++] = 0;
}
}
/*
* Store the message length as the last 8 octets
*/
Message_Block[56] = (Length_High >> 24) & 0xFF;
Message_Block[57] = (Length_High >> 16) & 0xFF;
Message_Block[58] = (Length_High >> 8) & 0xFF;
Message_Block[59] = (Length_High) & 0xFF;
Message_Block[60] = (Length_Low >> 24) & 0xFF;
Message_Block[61] = (Length_Low >> 16) & 0xFF;
Message_Block[62] = (Length_Low >> 8) & 0xFF;
Message_Block[63] = (Length_Low) & 0xFF;
ProcessMessageBlock();
}
/*
* CircularShift
*
* Description:
* This member function will perform a circular shifting operation.
*
* Parameters:
* bits: [in]
* The number of bits to shift (1-31)
* word: [in]
* The value to shift (assumes a 32-bit integer)
*
* Returns:
* The shifted value.
*
* Comments:
*
*/
unsigned SHA1::CircularShift(int bits, unsigned word)
{
return ((word << bits) & 0xFFFFFFFF) | ((word & 0xFFFFFFFF) >> (32-bits));
}

View File

@@ -0,0 +1,90 @@
/*
* sha1.h
*
* Copyright (C) 1998, 2009
* Paul E. Jones <paulej@packetizer.com>
* All Rights Reserved.
*
*****************************************************************************
* $Id: sha1.h 12 2009-06-22 19:34:25Z paulej $
*****************************************************************************
*
* Description:
* This class implements the Secure Hashing Standard as defined
* in FIPS PUB 180-1 published April 17, 1995.
*
* Many of the variable names in this class, especially the single
* character names, were used because those were the names used
* in the publication.
*
* Please read the file sha1.cpp for more information.
*
*/
#ifndef _SHA1_H_
#define _SHA1_H_
class SHA1
{
public:
SHA1();
virtual ~SHA1();
/*
* Re-initialize the class
*/
void Reset();
/*
* Returns the message digest
*/
bool Result(unsigned *message_digest_array);
/*
* Provide input to SHA1
*/
void Input( const unsigned char *message_array,
unsigned length);
void Input( const char *message_array,
unsigned length);
void Input(unsigned char message_element);
void Input(char message_element);
SHA1& operator<<(const char *message_array);
SHA1& operator<<(const unsigned char *message_array);
SHA1& operator<<(const char message_element);
SHA1& operator<<(const unsigned char message_element);
private:
/*
* Process the next 512 bits of the message
*/
void ProcessMessageBlock();
/*
* Pads the current message block to 512 bits
*/
void PadMessage();
/*
* Performs a circular left shift operation
*/
inline unsigned CircularShift(int bits, unsigned word);
unsigned H[5]; // Message digest buffers
unsigned Length_Low; // Message length in bits
unsigned Length_High; // Message length in bits
unsigned char Message_Block[64]; // 512-bit message blocks
int Message_Block_Index; // Index into message block array
bool Computed; // Is the digest computed?
bool Corrupted; // Is the message digest corruped?
};
#endif // _SHA1_H_

8
Gateway/gateway/build.sh Normal file
View File

@@ -0,0 +1,8 @@
#!/bin/bash
cd $(cd "$(dirname "$0")" && pwd)
srcDIR=`pwd`
cd $srcDIR/build
cmake ..
make -j2

View File

@@ -0,0 +1,399 @@
#include "StdAfx.h"
#include "client.h"
#include "base/sha1.h"
#include "base64.h"
BaseAllocator Client::alloc("ClientAlloc");
Client::Client(GameClientMgr *cli_mgr, SOCKET s, sockaddr_in* addr) {
shake_hands_ = false;
fd_ = s;
cli_mgr_ = cli_mgr;
send_packet_ = new DataPacket(&alloc);
send_packet_->reserve(SEND_PACKET_MAX);
send_packet_->setLength(0);
memcpy(&remote_addr_, addr, sizeof(sockaddr_in));
net_id_.socket_ = s;
conn_status_ = ConnStatusDef::CS_CONNED;
skey_ = 0;
is_close_ = false;
real_ip[0] = 0;
}
Client ::~Client() {
for (auto it : recv_list_) {
SafeDelete(it);
}
SafeDelete(send_packet_);
recv_list_.clear();
for (auto it : gw_recv_list_) {
SafeDelete(it);
}
real_ip[0] = 0;
}
int Client::SetBlockMode(const bool block) {
unsigned long flag = block ? 0 : 1;
#ifdef _MSC_VER
return ioctlsocket(fd_, FIONBIO, &flag);
#else
return ioctl(fd_, FIONBIO, &flag);//改为非阻塞;
#endif
}
void Client::RecvData(void) {
if (is_close_) return;
static char buf[1024];
while (true) {
int buflen = recv(fd_, buf, sizeof(buf), 0);
if (buflen < 0) {
// 由于是非阻塞的模式,所以当errno为EAGAIN时,表示当前缓冲区已无数据可读
// 在这里就当作是该次事件已处理
#ifdef _MSC_VER
if (WSAGetLastError() == WSAECONNABORTED) {
Close();
return;
} else if (WSAGetLastError() == WSAEWOULDBLOCK) {
#else
if (WSAGetLastError() == EINPROGRESS || WSAGetLastError() == EAGAIN) {
#endif
break;
} else {
MSG_ERR("not handle errno:[%d]%s", WSAGetLastError(), strerror(WSAGetLastError()));
Close();
return;
}
} else if (buflen == 0) {
// 这里表示对端的socket已正常关闭.
Close();
return;
}
if (shake_hands_) {
DataPacket* dp = new DataPacket(&alloc);
dp->writeBuf(buf, buflen);
dp->setPosition(0);
recv_list_.push_back(dp);
} else {
//进行websocket握手
ShakeHandsHandle(buf, buflen);
return;
}
}
}
bool Client::SendData(void) {
size_t splen = send_packet_->getAvaliableLength();
if (splen <= 0) { return true; }
int lsed = send(fd_, send_packet_->getOffsetPtr(), (int)splen, 0);
if(lsed <= 0) { return true; }
if (lsed < splen) {
send_packet_->setPosition(send_packet_->getPosition() + lsed);
return false;
} else {
send_packet_->setLength(0);
}
return true;
}
void Client::WriteEvent(void) {
if (is_close_) return;
DataPacket* dp = NULL;
while (true) {
if (gw_recv_list_.empty()) { break; }
dp = *(gw_recv_list_.begin());
gw_recv_list_.pop_front();
FlushWsPack(dp->getOffsetPtr(), dp->getAvaliableLength());
SafeDelete(dp);
}
if(send_packet_->getAvaliableLength() > 0) {
cli_mgr_->HaveData(this);
}
}
void Client::Flush(const char *buf, size_t len) {
if (send_packet_->getAvaliableLength() + len > SEND_PACKET_MAX) {
MSG_ERR("send packet is max, fd:%d", fd_);
Close();
return;
} else {
size_t pos = send_packet_->getPosition();
send_packet_->setPosition(pos + send_packet_->getAvaliableLength());
send_packet_->writeBuf(buf, len);
send_packet_->setPosition(pos);
}
}
void Client::SendNewSession(void) {
static GameWorldClient* wgc = cli_mgr_->GetGameWorldClient();
DataPacket &dp = wgc->AllocProtoPacket(GM_OPEN,net_id_.socket_,net_id_.index_,net_id_.gate_id_);
if (real_ip[0] != 0)
dp.writeBuf(real_ip, 32);
else
dp.writeBuf(inet_ntoa(remote_addr_.sin_addr), 32);
wgc->flushProtoPacket(dp);
OutputMsg(rmTip, _T("[Login] (2) 握手成功通知LogicServer创建一个玩家Gate gatekey(%d)socket(%lld)GateIdx(%d)LogicIdx(%d)CurrentThreadId(%d)。"),
skey_, net_id_.socket_, net_id_.index_, net_id_.gate_id_, GetCurrentThreadId());
}
void Client::SendSessionClose(void) {
static GameWorldClient* wgc = cli_mgr_->GetGameWorldClient();
DataPacket &dp = wgc->AllocProtoPacket(GM_CLOSE,net_id_.socket_,net_id_.index_,net_id_.gate_id_);
wgc->flushProtoPacket(dp);
}
void Client::Close(void) {
MSG_ERR("close client, fd:%d,index:%d", net_id_.socket_, net_id_.index_);
cli_mgr_->CloseClient(this);
SendSessionClose();
is_close_ = true;
}
#define WEB_SOCKET_HANDS_RE "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: %s\r\n\r\n"
#define MAGIC_KEY "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
void Client::ShakeHandsHandle(const char* buf, int buflen) {
char key[512]; memset(key, 0, 512);
for (int i = 0; i < buflen; ++i)
{
if (FindHttpParam("Sec-WebSocket-Key", buf+i)) {
short k = i + 17, ki = 0;
while(*(buf + k) != '\r' && *(buf + k) != '\n' && *(buf + k) != '\0') {
if (*(buf + k) == ':' || *(buf + k) == ' '){
++k; continue;
} else {
key[ki++] = *(buf + k);
}
++k;
}
break;
}
}
memset(real_ip, 0, sizeof(real_ip));
for (int i = 0; i < buflen; ++i)
{
if (FindHttpParam("X-Real-IP", buf+i)) {
short k = i + 9, ki = 0;
while(*(buf + k) != '\r' && *(buf + k) != '\n' && *(buf + k) != '\0') {
if (*(buf + k) == ':' || *(buf + k) == ' '){
++k; continue;
} else {
real_ip[ki++] = *(buf + k);
}
++k;
}
break;
}
}
//MSG_LOG("key:%s...", key);
memcpy(key + strlen(key), MAGIC_KEY, sizeof(MAGIC_KEY));
//MSG_LOG("megerkey:%s...", key);
//求哈希1
SHA1 sha;
unsigned int message_digest[5];
sha.Reset();
sha << key;
sha.Result(message_digest);
for (int i = 0; i < 5; i++) {
message_digest[i] = htonl(message_digest[i]);
}
memset(key, 0, 512);
base64_encode(key, reinterpret_cast<const char*>(message_digest), 20);
char http_res[512] = "";
sprintf(http_res, WEB_SOCKET_HANDS_RE, key);
Flush(http_res, strlen(http_res));
//MSG_LOG("res:%s...",http_res);//fkYTdNEVkParesYkrM4S
SendData();
shake_hands_ = true;
SendNewSession();//发送到gameworld新增连接
}
void Client::PacketHandle(void) {
if (is_close_) return;
while (!recv_list_.empty()) {
auto dpit = recv_list_.begin();
DataPacket* dp = *dpit;
//读取websocket固定包头
if (!ws_head_.rh) {
//这个包不够一个头部的大小
if (dp->getAvaliableLength() < 2) {
if (MergePacketList(dpit)) continue;
else break;
}
//读取
uint8_t head = 0;
dp->readBuf(&head, 1);
ws_head_.fin = head >> 7;
ws_head_.opcode = head & 0xF;
dp->readBuf(&head, 1);
ws_head_.len = head & 0x7F;
ws_head_.mask = head >> 7;
ws_head_.rh = 1;//标记头部读取完成
}
//读取长度
if (!ws_head_.rl) {
uint8_t nsize = ws_head_.GetLenNeedByte();
if (nsize) {
//这个包不够一个长度
if (dp->getAvaliableLength() < nsize) {
if (MergePacketList(dpit)) continue;
else break;
}
if (nsize == 2) {
(*dp) >> ws_head_.ex_len.v16;
ws_head_.ex_len.v16 = ntohs(ws_head_.ex_len.v16);
} else {
(*dp) >> ws_head_.ex_len.v32;
ws_head_.ex_len.v32 = ntohl((u_long)ws_head_.ex_len.v32);
}
}
ws_head_.rl = 1;
}
//读取MKEY
if (!ws_head_.rk) {
if (ws_head_.mask) {
//这个包不够一个key
if (dp->getAvaliableLength() < 4) {
if (MergePacketList(dpit)) continue;
else break;
}
(*dp) >> ws_head_.mkey[0];
(*dp) >> ws_head_.mkey[1];
(*dp) >> ws_head_.mkey[2];
(*dp) >> ws_head_.mkey[3];
}
ws_head_.rk = 1;
}
//读取数据段
uint64_t data_len = ws_head_.GetLen();
if (dp->getAvaliableLength() < data_len) {
if (MergePacketList(dpit)) continue;
else break;
}
if (ws_head_.mask) {
char* dptr = dp->getOffsetPtr();
for (size_t i = 0; i < data_len; ++i) {
dptr[i] = dptr[i] ^ ws_head_.mkey[i % 4];
}
}
if (!OnRecv(dp->getOffsetPtr(), data_len)) {
return;
}
ws_head_.reset();
dp->adjustOffset(data_len);
//这个包读取完了
if (dp->getAvaliableLength() <= 0) {
recv_list_.pop_front();
SafeDelete(dp);
}
}
}
bool Client::OnRecv(const char* buf, size_t size) {
if (conn_status_ == CS_COMMUNICATE) {
if (ws_head_.opcode == OPCODE_CLR) {
Close();
return false;
}
if (size < 4 + 2) {
MSG_ERR("size is min");
return true;
}
//截去key
unsigned short tag = *((unsigned short*)buf);
if (tag != skey_) {
Close();
return false;
}
char* pdata = (char*)buf + sizeof(unsigned short);
size -= 2;
//截去验证
uint32_t check = *((uint32_t*)pdata);
pdata = pdata + sizeof(uint32_t);
size -= 4;
//发送给游戏服
static GameWorldClient* wgc = cli_mgr_->GetGameWorldClient();
DataPacket &pack = wgc->AllocProtoPacket(GM_DATA,net_id_.socket_,net_id_.index_,net_id_.gate_id_);
#ifdef _DEBUG
const unsigned char* proto = pdata;
OutputMsg(rmTip, "<[sock:%d,idx:%d] Recv(%d,%d)", fd_, GetSessionId(), *proto, *(proto+1));
#endif
pack.writeBuf(pdata, size);
wgc->flushProtoPacket(pack);
//MSG_ERR("size is [%d + 4 + 2]", size);
return true;
}
if (conn_status_ == CS_CONNED) { //刚连接上来
uint32_t tag = *((uint32_t*)buf);
if (tag != DEFAULT_TAG) {
Close();
return false;
}
skey_ = wrand(SHRT_MAX);
FlushWsPack((char *)&skey_, 2);
SendData();
conn_status_ = CS_COMMUNICATE;
}
return true;
}
void Client::FlushWsPack(const char* buf, size_t size) {
static DataPacket pack(&alloc);
pack.setLength(0);
pack << (uint8_t)0x82;//写头部
//写长度
if (size >= 126) {//7位放不下
if (size <= 0xFFFF) {//16位放
pack << (uint8_t)126;
pack << (uint16_t)htons((u_short)size);
} else {//64位放
pack << (uint8_t)127;
pack << (uint64_t)OrderSwap64(size);
}
} else {
pack << (uint8_t)size;
}
//写数据
pack.writeBuf(buf, size);
pack.setPosition(0);
Flush(pack.getOffsetPtr(), pack.getAvaliableLength());
}
void Client::OnGameWorldRecv(const char* buf, size_t size) {
DataPacket *dp = new DataPacket(&alloc);
(*dp) << (uint16_t)skey_;
#ifdef _DEBUG
const unsigned char* proto = buf;
OutputMsg(rmTip, ">[sock:%d,idx:%d] Send(%d,%d)", fd_, GetSessionId(), *proto, *(proto+1));
#endif
dp->writeBuf(buf, size);
dp->setPosition(0);
gw_recv_list_.push_back(dp);
}
bool Client::MergePacketList(std::list<DataPacket*>::iterator &dpit) {
auto sdpit = dpit++;
if (dpit == recv_list_.end()) return false;
DataPacket* sdp = *sdpit;
//合并第二个到第一个
sdp->writeBuf((*dpit)->getOffsetPtr(), (*dpit)->getAvaliableLength());
SafeDelete((*dpit));
recv_list_.erase(dpit);
return true;
}
bool Client::FindHttpParam(const char * param, const char * buf) {
while (*param == *buf) {
if (*(param + 1) == '\0') return true;
++param; ++buf;
}
return false;
}

View File

@@ -0,0 +1,106 @@
#pragma once
#include <list>
#define SEND_PACKET_MAX 1024*1024*8
#define DEFAULT_TAG 0xCA0FFFFF
enum WebSocketOpcode { //操作码定义类型
OPCODE_MID = 0x0,//标识一个中间数据包
OPCODE_TXT = 0x1,//标识一个text类型数据包
OPCODE_BIN = 0x2,//标识一个binary类型数据包
//0x3 - 7保留
OPCODE_CLR = 0x8,//标识一个断开连接类型数据包
OPCODE_PIN = 0x9,//标识一个ping类型数据包
OPCODE_PON = 0xA,//表示一个pong类型数据包
};
#pragma pack(push,1)
struct WebSocketHead {
uint8_t fin : 1;//标识是否为此消息的最后一个数据包
uint8_t rsv1 : 1;//保留位1
uint8_t rsv2 : 1;//保留位2
uint8_t rsv3 : 1;//保留位3
uint8_t opcode : 4;//操作码
uint8_t mask : 1; //是否需要掩码
uint8_t len : 7;//长度
union {
uint16_t v16;//长度为126时
uint32_t v32;//长度为127时
} ex_len;
uint8_t mkey[4];
uint8_t rh : 1;//head读取完成
uint8_t rl : 1;//len读取完成
uint8_t rk : 1;//mkey读取完成
uint8_t rs : 5;//扩展保留
WebSocketHead(void) { reset(); }
void reset(void) { memset(this,0,sizeof(WebSocketHead)); }
inline uint32_t GetLen(void) {
if (len == 126) {
return ex_len.v16;
} else if (len == 127) {
return ex_len.v32;
}
return len;
}
inline uint8_t GetLenNeedByte(void) {
if (len == 126) {
return 2;
} else if (len == 127) {
return 8;
}
return 0;
}
};
#pragma pack(pop)
enum ConnStatusDef {
CS_CONNED,//连接上
CS_COMMUNICATE,//通信状态
};
typedef std::list<DataPacket*> DataPacketList;
class Client {
public:
Client(GameClientMgr *cli_mgr, SOCKET s, sockaddr_in* addr);
~Client();
//设置阻塞模式。true表示阻塞false表示非阻塞返回值为socket错误号0表示成功
int SetBlockMode(const bool block);
void SetSessionId(const uint16_t sid) { net_id_.index_ = sid; }
uint16_t GetSessionId(void) { return net_id_.index_; }
NetId &GetNetId(void) { return net_id_; }
void RecvData(void);
bool SendData(void);
void WriteEvent(void);
void Flush(const char *buf, size_t len);
void SendNewSession(void);
void SendSessionClose(void);
void Close(void);
bool OnRecv(const char* buf, size_t size);
void FlushWsPack(const char* buf, size_t size);
void OnGameWorldRecv(const char* buf, size_t size);
inline SOCKET GetFd(void) { return fd_; }
inline bool IsClose(void) { return is_close_; }
void PacketHandle(void);
uint16_t GetSKey() { return skey_; }
protected:
void ShakeHandsHandle(const char* buf, int buflen);
private:
inline bool MergePacketList(std::list<DataPacket*>::iterator &dpit);
bool FindHttpParam(const char* param, const char* buf);
bool shake_hands_;//是否已经握手
SOCKET fd_; //套接字
bool is_close_; //是否已经关闭连接
sockaddr_in remote_addr_;//远程地址
DataPacketList recv_list_;//收到的包列表
DataPacket* send_packet_;//需要发包的缓冲区
DataPacketList gw_recv_list_;//从游戏服收到的包列表
WebSocketHead ws_head_;//包头
NetId net_id_;
uint8_t conn_status_;//连接状态
uint16_t skey_;//服务端KEY
static BaseAllocator alloc;
GameClientMgr* cli_mgr_;
char real_ip[64];
};

View File

@@ -0,0 +1,67 @@
#include "StdAfx.h"
#include "client_obj_mgr.h"
#include <map>
ClientObjMgr::ClientObjMgr() {
cur_idx_ = 0;
max_session_ = 0;
}
ClientObjMgr::~ClientObjMgr() {
flush();
for (auto cli:client_list_) {
SafeDelete(cli.second);
}
client_list_.clear();
}
void ClientObjMgr::SetMaxSession(int max_session) {
max_session_ = max_session;
}
bool ClientObjMgr::setNewClient(Client *cli) {
client_lock_.Lock();
if (max_session_ <= cur_idx_) return false;
uint16_t index = 0;
if (free_cli_idx_.empty()) {
index = cur_idx_++;
} else {
index = free_cli_idx_.front();
free_cli_idx_.pop_front();
}
cli->SetSessionId(index);
client_append_list_.push_back(cli);
client_lock_.Unlock();
return true;
}
void ClientObjMgr::flush(void) {
client_lock_.Lock();
for (auto it:client_append_list_) {
client_list_.insert(std::make_pair(it->GetSessionId(), it));
}
client_append_list_.clear();
client_lock_.Unlock();
}
Client* ClientObjMgr::get(uint16_t index) {
auto it = client_list_.find(index);
if (it == client_list_.end()) return NULL;
return it->second;
}
Client * ClientObjMgr::remove(uint16_t index) {
auto it = client_list_.find(index);
if (it == client_list_.end()) return NULL;
Client *cli = it->second;
client_list_.erase(it);
client_lock_.Lock();
if (index == cur_idx_ - 1) {
--cur_idx_;
} else {
free_cli_idx_.push_back(index);
}
client_lock_.Unlock();
return cli;
}

View File

@@ -0,0 +1,24 @@
#pragma once
#include <map>
class ClientObjMgr {
public:
ClientObjMgr();
~ClientObjMgr();
void SetMaxSession(int max_session);
bool setNewClient(Client *cli);
void flush(void);
std::map<uint16_t, Client*> &getClientMap(void) {
return client_list_;
}
Client* get(uint16_t index);
Client* remove(uint16_t index);
private:
uint16_t max_session_;//<2F><><EFBFBD><EFBFBD><EFBFBD>ͻ<EFBFBD><CDBB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
uint16_t cur_idx_;
std::list<uint16_t> free_cli_idx_;//<2F><><EFBFBD>еĿͻ<C4BF><CDBB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
std::vector<Client*> client_append_list_;
Mutex client_lock_; //<2F>ͻ<EFBFBD><CDBB><EFBFBD><EFBFBD>б<EFBFBD><D0B1><EFBFBD><EFBFBD><EFBFBD>append_list<73><74>
std::map<uint16_t, Client*> client_list_;
};

View File

@@ -0,0 +1,78 @@
#include "StdAfx.h"
#include "ws_gate_config.h"
const char WsGateConfig::ConfigFileName[] = ("GateWay.txt");
WsGateConfig::WsGateConfig(){
}
WsGateConfig::~WsGateConfig() {
}
void WsGateConfig::showError(const char* err) {
SetErrDesc(err);
RefString s = ("[Config Error]");
s += err;
throw s;
}
bool WsGateConfig::loadServerConfig(GateServer * gate_srv)
{
using namespace stream;
MemoryStream ms(NULL);
try {
if (ms.loadFromFile(ConfigFileName) <= 0) {
showError("unable to load config from file GateWay.txt");
return false;
}
if (!setScript((const char*)ms.getMemory())) {
showError("parse config script failed");
return false;
}
if (openGlobalTable("GateServer")) {
if (enumTableFirst()) {
char str[32];
GameClientMgr* gcmgr = NULL;
do {
if (openFieldTable("LocalService")) {
getFieldStringBuffer(("ServerName"), str, sizeof(str));
gcmgr = gate_srv->AddGameClientMgr(str);
getFieldStringBuffer(("Address"), str, sizeof(str));
gcmgr->SetServiceHost(str);
int port = getFieldInt("Port");
gcmgr->SetServicePort(port);
gcmgr->SetMaxSession(getFieldInt("MaxSession"));
closeTable();
}
if (gcmgr && openFieldTable("BackServer")) {
getFieldStringBuffer(("Host"), str, sizeof(str));
int port = getFieldInt("Port");
gcmgr->InitGameWorldClient(str, port);
closeTable();
}
} while (enumTableNext());
}
closeTable();
}
} catch (RefString& s) {
OutputMsg(rmNormal, s.rawStr());
} catch (...) {
MSG_ERR("unexpected error on load config");
}
return true;
}

View File

@@ -0,0 +1,18 @@
#pragma once
class BaseLuaConfig;
class WsGateConfig :
public BaseLuaConfig {
public:
WsGateConfig();
~WsGateConfig();
static const char ConfigFileName[]; //定义配置文件名称
//加载并读取服务器服务配置
bool loadServerConfig(GateServer *gate_srv);
protected:
void showError(const char* err);
};

View File

@@ -0,0 +1,18 @@
#include "StdAfx.h"
#include "base_event.h"
BaseEvent::BaseEvent(GameClientMgr* cli_mgr)
:cli_mgr_(cli_mgr) {
}
BaseEvent::~BaseEvent()
{
}
bool BaseEvent::init(void) {
return true;
}
void BaseEvent::RunOne(void) {
}

View File

@@ -0,0 +1,16 @@
#pragma once
class BaseEvent
{
public:
BaseEvent(GameClientMgr* cli_mgr);
~BaseEvent();
virtual bool init(void);
virtual void RunOne(void);
virtual void AddReadFd(SOCKET fd, void *ptr = NULL) {}
virtual void DelFd(SOCKET fd, void *ptr = NULL) {}
virtual void AddWriteFd(SOCKET fd, void *ptr = NULL) {}
protected:
GameClientMgr* cli_mgr_;
};

View File

@@ -0,0 +1,52 @@
#include "StdAfx.h"
#include "epoll_event.h"
#ifndef _MSC_VER
EpollEvent::EpollEvent(GameClientMgr* cli_mgr) : BaseEvent(cli_mgr) {
epollfd_ = 0;
listen_fd_ = 0;
}
EpollEvent::~EpollEvent() {
if (epollfd_) {
close(epollfd_);
}
}
bool EpollEvent::init(void) {
epollfd_ = epoll_create(EPOLLEVENTS);
return true;
}
void EpollEvent::RunOne(void) {
int ret = epoll_wait(epollfd_, events_, EPOLLEVENTS, 0);
for (int i = 0; i < ret; i++) {
if (Client *ptr = (Client*)events_[i].data.ptr)
{
if (events_[i].events & EPOLLIN) {
cli_mgr_->HandleReadEvent(ptr->GetFd(), ptr);
} else if (events_[i].events & EPOLLOUT) {
cli_mgr_->HandleWriteEvent(ptr->GetFd(), ptr);
}
}
}
}
void EpollEvent::AddReadFd(SOCKET fd, void *ptr) {
struct epoll_event ev;
ev.events = EPOLLIN;
ev.data.ptr = ptr;
epoll_ctl(epollfd_, EPOLL_CTL_ADD, fd, &ev);
}
void EpollEvent::DelFd(SOCKET fd, void *ptr) {
epoll_ctl(epollfd_, EPOLL_CTL_DEL, fd, NULL);
}
void EpollEvent::AddWriteFd(SOCKET fd, void *ptr) {
struct epoll_event ev;
ev.events = EPOLLIN | EPOLLOUT;
ev.data.ptr = ptr;
epoll_ctl(epollfd_, EPOLL_CTL_MOD, fd, &ev);
}
#endif

View File

@@ -0,0 +1,22 @@
#pragma once
#ifndef _MSC_VER
#include "base_event.h"
#include <sys/epoll.h>
#define EPOLLEVENTS 1024
class EpollEvent :
public BaseEvent {
public:
EpollEvent(GameClientMgr* cli_mgr);
~EpollEvent();
virtual bool init(void);
virtual void RunOne(void);
virtual void AddReadFd(SOCKET fd, void *ptr = NULL);
virtual void DelFd(SOCKET fd, void *ptr = NULL);
virtual void AddWriteFd(SOCKET fd, void *ptr = NULL);
private:
SOCKET epollfd_;
SOCKET listen_fd_;
struct epoll_event events_[EPOLLEVENTS];
};
#endif

View File

@@ -0,0 +1,13 @@
#include "StdAfx.h"
#include "select_event.h"
SelectEvent::SelectEvent(GameClientMgr* cli_mgr) : BaseEvent(cli_mgr){
}
SelectEvent::~SelectEvent() {
}
void SelectEvent::RunOne(void) {
cli_mgr_->ProssClient();
}

View File

@@ -0,0 +1,11 @@
#pragma once
#include "base_event.h"
#include <map>
class SelectEvent : public BaseEvent {
public:
typedef std::map<SOCKET, void*> FdPtrMap;
SelectEvent(GameClientMgr* cli_mgr);
~SelectEvent();
virtual void RunOne(void);
};

View File

@@ -0,0 +1,144 @@
#include "StdAfx.h"
#include "game_world_client.h"
GameWorldClient::GameWorldClient(GateServer* serv, GameClientMgr* gcmgr, const char* name) :
NetClient(name),
serv_(serv),
gcmgr_(gcmgr) {
SetClientName(name);
free_.setLock(&lock_);
}
GameWorldClient::~GameWorldClient() {
free_.flush();
for (int i = 0; i < free_.count(); i++)
{
DataPacket* dp = free_[i];
dp->setPosition(0);
Flush(*dp);
}
free_.clear();
}
void GameWorldClient::OnRecv(const uint16_t cmd, char * buf, int size)
{
GATEMSGHDR* hdr = (GATEMSGHDR*)buf;
buf = (char*)(hdr + 1);
switch (cmd) {
case GM_DATA: {
//NetId net_id;
//net_id.socket_ = hdr->nSocket;
//net_id.index_ = hdr->wSessionIdx;
//net_id.gate_id_ = hdr->wServerIdx;
DataPacket *dp = AllocPostPacket();
dp->writeBuf(buf , size);
dp->setPosition(0);
GateInterMsg msg;
msg.msg_id_ = gcGWData;
msg.data_.index_ = hdr->wSessionIdx;
msg.data_.packet_ = dp;
gcmgr_->PostMsg(msg);
break;
}
case GM_CLOSE: {
GateInterMsg msg;
msg.msg_id_ = gcGWClose;
msg.data_.index_ = hdr->wSessionIdx;
gcmgr_->PostMsg(msg);
break;
}
case GM_SERVERUSERINDEX: {
GateInterMsg msg;
msg.msg_id_ = gcServerIdx;
msg.data_.idx_ = hdr->wSessionIdx;
msg.data_.para_ = hdr->wServerIdx;
gcmgr_->PostMsg(msg);
break;
}
case GM_CHECKCLIENT: {
break;
}
default:
MSG_LOG("not handle gameword cmd:%d", cmd);
break;
}
}
void GameWorldClient::OnChannelMsg(char* buf, int size) {
Channel info = *((Channel*)buf);
switch (info.type) {
case ccBroadCast: {
uint8_t nsize = sizeof(Channel);
DataPacket *dp = AllocPostPacket();
dp->writeBuf(buf + nsize, size - nsize);
dp->setPosition(0);
GateInterMsg msg;
msg.msg_id_ = gcChBro;
msg.data_.b_channel_ = info.channelId;
msg.data_.b_para_ = info.para;
msg.data_.dp_ = dp;
gcmgr_->PostMsg(msg);
break;
}
case ccAddUser: {
GateInterMsg msg;
msg.msg_id_ = gcChAdd;
msg.data_.channel_ = info.channelId;
msg.data_.para_ = info.para;
msg.data_.idx_ = info.index_;
gcmgr_->PostMsg(msg);
break;
}
case ccDelUser: {
GateInterMsg msg;
msg.msg_id_ = gcChDel;
msg.data_.channel_ = info.channelId;
msg.data_.para_ = info.para;
msg.data_.idx_ = info.index_;
gcmgr_->PostMsg(msg);
break;
}
default:
MSG_LOG("not handle channel type:%d", info.type);
break;
}
}
int GameWorldClient::GetLocalServerType() {
return SrvDef::GateServer;
}
const char * GameWorldClient::GetLocalServerName() {
return gcmgr_->GetServiceName();
}
void GameWorldClient::OnDisconnected() {
GateInterMsg msg;
msg.msg_id_ = gcGWDisconn;
gcmgr_->PostMsg(msg);
}
void GameWorldClient::FreeBackUserDataPacket(DataPacket* pack) {
free_.append(pack);
}
DataPacket* GameWorldClient::AllocPostPacket()
{
if (free_.count() <= 0)
{
free_.flush();
}
if (free_.count() <= 0)
{
AllocSendPack(&free_, 512);
}
DataPacket* dp = free_.pop();//<2F>õ<EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD>е<EFBFBD>Datapacket
dp->setLength(0);
return dp;
}

View File

@@ -0,0 +1,34 @@
#pragma once
struct Channel {
int type;// == 0 ? ccAddUser : ccDelUser;
int channelId;
int para;
int index_;
};
class GameWorldClient :
public NetClient
{
public:
GameWorldClient(GateServer* serv, GameClientMgr* gcmgr, const char* name);
~GameWorldClient();
// 回收空闲的CDataPacket类
void FreeBackUserDataPacket(DataPacket* pack);
protected:
// 以下是实现基类的虚函数
virtual void OnRecv(const uint16_t cmd, char* buf, int size);
void OnChannelMsg(char* buf, int size);
virtual int GetLocalServerType();
/* 查询本地服务器的名称,以便正确的发送注册数据 */
virtual const char* GetLocalServerName();
virtual void OnDisconnected();
private:
// 分配一个包,这个包传递给游戏主逻辑处理
DataPacket* AllocPostPacket();
private:
QueueList<DataPacket*> free_; //用来存放空闲的数据包
Mutex lock_;
GateServer* serv_;
GameClientMgr* gcmgr_;
};

View File

@@ -0,0 +1,12 @@
#pragma once
#include <syscall.h>
#define GetCurrentThreadId() syscall(SYS_gettid)
#define MSG_LOG(format, ...) OutputMsg(rmNormal, "[%s:%d %s] "#format, __FILE__, __LINE__, __FUNCTION__,##__VA_ARGS__);
#define MSG_WAR(format, ...) OutputMsg(rmWarning, "[%s:%d %s] "#format, __FILE__, __LINE__, __FUNCTION__,##__VA_ARGS__);
#define MSG_TIP(format, ...) OutputMsg(rmTip, "[%s:%d %s] "#format, __FILE__, __LINE__, __FUNCTION__,##__VA_ARGS__);
#define MSG_ERR(format, ...) OutputMsg(rmError, "[%s:%d %s] "#format, __FILE__, __LINE__, __FUNCTION__,##__VA_ARGS__);
#define OrderSwap16(A) (((uint16_t)(A) >> 8) | ((uint16_t)(A & 0xFF) << 8))
#define OrderSwap32(A) (OrderSwap16((uint32_t)(A) >> 16) | ((uint32_t)(OrderSwap16(A)) << 16))
#define OrderSwap64(A) (OrderSwap32((uint64_t)(A) >> 32) | ((uint64_t)(OrderSwap32(A)) << 32));

View File

@@ -0,0 +1,38 @@
#include "StdAfx.h"
GateServer::GateServer() {
GateServer::Instance = this;
GetSystemTime(cur_sys_time_);
now_sec_.encode(cur_sys_time_);
}
GateServer::~GateServer() {
for (auto gcmgr : game_client_mgr_) {
SafeDelete(gcmgr);
}
game_client_mgr_.clear();
}
bool GateServer::StartServer() {
MSG_LOG("start server...................");
for (auto gcmgr : game_client_mgr_) {
gcmgr->Startup();
}
return true;
}
void GateServer::StopServer() {
MSG_LOG("stop server................... start");
for (auto gcmgr : game_client_mgr_) {
gcmgr->Stop();
}
MSG_LOG("stop server................... ok");
}
GameClientMgr* GateServer::AddGameClientMgr(const char *name)
{
GameClientMgr* gcmgr = new GameClientMgr(name, this);
gcmgr->SetServiceName(name);
game_client_mgr_.push_back(gcmgr);
return gcmgr;
}

View File

@@ -0,0 +1,31 @@
#pragma once
class GameClientMgr;
class GateServer {
public:
GateServer();
~GateServer();
//启动服务器
bool StartServer();
//停止服务器
void StopServer();
//获取同步的逻辑短日期时间值
inline unsigned int getMiniDateTime() {
GetSystemTime(cur_sys_time_);
now_sec_.encode(cur_sys_time_);
return now_sec_;
}
GameClientMgr* AddGameClientMgr(const char *name);
public:
static GateServer* Instance;
private:
std::vector<GameClientMgr*> game_client_mgr_;//游戏客户端管理类
SYSTEMTIME cur_sys_time_;
SecondTime now_sec_; //当前短日期时间
};

148
Gateway/gateway/main.cc Normal file
View File

@@ -0,0 +1,148 @@
#include "StdAfx.h"
#include <signal.h>
void Exit() {
#ifdef _MLIB_DUMP_MEMORY_LEAKS_
_CrtDumpMemoryLeaks();
#endif
}
#ifdef _MSC_VER
const char szExceptionDumpFile[] = ".\\wsgate.dmp";
#endif
bool SetupLogicServerConfig(GateServer* gate_srv);
void ServerMain();
GateServer* GateServer::Instance = NULL;
void sighup_handler(int) {
MSG_TIP("log the perfermance ");
MemoryCounter::getSingleton().logToFile();
}
bool runing = false;
void sigterm_handler(int arg) {
sighup_handler(arg);
runing = false;
}
int main(int argc, char** argv) {
winitseed((unsigned int)time(NULL));
#ifdef _MSC_VER
//初始化网络库
int err = WorkSocket::InitSocketLib();
if (err) {
MSG_ERR("initialize inet library failure");
return 0;
}
SetMiniDumpFlag(MiniDumpWithFullMemory, szExceptionDumpFile);
SetUnhandledExceptionFilter(DefaultUnHandleExceptionFilter);
#else
//改为正确的启动目录
const int MAX_PATH = 256;
char startDir[MAX_PATH];
FDOP::ExtractFileDirectory(argv[1], startDir, MAX_PATH - 1);
//merge
char dir[MAX_PATH];
if (startDir[0] == '/') {
SNPRINTFA(dir, MAX_PATH - 1, "%s", startDir);
} else {
char p[MAX_PATH];
getcwd(p, MAX_PATH - 1);
SNPRINTFA(dir, MAX_PATH - 1, "%s/%s", p, startDir);
}
int err = chdir(dir);
printf("chdir:%s, ret:%d\n", dir, err);
//daemon(1, 0);
#endif
InitDefMsgOut();
#ifdef _MSC_VER
TimeProfMgr::getSingleton().InitMgr();
#endif
ServerMain();
MemoryCounter::getSingleton().logToFile();
#ifdef _MSC_VER
TimeProfMgr::getSingleton().clear();
WorkSocket::UnintSocketLib();
#endif
MemoryCounter::getSingleton().clear();
UninitDefMsgOut();
return 0;
}
void ServerMain() {
//设置窗口标题
#ifdef _MSC_VER
SetConsoleTitle("gateway");
#endif
char logpath[256] = "./log/";
if (!FDOP::FileExists(logpath)) {
FDOP::DeepCreateDirectory(logpath);
}
FileLogger flog(("./log/gateway"));
GateServer::Instance = new GateServer();
if (SetupLogicServerConfig(GateServer::Instance)) {
if (GateServer::Instance->StartServer()) {
MSG_TIP("===========================");
MSG_TIP("gateway start ok");
MSG_TIP("quit:stop server and exit");
MSG_TIP("===========================");
#ifndef _MSC_VER
runing = true;
signal(SIGTERM, sigterm_handler);
signal(SIGPIPE, SIG_IGN);
signal(SIGHUP, sighup_handler);
#endif
while (true) {
#ifdef _MSC_VER
char cmd_buf[512];
//gets(cmd_buf);
scanf("%s", cmd_buf);
if (cmd_buf == NULL || *cmd_buf == 0) {
Sleep(500);
continue;
}
if (strncmp(cmd_buf, ("\\q"), 2) == 0
|| strncmp(cmd_buf, ("exit"), 4) == 0
|| strncmp(cmd_buf, ("quit"), 4) == 0) {
sighup_handler(0);
MSG_TIP("stop gate...");
break;
} else if (strncmp(cmd_buf, "spf", 3) == 0) {
sighup_handler(0);
} else if (strncmp(cmd_buf, "dmp", 3) == 0) {
DebugBreak();
}
#else
if (!runing) break;
#endif
Sleep(10);
}
GateServer::Instance->StopServer();
} else {
MSG_ERR("Press Any Key To Exit...\n");
getc(stdin);
}
}
delete GateServer::Instance;
MSG_LOG("delete GateServer::Instance");
}
bool SetupLogicServerConfig(GateServer* gate_srv) {
WsGateConfig config;
return config.loadServerConfig(gate_srv);
}

View File

@@ -0,0 +1,235 @@
#include "StdAfx.h"
#include <map>
#include "client/client_obj_mgr.h"
#include "event/select_event.h"
#include "event/epoll_event.h"
GameClientMgr::GameClientMgr(const char *name, GateServer *srv) {
srv_ = srv;
gw_cli_ = new GameWorldClient(srv, this, name);
cli_obj_mgr_ = new ClientObjMgr();
inner_msg_list_.setLock(&inner_msg_lock_);
#if USE_EPOLL
event_ = new EpollEvent(this);
#else
event_ = new SelectEvent(this);
#endif
}
GameClientMgr::~GameClientMgr() {
cli_obj_mgr_->flush();
SafeDelete(cli_obj_mgr_);
inner_msg_list_.flush();
inner_msg_list_.clear();
SafeDelete(gw_cli_);
}
void GameClientMgr::SetMaxSession(int max_session) {
cli_obj_mgr_->SetMaxSession(max_session);
}
void GameClientMgr::InitGameWorldClient(const char * ip, int port) {
gw_cli_ = new GameWorldClient(srv_, this, GetServiceName());
gw_cli_->UseBaseAlloc(true);
gw_cli_->SetHost(ip);
gw_cli_->SetPort(port);
}
bool GameClientMgr::onConnect(SOCKET nSocket, sockaddr_in * pAddrIn) {
if (!gw_cli_->connected()) return false;
Client *cli = new Client(this, nSocket, pAddrIn);
cli_obj_mgr_->setNewClient(cli);
cli_obj_mgr_->flush();
cli->SetBlockMode(false);
GateInterMsg msg;
msg.msg_id_ = gcAddClient;
msg.data_.fd_ = nSocket;
msg.data_.sessidx_ = cli->GetSessionId();
PostMsg(msg);
OutputMsg(rmTip, _T("[Login] (1) 客户端连接上来: gatekey(%d)socket(%lld)GateIdx(%d)LogicIdx(%d)CurrentThreadId(%d)。"),
cli->GetSKey(), nSocket, cli->GetNetId().index_, cli->GetNetId().gate_id_, GetCurrentThreadId());
//MSG_TIP("new client connect fd:%d, sid:%d", cli->GetFd(), cli->GetSessionId());
return true;
}
int GameClientMgr::Run() {
inner_msg_list_.flush();
int count = inner_msg_list_.count();
for (int i = 0; i < count; ++i)
{
GateInterMsg& msg = inner_msg_list_[i];
OnRecvSysMsg(msg);
}
inner_msg_list_.clear();
event_->RunOne();
return count;
}
void GameClientMgr::OnStart() {
MSG_LOG("GameClientMgr::OnStart");
event_->init();
}
void GameClientMgr::OnStop() {
MSG_LOG("GameClientMgr::OnStop");
}
void GameClientMgr::Stop() {
MSG_LOG("%s, start", GetServiceName());
while (gw_cli_->GetPacketCount()) {//这里还有包没发完,导致一致没法停止
gw_cli_->SingleRun();
Sleep(1);
}
gw_cli_->Stop();
Inherited::Stop();
MSG_LOG("%s, ok", GetServiceName());
}
void GameClientMgr::OnRecvSysMsg(GateInterMsg & msg)
{
switch (msg.msg_id_)
{
case gcAddClient:
{
event_->AddReadFd(msg.data_.fd_, cli_obj_mgr_->get(msg.data_.sessidx_));
break;
}
case gcServerIdx:
{
Client* cli = cli_obj_mgr_->get(msg.data_.idx_);
if (cli) {
cli->GetNetId().gate_id_ = msg.data_.para_;
OutputMsg(rmTip, _T("[Login] (5) LogicServer已成功添加玩家Gate gatekey(%d)socket(%lld)GateIdx(%d)LogicIdx(%d)CurrentThreadId(%d)。"),
cli->GetSKey(), cli->GetNetId().socket_, cli->GetNetId().index_, cli->GetNetId().gate_id_, GetCurrentThreadId());
}
break;
}
case gcGWData:
{
Client* cli = cli_obj_mgr_->get(msg.data_.index_);
if (cli) {
auto dp = msg.data_.packet_;
cli->OnGameWorldRecv(dp->getOffsetPtr(), dp->getAvaliableLength());
}
gw_cli_->FreeBackUserDataPacket(msg.data_.packet_);
break;
}
case gcGWClose:
{
Client* cli = cli_obj_mgr_->get(msg.data_.index_);
if (cli) {
cli->Close();
}
break;
}
case gcChAdd:
{
uint64_t key = MAKEINT64(msg.data_.channel_, msg.data_.para_);
channel_indexs_map_[key].insert(msg.data_.idx_);
break;
}
case gcChDel:
{
uint64_t key = MAKEINT64(msg.data_.channel_, msg.data_.para_);
channel_indexs_map_[key].erase(msg.data_.idx_);
break;
}
case gcChBro:
{
uint64_t key = MAKEINT64(msg.data_.b_channel_, msg.data_.b_para_);
auto &list = channel_indexs_map_[key];
for (auto idx:list) {
Client* cli = cli_obj_mgr_->get(idx);
if (cli) {
auto dp = msg.data_.packet_;
cli->OnGameWorldRecv(dp->getOffsetPtr(), dp->getAvaliableLength());
}
}
gw_cli_->FreeBackUserDataPacket(msg.data_.dp_);
break;
}
case gcGWDisconn:
{
CloseAllClient();
break;
}
}
}
void GameClientMgr::ProssClient(void) {
//cli_obj_mgr_->flush();
auto &list = cli_obj_mgr_->getClientMap();
std::vector<uint16_t> remove_list;
for (auto it:list) {
Client *cli = it.second;
if(cli)
{
if (cli->IsClose()) {
remove_list.push_back(cli->GetSessionId());
continue;
}
cli->RecvData();
cli->PacketHandle();
cli->WriteEvent();
cli->SendData();
}
}
for (auto idx: remove_list) {
Client *cli = cli_obj_mgr_->remove(idx);
SafeDelete(cli);
}
remove_list.clear();
}
void GameClientMgr::HandleReadEvent(SOCKET fd, Client * cli) {
if (cli) {
cli->RecvData();
cli->PacketHandle();
event_->AddWriteFd(fd, cli);
}
}
void GameClientMgr::HandleWriteEvent(SOCKET fd, Client * cli) {
if (cli) {
cli->WriteEvent();
if (!cli->SendData()) {
event_->AddWriteFd(fd, cli);
}
}
}
void GameClientMgr::CloseAllClient() {
cli_obj_mgr_->flush();
auto &list = cli_obj_mgr_->getClientMap();
std::vector<uint16_t> remove_list;
for (auto it : list) {
Client *cli = it.second;
cli->Close();
}
}
void GameClientMgr::HaveData(Client * cli) {
if(cli) {
event_->AddWriteFd(cli->GetFd(), cli);
}
}
void GameClientMgr::CloseClient(Client * cli) {
event_->DelFd(cli->GetFd());
closesocket(cli->GetFd());
if (cli_obj_mgr_->get(cli->GetSessionId()))
{
cli_obj_mgr_->remove(cli->GetSessionId());
}
}
bool GameClientMgr::Startup() {
if (!Inherited::Startup()) {
return false;
}
// 创建发送线程
return gw_cli_->Startup();
}

View File

@@ -0,0 +1,95 @@
#pragma once
#include <map>
#include <set>
typedef union GateInterMsgData {
struct {
uint32_t b_channel_;
uint32_t b_para_;
DataPacket* dp_;
};
struct {
uint32_t index_;
DataPacket* packet_;
};
struct {
uint32_t idx_;
uint32_t para_;
uint32_t channel_;
};
struct {
uint32_t sessidx_;
SOCKET fd_;
};
} tagGateInterMsgData;
typedef struct GateInterMsg
{
int msg_id_;
GateInterMsgData data_;
} tagGateInterMsg;
class GameWorldClient;
class BaseEvent;
class SocketSrv;
class ClientObjMgr;
enum {
gcAddClient = 1, //增加一个新的客户端连接
gcGWData = 2, //游戏服给客户端发消息
gcGWClose = 3, //游戏服主动关闭客户端
gcChBro = 4,//频道广播消息
gcChAdd = 5,//频道信息增加
gcChDel = 6,//频道信息删除
gcGWDisconn = 7,//游戏服断开连接
gcServerIdx = 8,//游戏服的玩家对应gateid
};
class GameClientMgr : public SocketSrv {
public:
typedef SocketSrv Inherited;
GameClientMgr(const char *name, GateServer *srv);
~GameClientMgr();
void SetMaxSession(int max_session);
bool Startup();
void InitGameWorldClient(const char *ip, int port);
GameWorldClient* GetGameWorldClient(void) { return gw_cli_; }
virtual bool onConnect(SOCKET nSocket, sockaddr_in* pAddrIn);
//单次逻辑处理
virtual int Run();
virtual void OnStart();
virtual void OnStop();
virtual void Stop();
void PostMsg(GateInterMsg& msg) {
inner_msg_list_.append(msg);
}
void OnRecvSysMsg(GateInterMsg& msg);
//select模式使用
void ProssClient(void);
//epoll模式使用
void HandleReadEvent(SOCKET fd, Client* cli);
void HandleWriteEvent(SOCKET fd, Client* cli);
//断开所有客户端连接
void CloseAllClient();
void HaveData(Client* cli);
void CloseClient(Client *cli);
protected:
GateServer *srv_;
GameWorldClient *gw_cli_;
ClientObjMgr *cli_obj_mgr_;
std::map<uint64_t, std::set<int> > channel_indexs_map_;
QueueList<GateInterMsg> inner_msg_list_;//内部消息列表
Mutex inner_msg_lock_;//内部消息列表锁
BaseEvent *event_;//事件处理
};

View File

@@ -0,0 +1,148 @@
#ifdef _MSC_VER
#include <Windows.h>
#include <process.h>
#else
#include <pthread.h>
#endif
#include "StdAfx.h"
#include "socket_srv.h"
SocketSrv::SocketSrv() {
srv_stoped_ = true;
memset(server_name_, 0, sizeof(server_name_));
#ifdef _MSC_VER
accept_thread_ = NULL;
#else
accept_thread_ = 0;
#endif
accept_exit_ = true;
}
SocketSrv::~SocketSrv()
{
#ifdef _MSC_VER
if (NULL != accept_thread_) {
CloseHandle(accept_thread_);
}
accept_thread_ = NULL;
#else
accept_thread_ = 0;
#endif
}
#ifdef _MSC_VER
void STDCALL SocketSrv::ServerSocketAcceptThreadRoutine(void* arg) {
#else
void * SocketSrv::ServerSocketAcceptThreadRoutine(void * arg) {
#endif
SocketSrv *srv = (SocketSrv*)arg;
struct sockaddr_in server_addr;
SOCKET listen_fd_ = 0;
if ((listen_fd_ = socket(AF_INET, SOCK_STREAM, 0)) == SOCKET_ERROR) {
MSG_ERR("create socket error:%d",errno);
assert(false);
}
#ifdef _MSC_VER
char optval = 1;
#else
int optval = 1;
#endif
if (setsockopt(listen_fd_, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) == SOCKET_ERROR) {
MSG_ERR("setsockopt");
assert(false);
}
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(srv->GetServicePort());
server_addr.sin_addr.s_addr = inet_addr(srv->GetServiceHost());
memset(server_addr.sin_zero, 0, sizeof(server_addr.sin_zero));
if (::bind(listen_fd_, (struct sockaddr *)&server_addr, sizeof(server_addr)) == SOCKET_ERROR) {
MSG_ERR("bind error");
assert(false);
}
if (listen(listen_fd_, 5) == SOCKET_ERROR) {
MSG_ERR("listen error");
assert(false);
}
socklen_t len = sizeof(sockaddr);
do {
sockaddr_in cli_addr;
SOCKET nSocket = accept(listen_fd_, (sockaddr*)&cli_addr, &len);
if (srv->Started() && !srv->onConnect(nSocket, &cli_addr)) {
closesocket(nSocket);
}
} while (srv->Started());
closesocket(listen_fd_);
srv->accept_exit_ = true;
#ifdef _MSC_VER
ExitThread(0);//设置线程退出返回值
#else
return NULL;
#endif
}
void SocketSrv::SetServiceName(const char * sName)
{
_STRNCPY_A(server_name_, sName);
}
void SocketSrv::SetServiceHost(const char * sHost)
{
_STRNCPY_A(host_, sHost);
}
void SocketSrv::SetServicePort(const int nPort) {
port_ = nPort;
}
bool SocketSrv::Startup() {
Inherited:Start();
bool ret = true;
int err = 0;
srv_stoped_ = false;
#ifdef _MSC_VER
accept_thread_ = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ServerSocketAcceptThreadRoutine, this, 0, NULL);
if (!accept_thread_) {
err = GetLastError();
ret = false;
}
#else
if (pthread_create(&accept_thread_, NULL, ServerSocketAcceptThreadRoutine, this)) {
err = errno;
ret = false;
}
#endif
if (!ret) {
MSG_ERR("create listen thread error %d", err);
return false;
}
accept_exit_ = false;
return true;
}
void SocketSrv::Stop() {
if (srv_stoped_) return;
MSG_LOG("start");
srv_stoped_ = true;
// while (!accept_exit_) {
// Sleep(1);
// }
//#ifdef _MSC_VER
// CloseThread(accept_thread_);
//#endif
Inherited::Stop();
MSG_LOG("ok");
}
void SocketSrv::OnRoutine() {
OnStart();
while (!terminated()) {
if (Run() <= 0)
Sleep(1);
}
OnStop();
}

View File

@@ -0,0 +1,55 @@
#pragma once
class SocketSrv : public thread::BaseThread {
public:
typedef thread::BaseThread Inherited;
SocketSrv();
~SocketSrv();
#ifdef _MSC_VER
static void STDCALL ServerSocketAcceptThreadRoutine(void* srv);
#else
static void* ServerSocketAcceptThreadRoutine(void* arg);
#endif
virtual bool onConnect(SOCKET nSocket, sockaddr_in* pAddrIn) = 0;
virtual void OnRoutine();
//单次逻辑处理
virtual int Run() = 0;
virtual void OnStart() = 0;
virtual void OnStop() = 0;
inline const char* GetServiceName()
{
return server_name_;
}
inline const char* GetServiceHost()
{
return host_;
}
inline int GetServicePort()
{
return port_;
}
inline bool Started()
{
return !srv_stoped_;
}
void SetServiceName(const char* sName);
void SetServiceHost(const char* sHost);
void SetServicePort(const int nPort);
bool Startup();
virtual void Stop();
private:
#ifdef _MSC_VER
HANDLE accept_thread_; //接受客户端连接线程
#else
pthread_t accept_thread_;
#endif
bool srv_stoped_; //是否停止工作线程
bool accept_exit_; //监听线程完整退出
char server_name_[256]; //服务名称
char host_[256]; //服务绑定地址
int port_; //服务绑定端口
};