├── LICENSE ├── README.md ├── cppserver ├── App.cpp ├── App.h ├── Connection.cpp ├── Connection.h ├── ConnectionManager.cpp ├── ConnectionManager.h ├── MsgHandler.cpp ├── MsgHandler.h ├── Packet.h ├── ServerConnection.cpp ├── ServerConnection.h ├── SimpleLog.cpp ├── SimpleLog.h ├── StdAfx.h ├── Util.cpp ├── Util.h └── main.cpp ├── index.js ├── lib ├── Int64.js ├── acceptor.js ├── base_define.js ├── base_types.js ├── myutil.js └── socket.js ├── package.json └── test ├── op.js ├── test.proto ├── testChildServer.js ├── testClient.js ├── testMasterServer.js └── testServer.js /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 zhonghua 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 | Episode 2 | ======= 3 | 4 | episode is a gameserver framework based on nodejs 5 | 6 | Pomelo追求的是大而全,Episode追求的是小而精。 7 | 8 | 目前只有网络层的功能。 9 | 10 | 1. 监听端口 11 | 2. 接收数据包 12 | 3. 发送数据包 13 | 4. 检测连接断开等事件 14 | 5. 连接别的网络服务 15 | 6. 搭建分布式服务器时的RPC调用 16 | 17 | --- 18 | 19 | 使用方法参考test下的testServer.js和testClient.js和testClient.js 20 | 21 | 启动测试服务器 22 | 23 | node testServer.js 24 | 25 | 启动测试客户端 26 | 27 | node testClient.js 28 | 29 | --- 30 | 31 | myutil.LOG(...) 32 | 33 | var myutil = require('../lib/myutil'); 34 | myutil.LOG("init "+new Date()); 35 | 36 | --- 37 | 38 | myutil.ERROR(...) 39 | 40 | 同上 41 | 42 | --- 43 | 44 | myutil.CRASH(...) 此方法一般在try catch中使用 45 | 46 | var myutil = require('../lib/myutil'); 47 | try{ 48 | throw Error('error'); 49 | } 50 | catch(e){ 51 | myutil.CRASH(e.stack); 52 | } 53 | 54 | --- 55 | 56 | myutil.cbFunc(...) 函数回调时如果会出现异常,那么用此方法包装 57 | 58 | var myutil = require('../lib/myutil'); 59 | var fs = require('fs'); 60 | fs.read('abc.txt', myutil.cbFunc(function(content){ 61 | if(content[0] != "1"){ throw Error('error'); } 62 | })); 63 | 64 | --- 65 | 66 | Socket 作为客户端发起tcp连接,或者作为服务器接收tcp连接 67 | 68 | // client 69 | var myutil = require('../lib/myutil'); 70 | var Socket = require('../lib/socket'); 71 | var client = new Socket({host: "127.0.0.1", 72 | port: 9527, 73 | client: true, 74 | myutil.cbFunc(function(session, id, buf){ 75 | console.log('recv '+id); 76 | }), 77 | myutil.cbFunc(function(sock){ 78 | if(client != sock){ 79 | throw Error('internal error'); 80 | } 81 | })}); 82 | 83 | // server 84 | var Acceptor = require('../lib/acceptor'); 85 | var server = new Acceptor(9527, myutil.cbFunc(function(sock){ 86 | var client = new Socket({sock: sock, 87 | myutil.cbFunc(function(session, id, buf){ 88 | console.log('recv '+id); 89 | }), 90 | myutil.cbFunc(function(sock){ 91 | if(client != sock){ 92 | throw Error('internal error'); 93 | } 94 | })}); 95 | })); 96 | 97 | 98 | --- 99 | RPC使用实例,参考test/testMasterServer.js与test/testChildServer.js 100 | -------------------------------------------------------------------------------- /cppserver/App.cpp: -------------------------------------------------------------------------------- 1 | #include "StdAfx.h" 2 | 3 | #include "App.h" 4 | #include "MsgHandler.h" 5 | #include "RoomManager.h" 6 | 7 | #include "ConnectionManager.h" 8 | 9 | App* App::s_inst; 10 | App* App::inst() 11 | { 12 | return s_inst?s_inst:(s_inst = new App()); 13 | } 14 | 15 | App::App():m_tick(m_io, boost::posix_time::microsec(TICK_MS)),m_pFSMaster(NULL) 16 | { 17 | 18 | } 19 | 20 | bool App::init() 21 | { 22 | // *log thread 23 | if(!LOGTHREAD_P()->init()) 24 | { 25 | SLOWLOG() << "log thread init false!!!!!!!!!!!!!!!!" << LOGEND(); 26 | return false; 27 | } 28 | SLOWLOG() << "log init OK!" << LOGEND(); 29 | 30 | // *init connection to master 31 | m_pFSMaster = new ServerConnection(m_io); 32 | BaseConfig* bc = Config::get()->getBaseConfig(); 33 | m_pFSMaster->init("127.0.0.1", 1234); 34 | SLOWLOG() << "connection to master init OK!" << LOGEND(); 35 | 36 | m_pFS = new ConnectionManager(m_io, 5678); 37 | 38 | // init msg handler 39 | MsgHandler::init(); 40 | SLOWLOG() << "msg handler init OK!" << LOGEND(); 41 | 42 | return true; 43 | } 44 | 45 | void App::loop() 46 | { 47 | m_tick.async_wait(boost::bind(&App::tick, this, boost::asio::placeholders::error)); 48 | 49 | m_io.run(); 50 | } 51 | 52 | void App::tick(const boost::system::error_code& e) 53 | { 54 | if (boost::asio::error::operation_aborted != e) 55 | { 56 | PTime pStart = Util::getPTime(); 57 | 58 | m_pFSMaster->update(); 59 | m_pFS->update(); 60 | 61 | PTime pEnd = Util::getPTime(); 62 | int duration = Util::getDuration(pEnd, pStart); 63 | 64 | if ( duration <= TICK_MS) 65 | { 66 | m_tick.expires_at(m_tick.expires_at()+boost::posix_time::millisec(TICK_MS-duration)); 67 | } 68 | 69 | m_tick.async_wait(boost::bind(&App::tick, this, boost::asio::placeholders::error)); 70 | } 71 | } 72 | 73 | void App::exit() 74 | { 75 | 76 | } 77 | 78 | ServerConnection* App::getFSMasterConn() 79 | { 80 | return m_pFSMaster; 81 | } 82 | 83 | ConnectionManager* App::getFS() 84 | { 85 | return m_pFS; 86 | } -------------------------------------------------------------------------------- /cppserver/App.h: -------------------------------------------------------------------------------- 1 | #ifndef __FIGHTSERVER_APP_H__ 2 | #define __FIGHTSERVER_APP_H__ 3 | 4 | #include 5 | 6 | #include "ServerConnection.h" 7 | 8 | class ConnectionManager; 9 | 10 | class App 11 | { 12 | public: 13 | static App* inst(); 14 | bool init(); 15 | void loop(); 16 | void exit(); 17 | public: 18 | ServerConnection* getFSMasterConn(); 19 | ConnectionManager* getFS(); 20 | protected: 21 | void tick(const boost::system::error_code& e); 22 | App(); 23 | static App* s_inst; 24 | protected: 25 | boost::asio::io_service m_io; 26 | boost::asio::deadline_timer m_tick; 27 | 28 | ServerConnection* m_pFSMaster; 29 | ConnectionManager* m_pFS; 30 | }; 31 | 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /cppserver/Connection.cpp: -------------------------------------------------------------------------------- 1 | #include "StdAfx.h" 2 | 3 | #include "Connection.h" 4 | #include "MsgHandler.h" 5 | 6 | Connection::Connection(boost::asio::io_service& io_service, int id) 7 | :m_sock(io_service), 8 | m_id(id) 9 | { 10 | m_status = CONN_STATUS_INIT; 11 | m_writeStatus = SW_STATUS_INIT; 12 | 13 | m_errHandler = NULL; 14 | 15 | this->clear(); 16 | } 17 | 18 | void Connection::sendMsg(SendPacket* p) 19 | { 20 | if (m_status != CONN_STATUS_CONNECTED) 21 | { 22 | LOGERROR() << "sendmsg status not connected" 23 | <<"id"<getOPCode(); 28 | std::string body = p->getData(); 29 | 30 | unsigned int pack = (13 << 24) + (body.size() & 0xFFFFFF); 31 | 32 | char header[MSG_HEADER_SIZE] = {0}; 33 | memmove(header, (char*)&opCode, sizeof(opCode)); 34 | memmove(header+sizeof(opCode), (char*)&pack, sizeof(pack)); 35 | 36 | std::stringstream ss; 37 | ss << std::string(header, 6) << body; 38 | m_outData.push_back(ss.str()); 39 | LOGNET() << "try send msg " << opCode << " pack size " << body.size() << LOGEND(); 40 | 41 | tryWrite(); 42 | } 43 | 44 | void Connection::start() 45 | { 46 | m_connSuccTime = Util::getMSTime(); 47 | m_status = CONN_STATUS_CONNECTED; 48 | tryRead(); 49 | } 50 | 51 | void Connection::clear() 52 | { 53 | m_outData.clear(); 54 | m_msgBuffer.clear(); 55 | 56 | memset(m_buffer, 0, sizeof(m_buffer)); 57 | m_offSet = 0; 58 | 59 | m_sock.close(); 60 | } 61 | 62 | Connection::~Connection() 63 | { 64 | clear(); 65 | } 66 | 67 | // return false if not enough buf 68 | bool Connection::getMsgSize(std::string* buf, int size) 69 | { 70 | int tempSize = 0; 71 | std::list::iterator iter = m_msgBuffer.begin(); 72 | for (; iter != m_msgBuffer.end(); ++iter) 73 | { 74 | std::string &temp = *iter; 75 | if (temp.size() <= size - tempSize) 76 | { 77 | tempSize += temp.size(); 78 | buf->append(temp.begin(), temp.end()); 79 | } 80 | else 81 | { 82 | buf->append(temp, 0, (size - tempSize)); 83 | tempSize = size; 84 | break; 85 | } 86 | } 87 | 88 | return tempSize >= size; 89 | } 90 | 91 | void Connection::skipMsgSize(int size) 92 | { 93 | std::list::iterator iter = m_msgBuffer.begin(); 94 | while(size > 0 && iter != m_msgBuffer.end()) 95 | { 96 | std::string &temp = *iter; 97 | if (temp.size() <= size) 98 | { 99 | size -= temp.size(); 100 | iter = m_msgBuffer.erase(iter); 101 | } 102 | else 103 | { 104 | temp.erase(0, size); 105 | size = 0; 106 | break; 107 | } 108 | } 109 | } 110 | 111 | 112 | // trigger read event 113 | void Connection::tryRead() 114 | { 115 | // read 116 | m_sock.async_read_some 117 | ( 118 | boost::asio::buffer(m_buffer+m_offSet, INBUF_MAX_SIZE-m_offSet), 119 | boost::bind 120 | ( 121 | &Connection::handleRead, 122 | this, 123 | boost::asio::placeholders::error, 124 | boost::asio::placeholders::bytes_transferred 125 | ) 126 | ); 127 | } 128 | 129 | // trigger 130 | void Connection::tryWrite() 131 | { 132 | if (m_status != CONN_STATUS_CONNECTED) 133 | { 134 | LOGERROR() << "write status not connected " 135 | <<"id"< 0 && m_writeStatus != SW_STATUS_WRITTING) 140 | { 141 | m_writeStatus = SW_STATUS_WRITTING; 142 | m_tempBuf = m_outData.front(); 143 | m_sock.async_write_some 144 | ( 145 | boost::asio::buffer(m_tempBuf, m_tempBuf.size()), 146 | boost::bind 147 | ( 148 | &Connection::handleWrite, 149 | this, 150 | boost::asio::placeholders::error, 151 | boost::asio::placeholders::bytes_transferred 152 | ) 153 | ); 154 | } 155 | } 156 | 157 | 158 | // get some data 159 | void Connection::handleRead(const boost::system::error_code& error, size_t len) 160 | { 161 | if(!error) 162 | { 163 | LOGNET() << ">>> got " << len << " data from " 164 | <<"id"< 0); 202 | // ok write some chars 203 | //std::string& buf = m_outData.front(); 204 | // first buffer all flushed 205 | if (len == m_tempBuf.length()) 206 | { 207 | LOGNET() << "<<< write full " << len << " " 208 | <<"id"<getBufSize() <= 0) 250 | { 251 | break; 252 | } 253 | std::string header; 254 | bool flag = this->getMsgSize(&header, MSG_HEADER_SIZE); 255 | if (!flag) 256 | { 257 | LOGERROR() << "not enough header" << LOGEND(); 258 | break; 259 | } 260 | else 261 | { 262 | char* buf = &header[0]; 263 | // check msg header 264 | int offset = 0; 265 | short msgID = 0; 266 | memcpy(&msgID, buf, sizeof(msgID)); 267 | 268 | unsigned int pack = 0; 269 | memcpy(&pack, buf+sizeof(msgID), sizeof(pack)); 270 | 271 | int msgSize = pack & 0xFFFFFF; 272 | unsigned int chaos = pack >> 24; 273 | if (chaos != 13) 274 | { 275 | LOGERROR() << "wrong pack chaos " << chaos << " msg " << msgID << " from " 276 | <<"id"<skipMsgSize(msgSize+MSG_HEADER_SIZE); 287 | 288 | body.erase(0, MSG_HEADER_SIZE); 289 | LOGNET() << ">>> got msg " << msgID << " size " << msgSize << LOGEND(); 290 | Packet p(msgID, body); 291 | 292 | MsgHandlerType handler = MsgHandler::getHandler(p.getOP()); 293 | if (handler) 294 | { 295 | bool flag = handler(this, &p); 296 | if (!flag) 297 | { 298 | LOGERROR() << "return false handle " << p.getOP() << LOGEND(); 299 | } 300 | } 301 | else 302 | { 303 | LOGERROR() << "didn't find handler for " << p.getOP() << LOGEND(); 304 | } 305 | } 306 | else 307 | { 308 | LOGNET() << "not enough body need " << msgSize << 309 | " but have " << m_offSet - MSG_HEADER_SIZE << 310 | " msgID=" << msgID << LOGEND(); 311 | } 312 | } 313 | } 314 | } 315 | 316 | void Connection::forceClose() 317 | { 318 | m_sock.close(); 319 | //if (m_writeStatus != SW_STATUS_WRITTING) 320 | //{ 321 | // m_errHandler(boost::system::error_code(), this, "forceClose"); 322 | //} 323 | //else 324 | //{ 325 | // // write callback will call immediately 326 | //} 327 | } -------------------------------------------------------------------------------- /cppserver/Connection.h: -------------------------------------------------------------------------------- 1 | #ifndef __FIGHTSERVER_CONNECTION_H__ 2 | #define __FIGHTSERVER_CONNECTION_H__ 3 | 4 | #include 5 | #include 6 | #include "Packet.h" 7 | using namespace boost::asio; 8 | using boost::asio::ip::tcp; 9 | 10 | class Connection; 11 | typedef boost::function ErrHandler; 12 | 13 | class Connection 14 | { 15 | public: 16 | Connection(boost::asio::io_service& io_service, int id=-1); 17 | ~Connection(); 18 | tcp::socket& socket() { return m_sock; } 19 | int id() { return m_id; } 20 | 21 | void start(); 22 | void clear(); 23 | virtual void sendMsg(SendPacket* p); 24 | virtual void handleRead(const boost::system::error_code& error, size_t len); 25 | virtual void handleWrite(const boost::system::error_code& error, size_t len); 26 | virtual void handlePacket(); 27 | // 28 | virtual void tryRead(); 29 | virtual void tryWrite(); 30 | // 31 | int getBufSize() { return m_msgBuffer.size(); } 32 | bool getMsgSize(std::string* buf, int size); 33 | void skipMsgSize(int size); 34 | // 35 | void setErrHandler(ErrHandler handler) { m_errHandler = handler;} 36 | // 37 | double getConnSuccTime() { return m_connSuccTime; } 38 | CONNECTION_STATUS getStatus() { return m_status; } 39 | void forceClose(); 40 | protected: 41 | CONNECTION_STATUS m_status; 42 | double m_connSuccTime; 43 | ip::tcp::socket m_sock; 44 | int m_id; 45 | 46 | std::list m_msgBuffer; 47 | char m_buffer[INBUF_MAX_SIZE]; // temporary 48 | int m_offSet; 49 | 50 | std::string m_tempBuf; 51 | std::list m_outData; 52 | SOCKET_WRITE_STATUS m_writeStatus; 53 | 54 | ErrHandler m_errHandler; 55 | }; 56 | #endif -------------------------------------------------------------------------------- /cppserver/ConnectionManager.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhuzhonghua/Episode/86626fb87696f9fff4b571a9647ca9d9ae77af7a/cppserver/ConnectionManager.cpp -------------------------------------------------------------------------------- /cppserver/ConnectionManager.h: -------------------------------------------------------------------------------- 1 | #ifndef __CONNECTIONMANAGER_H__ 2 | #define __CONNECTIONMANAGER_H__ 3 | 4 | #include 5 | #include 6 | 7 | #include "Packet.h" 8 | #include "Connection.h" 9 | 10 | using namespace boost::asio; 11 | 12 | class ConnectionManager { 13 | public: 14 | ConnectionManager(boost::asio::io_service& io_service, int port); 15 | ~ConnectionManager(); 16 | public: 17 | void handleAccept(Connection* new_session, const boost::system::error_code& error); 18 | void errHandler(const boost::system::error_code& e, Connection*, std::string dummy); 19 | void update(); 20 | public: 21 | Connection* getConn(int id); 22 | protected: 23 | boost::asio::io_service& m_io_service; 24 | tcp::acceptor acceptor_; 25 | 26 | int m_index; 27 | std::map m_allConns; 28 | int m_port; 29 | 30 | double m_lastUpdateTime; 31 | protected: 32 | void startAccept(); 33 | }; 34 | 35 | #endif -------------------------------------------------------------------------------- /cppserver/MsgHandler.cpp: -------------------------------------------------------------------------------- 1 | #include "StdAfx.h" 2 | 3 | #include "MsgHandler.h" 4 | #include "Packet.h" 5 | 6 | #include "Util.h" 7 | 8 | using namespace com::magetower::op; 9 | std::map MsgHandler::_s_handler; 10 | 11 | void MsgHandler::init() 12 | { 13 | 14 | } 15 | 16 | MsgHandlerType MsgHandler::getHandler(int opCode) 17 | { 18 | std::map::iterator iter = MsgHandler::_s_handler.find(opCode); 19 | if (iter != MsgHandler::_s_handler.end()) 20 | { 21 | return iter->second; 22 | } 23 | else 24 | { 25 | return NULL; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /cppserver/MsgHandler.h: -------------------------------------------------------------------------------- 1 | #ifndef __FIGHTSERVER_MSGHANDLER_H__ 2 | #define __FIGHTSERVER_MSGHANDLER_H__ 3 | 4 | #include 5 | #include "Connection.h" 6 | 7 | class MsgHandler; 8 | class Packet; 9 | 10 | typedef bool (*MsgHandlerType)(Connection*, Packet* p); 11 | 12 | class MsgHandler 13 | { 14 | public: 15 | static void init(); 16 | static MsgHandlerType getHandler(int opCode); 17 | public: 18 | private: 19 | static std::map _s_handler; 20 | }; 21 | 22 | #endif -------------------------------------------------------------------------------- /cppserver/Packet.h: -------------------------------------------------------------------------------- 1 | #ifndef __FIGHTSERVER_PACKET_H__ 2 | #define __FIGHTSERVER_PACKET_H__ 3 | 4 | #include 5 | 6 | class Packet 7 | { 8 | public: 9 | Packet(int opCode, std::string &buf) 10 | { 11 | m_opCode = opCode; 12 | m_strBuf = buf; 13 | } 14 | int getOP() 15 | { 16 | return m_opCode; 17 | } 18 | std::string* getData() 19 | { 20 | return &m_strBuf; 21 | } 22 | private: 23 | int m_opCode; 24 | std::string m_strBuf; 25 | }; 26 | 27 | class SendPacket 28 | { 29 | public: 30 | virtual short getOPCode() = 0; 31 | virtual std::string getData() = 0; 32 | }; 33 | 34 | #define MSG_BEGIN(name, msgName, op) \ 35 | class name : public msgName, public SendPacket \ 36 | { \ 37 | public: \ 38 | short getOPCode(){ return op; } \ 39 | std::string getData(){ return this->SerializeAsString(); } 40 | 41 | #define MSG_END() \ 42 | }; 43 | 44 | #define GETMSG(name, p) \ 45 | name msg; \ 46 | bool okFlag = msg.ParseFromString(*p->getData()); \ 47 | if(okFlag) \ 48 | {\ 49 | LOGNET() << "OK! parse msg " << p->getOP() << " [" << #name << "]" << LOGEND(); \ 50 | }\ 51 | else\ 52 | {\ 53 | LOGERROR() << "Error! parse msg " << p->getOP() << " ["<< #name << "]" << LOGEND(); \ 54 | } 55 | 56 | #endif -------------------------------------------------------------------------------- /cppserver/ServerConnection.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "StdAfx.h" 5 | #include "ServerConnection.h" 6 | 7 | ServerConnection::ServerConnection(boost::asio::io_service& io_service) 8 | :Connection(io_service), 9 | m_tickTimer(io_service) 10 | { 11 | } 12 | 13 | ServerConnection::~ServerConnection() 14 | { 15 | 16 | } 17 | 18 | void ServerConnection::init(std::string ip, int port) 19 | { 20 | m_ip = ip; 21 | m_port = port; 22 | 23 | this->setErrHandler(boost::bind(&ServerConnection::errHandler, this, boost::asio::placeholders::error, _2, _3)); 24 | tryConnect(); 25 | /* 26 | m_tickTimer.expires_from_now(boost::posix_time::seconds(CONNECT_INTERVAL)); 27 | m_tickTimer.async_wait(boost::bind(&ServerConnection::tick, this, boost::asio::placeholders::error));*/ 28 | } 29 | 30 | void ServerConnection::update() 31 | { 32 | switch(m_status) 33 | { 34 | //case CONN_STATUS_INIT: 35 | // break; 36 | ////case CONN_STATUS_CONNECTING: 37 | //// // wait 38 | //// break; 39 | //case CONN_STATUS_CONNECTED: 40 | // // handle command 41 | // handlePacket(); 42 | // break; 43 | //case CONN_STATUS_DISCONNECT: 44 | // { 45 | // tryConnect(); 46 | // } 47 | // break; 48 | } 49 | } 50 | 51 | void ServerConnection::connectHandler(const boost::system::error_code& e) 52 | { 53 | if(!e) 54 | { 55 | LOGNORMAL() << "connect " << m_ip.c_str() << " " << m_port << " OK" << LOGEND(); 56 | //m_status = CONN_STATUS_CONNECTED; 57 | start(); 58 | // send handshake message 59 | 60 | // trigger read 61 | //tryRead(); 62 | 63 | } 64 | else 65 | { 66 | m_status = CONN_STATUS_DISCONNECT; 67 | LOGERROR() << "connect error " << m_ip.c_str() << " " << m_port << LOGEND(); 68 | tryConnect(); 69 | } 70 | } 71 | 72 | void ServerConnection::tick(const boost::system::error_code& e) 73 | { 74 | //if(boost::asio::error::operation_aborted != e) 75 | //{ 76 | // if (CONN_STATUS_DISCONNECT == m_status) 77 | // { 78 | // tryConnect(); 79 | // m_tickTimer.expires_at(m_tickTimer.expires_at()+boost::posix_time::seconds(CONNECT_INTERVAL)); 80 | // m_tickTimer.async_wait(boost::bind(&ServerConnection::tick, this, boost::asio::placeholders::error)); 81 | // } 82 | // else if (CONN_STATUS_CONNECTED == m_status) 83 | // { 84 | // //// send msg hear beat 85 | // //OPSSHeartBeat msg; 86 | // //sendMsg(&msg); 87 | 88 | // //LOGNORMAL() << "send ss heartbeat " << m_ip << " " << m_port << LOGEND(); 89 | // m_tickTimer.expires_at(m_tickTimer.expires_at()+boost::posix_time::seconds(HEARTBEAT_INTERVAL)); 90 | // m_tickTimer.async_wait(boost::bind(&ServerConnection::tick, this, boost::asio::placeholders::error)); 91 | // } 92 | // else 93 | // { 94 | // // just wait 95 | // } 96 | //} 97 | } 98 | 99 | void ServerConnection::errHandler(const boost::system::error_code& e, Connection*, std::string dummy) 100 | { 101 | LOGERROR() << "serverconnection error" 102 | <<"ip"<clear(); 112 | 113 | ip::tcp::endpoint point(ip::address_v4::from_string(m_ip.c_str()), m_port); 114 | m_sock.async_connect(point, boost::bind(&ServerConnection::connectHandler, this, boost::asio::placeholders::error)); 115 | m_status = CONN_STATUS_CONNECTING; 116 | LOGNORMAL() << "trying to connect " << m_ip.c_str() << " " << m_port << LOGEND(); 117 | } 118 | -------------------------------------------------------------------------------- /cppserver/ServerConnection.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhuzhonghua/Episode/86626fb87696f9fff4b571a9647ca9d9ae77af7a/cppserver/ServerConnection.h -------------------------------------------------------------------------------- /cppserver/SimpleLog.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace boost::gregorian; 6 | namespace fs = boost::filesystem; 7 | 8 | #include "StdAfx.h" 9 | #include "SimpleLog.h" 10 | #include 11 | 12 | SimpleLogNormal* SimpleLogNormal::m_instance = NULL; 13 | SimpleLogNet* SimpleLogNet::m_instance = NULL; 14 | SimpleLogTest* SimpleLogTest::m_instance = NULL; 15 | SimpleLogError* SimpleLogError::m_instance = NULL; 16 | SlowLog* SlowLog::m_instance = NULL; 17 | 18 | 19 | SimpleLog::SimpleLog(const char* fileName) 20 | :m_fileName(fileName), 21 | m_bDisplay(true) 22 | { 23 | 24 | } 25 | 26 | // log/logname-2014-7-23.log 27 | std::string SimpleLog::getFileName() 28 | { 29 | date theDay = day_clock::local_day(); 30 | 31 | std::stringstream fileName; 32 | fileName << "log/" << m_fileName 33 | << "-" 34 | << theDay.year() 35 | << "-" 36 | << theDay.month().as_number() 37 | << "-" 38 | << theDay.day() 39 | << ".log"; 40 | 41 | return fileName.str(); 42 | } 43 | 44 | void SimpleLog::getLogContent(std::stringstream* ss) 45 | { 46 | boost::mutex::scoped_lock lock(m_mutex); 47 | 48 | int count = 0; 49 | while(count++ < 10 && m_bufSS.size() > 0) 50 | { 51 | *ss << m_bufSS.front(); 52 | m_bufSS.pop_front(); 53 | } 54 | } 55 | 56 | bool SimpleLog::flushLog() 57 | { 58 | std::stringstream ss; 59 | // no item , just return 60 | if(m_bufSS.size() <= 0) 61 | { 62 | return false; 63 | } 64 | else 65 | { 66 | getLogContent(&ss); 67 | } 68 | 69 | 70 | FILE* p = fopen(getFileName().c_str(), "a"); 71 | fwrite(ss.str().c_str(), ss.str().length(), 1, p); 72 | fclose(p); 73 | 74 | return true; 75 | } 76 | 77 | // check directory log 78 | // check if can append file 79 | bool SimpleLog::init() 80 | { 81 | if (!fs::exists("log")) 82 | { 83 | fs::create_directory("log"); 84 | } 85 | if (!fs::exists("log")) 86 | { 87 | SLOWLOG() << "can't create log directory!!!!!!!" << LOGEND(); 88 | return false; 89 | } 90 | 91 | std::ofstream ofs(getFileName().c_str(), std::ofstream::app); 92 | if (!ofs.is_open()) 93 | { 94 | SLOWLOG() << "can't append " << getFileName().c_str() << "!!!!!!!" << LOGEND(); 95 | return false; 96 | } 97 | 98 | return true; 99 | } 100 | 101 | SimpleLog& SimpleLog::readyToLog() 102 | { 103 | std::stringstream ssBuf; 104 | boost::posix_time::ptime p = boost::posix_time::microsec_clock::local_time(); 105 | ssBuf << "(" << p.time_of_day() << ") "; 106 | *this << ssBuf.str().c_str(); 107 | return *this; 108 | } 109 | 110 | SimpleLogNormal::SimpleLogNormal() 111 | :SimpleLog("normal") 112 | { 113 | 114 | } 115 | 116 | SimpleLogNormal* SimpleLogNormal::get() 117 | { 118 | if(SimpleLogNormal::m_instance) 119 | { 120 | return SimpleLogNormal::m_instance; 121 | } 122 | else 123 | { 124 | return SimpleLogNormal::m_instance = new SimpleLogNormal(); 125 | } 126 | } 127 | 128 | SimpleLogTest::SimpleLogTest() 129 | :SimpleLog("test") 130 | { 131 | //m_bDisplay = false; 132 | } 133 | 134 | SimpleLogTest* SimpleLogTest::get() 135 | { 136 | if(SimpleLogTest::m_instance) 137 | { 138 | return SimpleLogTest::m_instance; 139 | } 140 | else 141 | { 142 | return SimpleLogTest::m_instance = new SimpleLogTest(); 143 | } 144 | } 145 | 146 | SimpleLogNet::SimpleLogNet() 147 | :SimpleLog("net") 148 | { 149 | m_bDisplay = false; 150 | } 151 | 152 | SimpleLogNet* SimpleLogNet::get() 153 | { 154 | if(SimpleLogNet::m_instance) 155 | { 156 | return SimpleLogNet::m_instance; 157 | } 158 | else 159 | { 160 | return SimpleLogNet::m_instance = new SimpleLogNet(); 161 | } 162 | } 163 | 164 | SimpleLogError::SimpleLogError() 165 | :SimpleLog("error") 166 | { 167 | 168 | } 169 | 170 | SimpleLogError* SimpleLogError::get() 171 | { 172 | if(SimpleLogError::m_instance) 173 | { 174 | return SimpleLogError::m_instance; 175 | } 176 | else 177 | { 178 | return SimpleLogError::m_instance = new SimpleLogError(); 179 | } 180 | } 181 | 182 | SlowLog::SlowLog() 183 | :SimpleLog("slow-log") 184 | { 185 | 186 | } 187 | 188 | SlowLog* SlowLog::get() 189 | { 190 | if(SlowLog::m_instance) 191 | { 192 | return SlowLog::m_instance; 193 | } 194 | else 195 | { 196 | return SlowLog::m_instance = new SlowLog(); 197 | } 198 | } 199 | 200 | // flush 201 | void SlowLog::afterLog(const std::string &str) 202 | { 203 | std::ofstream ofs(getFileName().c_str(), std::ofstream::app); 204 | ofs << str; 205 | } 206 | 207 | LogThread* LogThread::s_inst = NULL; 208 | 209 | LogThread::LogThread() 210 | { 211 | m_status = THREAD_STATUS_INIT; 212 | } 213 | 214 | bool LogThread::init() 215 | { 216 | if (!LOGNORMAL_P()->init()) 217 | { 218 | return false; 219 | } 220 | SLOWLOG() << "lognormal init OK!" << LOGEND(); 221 | if (!LOGERROR_P()->init()) 222 | { 223 | return false; 224 | } 225 | SLOWLOG() << "logerror init OK!" << LOGEND(); 226 | 227 | start(); 228 | return true; 229 | } 230 | 231 | void LogThread::start() 232 | { 233 | if(m_status == THREAD_STATUS_RUNNING) 234 | { 235 | return; 236 | } 237 | 238 | m_thread = new boost::thread(boost::bind(&LogThread::run, this)); 239 | m_status = THREAD_STATUS_RUNNING; 240 | 241 | SLOWLOG() << "logthread init OK!" << LOGEND(); 242 | } 243 | 244 | void LogThread::run() 245 | { 246 | while(m_status != THREAD_STATUS_EXIT) 247 | { 248 | std::string bufNormal, bufError; 249 | bool flagNormal = LOGNORMAL_P()->flushLog(); 250 | bool flagError = LOGERROR_P()->flushLog(); 251 | bool flagNet = LOGNET_P()->flushLog(); 252 | bool flagTest = LOGTEST_P()->flushLog(); 253 | if(!flagNormal && !flagError && !flagNet && !flagTest) 254 | { 255 | boost::this_thread::sleep_for(boost::chrono::seconds(1)); 256 | continue; 257 | } 258 | } 259 | } 260 | 261 | LogThread* LogThread::get() 262 | { 263 | if(LogThread::s_inst) 264 | { 265 | return LogThread::s_inst; 266 | } 267 | else 268 | { 269 | return LogThread::s_inst = new LogThread(); 270 | } 271 | } 272 | 273 | void LogThread::exit() 274 | { 275 | m_status = THREAD_STATUS_EXIT; 276 | } -------------------------------------------------------------------------------- /cppserver/SimpleLog.h: -------------------------------------------------------------------------------- 1 | #ifndef __FIGHTSERVER_SIMPLE_LOG_H__ 2 | #define __FIGHTSERVER_SIMPLE_LOG_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #include "BaseDefine.h" 14 | 15 | class SimpleLog 16 | { 17 | public: 18 | template 19 | SimpleLog& operator << (T &s) 20 | { 21 | this->log(s); 22 | return *this; 23 | } 24 | SimpleLog& operator << (const char* s) 25 | { 26 | if(s) 27 | { 28 | this->log(s); 29 | } 30 | return *this; 31 | } 32 | SimpleLog& operator << (const int64 s) 33 | { 34 | this->log(s); 35 | return *this; 36 | } 37 | /*SimpleLog& operator << (const int s) 38 | { 39 | this->log(s); 40 | return *this; 41 | } 42 | SimpleLog& operator << (const unsigned int s) 43 | { 44 | this->log(s); 45 | return *this; 46 | } 47 | SimpleLog& operator << (const short s) 48 | { 49 | this->log(s); 50 | return *this; 51 | } 52 | SimpleLog& operator << (const unsigned short s) 53 | { 54 | this->log(s); 55 | return *this; 56 | } 57 | SimpleLog& operator << (const double s) 58 | { 59 | this->log(s); 60 | return *this; 61 | }*/ 62 | 63 | public: 64 | void getLogContent(std::stringstream* ss); 65 | virtual bool flushLog(); 66 | virtual bool init(); 67 | SimpleLog& readyToLog(); 68 | protected: 69 | virtual void afterLog(const std::string &str) 70 | { 71 | boost::mutex::scoped_lock lock(m_mutex); 72 | m_bufSS.push_back(str); 73 | } 74 | template 75 | void log(T & inst) 76 | { 77 | std::stringstream ssBuf; 78 | ssBuf <<" "<< inst; 79 | 80 | if(m_bDisplay) 81 | std::cout << ssBuf.str(); 82 | 83 | afterLog(ssBuf.str()); 84 | } 85 | std::string getFileName(); 86 | SimpleLog(const char* fileName); 87 | protected: 88 | std::list m_bufSS; 89 | std::string m_fileName; 90 | 91 | boost::mutex m_mutex; 92 | bool m_bDisplay; 93 | }; 94 | 95 | class SimpleLogTest: public SimpleLog 96 | { 97 | public: 98 | static SimpleLogTest* get(); 99 | private: 100 | SimpleLogTest(); 101 | static SimpleLogTest* m_instance; 102 | }; 103 | 104 | class SimpleLogNormal: public SimpleLog 105 | { 106 | public: 107 | static SimpleLogNormal* get(); 108 | private: 109 | SimpleLogNormal(); 110 | static SimpleLogNormal* m_instance; 111 | }; 112 | 113 | class SimpleLogNet: public SimpleLog 114 | { 115 | public: 116 | static SimpleLogNet* get(); 117 | private: 118 | SimpleLogNet(); 119 | static SimpleLogNet* m_instance; 120 | }; 121 | 122 | class SimpleLogError: public SimpleLog 123 | { 124 | public: 125 | static SimpleLogError* get(); 126 | private: 127 | SimpleLogError(); 128 | static SimpleLogError* m_instance; 129 | }; 130 | 131 | class SlowLog: public SimpleLog 132 | { 133 | public: 134 | static SlowLog* get(); 135 | protected: 136 | void afterLog(const std::string &str); 137 | private: 138 | SlowLog(); 139 | static SlowLog* m_instance; 140 | }; 141 | 142 | class LogThread 143 | { 144 | public: 145 | bool init(); 146 | void run(); 147 | void start(); 148 | void exit(); 149 | 150 | static LogThread* get(); 151 | private: 152 | LogThread(); 153 | private: 154 | boost::thread* m_thread; 155 | 156 | THREAD_STATUS m_status; 157 | 158 | static LogThread* s_inst; 159 | }; 160 | #endif -------------------------------------------------------------------------------- /cppserver/StdAfx.h: -------------------------------------------------------------------------------- 1 | #ifndef __FIGHTSERVER_STDAFX_H__ 2 | #define __FIGHTSERVER_STDAFX_H__ 3 | 4 | #include "SimpleLog.h" 5 | #include "Util.h" 6 | 7 | #define LOGNORMAL() ((SimpleLogNormal::get()->readyToLog())) 8 | #define LOGTEST() ((SimpleLogTest::get()->readyToLog())) 9 | #define LOGNET() ((SimpleLogNet::get()->readyToLog())) 10 | #define LOGERROR() ((SimpleLogError::get()->readyToLog())) 11 | #define SLOWLOG() ((SlowLog::get()->readyToLog())) 12 | #define LOGEND() ("\n\n"); 13 | 14 | #define LOGNORMAL_P() SimpleLogNormal::get() 15 | #define LOGERROR_P() SimpleLogError::get() 16 | #define LOGNET_P() SimpleLogNet::get() 17 | #define LOGTEST_P() SimpleLogTest::get() 18 | 19 | #define LOGTHREAD_P() LogThread::get() 20 | 21 | #define ASSERT(a) do \ 22 | { \ 23 | if (!(a)) \ 24 | { \ 25 | *(int*)0=1; \ 26 | } \ 27 | } while (false); 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /cppserver/Util.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "Util.h" 10 | 11 | int Util::getUnixTime() 12 | { 13 | return time(NULL); 14 | } 15 | 16 | int64 Util::getUnixMsTime() 17 | { 18 | return Util::getPTime().time_of_day().total_milliseconds(); 19 | } 20 | 21 | PTime Util::getPTime() 22 | { 23 | return boost::posix_time::microsec_clock::local_time(); 24 | } 25 | 26 | int64 Util::getDuration(PTime p1, PTime p2) 27 | { 28 | boost::posix_time::time_duration p = p1-p2; 29 | return p.total_milliseconds(); 30 | } 31 | 32 | float Util::getDurationMicro(PTime p1, PTime p2) 33 | { 34 | boost::posix_time::time_duration p = p1-p2; 35 | return p.total_microseconds()/(float)1000000; 36 | } 37 | 38 | std::string ts("2000-01-01 00:00:00.001"); 39 | PTime begin(boost::posix_time::time_from_string(ts)); 40 | 41 | double Util::getMSTime() 42 | { 43 | PTime now = boost::posix_time::microsec_clock::local_time(); 44 | 45 | boost::posix_time::time_duration p = now-begin; 46 | return p.total_microseconds()/1000000.0; 47 | } 48 | 49 | boost::minstd_rand fRnd(time(0)); 50 | double Util::getRand(double start, double end) 51 | { 52 | boost::uniform_real<> uni_dist(start,end); 53 | boost::variate_generator > uni(fRnd, uni_dist); 54 | return uni(); 55 | } 56 | 57 | boost::minstd_rand intRnd(time(0)); 58 | int Util::getRand(int start, int end) 59 | { 60 | if (start == end) 61 | { 62 | return start; 63 | } 64 | int random_variable = std::rand(); 65 | return random_variable % (end-start+1) + start; 66 | } -------------------------------------------------------------------------------- /cppserver/Util.h: -------------------------------------------------------------------------------- 1 | #ifndef __FIGHTSERVER_UTIL_H__ 2 | #define __FIGHTSERVER_UTIL_H__ 3 | 4 | #include 5 | 6 | #include "BaseDefine.h" 7 | 8 | typedef boost::posix_time::ptime PTime; 9 | 10 | class Util 11 | { 12 | public: 13 | static int getUnixTime(); 14 | static int64 getUnixMsTime(); 15 | static PTime getPTime(); 16 | // return milisec p1-p2 17 | static int64 getDuration(PTime p1, PTime p2); 18 | static float getDurationMicro(PTime p1, PTime p2); 19 | static double getMSTime(); 20 | 21 | static double getRand(double start, double end); 22 | static int getRand(int start, int end); 23 | }; 24 | #endif -------------------------------------------------------------------------------- /cppserver/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | #include "boost/date_time/gregorian/gregorian.hpp" 8 | #include 9 | 10 | #include "StdAfx.h" 11 | #include "App.h" 12 | 13 | int main() 14 | { 15 | std::srand(std::time(0)); // use current time as seed for random generator 16 | 17 | //getchar(); 18 | if (!App::inst()->init()) 19 | { 20 | std::cout << "app init error!!!!!!!!!!!!!!!!!!!" << std::endl; 21 | return 1; 22 | } 23 | 24 | App::inst()->loop(); 25 | App::inst()->exit(); 26 | 27 | return 0; 28 | } -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var Acceptor = require('./lib/acceptor'); 2 | var myutil = require('./lib/myutil'); 3 | var Socket = require('./lib/socket'); 4 | 5 | 6 | exports.Acceptor = Acceptor; 7 | exports.myutil = myutil; 8 | exports.Socket = Socket; 9 | 10 | -------------------------------------------------------------------------------- /lib/Int64.js: -------------------------------------------------------------------------------- 1 | // Int64.js 2 | // 3 | // Copyright (c) 2012 Robert Kieffer 4 | // MIT License - http://opensource.org/licenses/mit-license.php 5 | 6 | /** 7 | * Support for handling 64-bit int numbers in Javascript (node.js) 8 | * 9 | * JS Numbers are IEEE-754 binary double-precision floats, which limits the 10 | * range of values that can be represented with integer precision to: 11 | * 12 | * 2^^53 <= N <= 2^53 13 | * 14 | * Int64 objects wrap a node Buffer that holds the 8-bytes of int64 data. These 15 | * objects operate directly on the buffer which means that if they are created 16 | * using an existing buffer then setting the value will modify the Buffer, and 17 | * vice-versa. 18 | * 19 | * Internal Representation 20 | * 21 | * The internal buffer format is Big Endian. I.e. the most-significant byte is 22 | * at buffer[0], the least-significant at buffer[7]. For the purposes of 23 | * converting to/from JS native numbers, the value is assumed to be a signed 24 | * integer stored in 2's complement form. 25 | * 26 | * For details about IEEE-754 see: 27 | * http://en.wikipedia.org/wiki/Double_precision_floating-point_format 28 | */ 29 | 30 | // Useful masks and values for bit twiddling 31 | var MASK31 = 0x7fffffff, VAL31 = 0x80000000; 32 | var MASK32 = 0xffffffff, VAL32 = 0x100000000; 33 | 34 | // Map for converting hex octets to strings 35 | var _HEX = []; 36 | for (var i = 0; i < 256; i++) { 37 | _HEX[i] = (i > 0xF ? '' : '0') + i.toString(16); 38 | } 39 | 40 | // 41 | // Int64 42 | // 43 | 44 | /** 45 | * Constructor accepts any of the following argument types: 46 | * 47 | * new Int64(buffer[, offset=0]) - Existing Buffer with byte offset 48 | * new Int64(string) - Hex string (throws if n is outside int64 range) 49 | * new Int64(number) - Number (throws if n is outside int64 range) 50 | * new Int64(hi, lo) - Raw bits as two 32-bit values 51 | */ 52 | var Int64 = module.exports = function(a1, a2) { 53 | if (a1 instanceof Buffer) { 54 | this.buffer = a1; 55 | this.offset = a2 || 0; 56 | } else { 57 | this.buffer = this.buffer || new Buffer(8); 58 | this.offset = 0; 59 | this.setValue.apply(this, arguments); 60 | } 61 | }; 62 | 63 | 64 | // Max integer value that JS can accurately represent 65 | Int64.MAX_INT = Math.pow(2, 53); 66 | 67 | // Min integer value that JS can accurately represent 68 | Int64.MIN_INT = -Math.pow(2, 53); 69 | 70 | Int64.prototype = { 71 | /** 72 | * Do in-place 2's compliment. See 73 | * http://en.wikipedia.org/wiki/Two's_complement 74 | */ 75 | _2scomp: function() { 76 | var b = this.buffer, o = this.offset, carry = 1; 77 | for (var i = o + 7; i >= o; i--) { 78 | var v = (b[i] ^ 0xff) + carry; 79 | b[i] = v & 0xff; 80 | carry = v >> 8; 81 | } 82 | }, 83 | 84 | /** 85 | * Set the value. Takes any of the following arguments: 86 | * 87 | * setValue(string) - A hexidecimal string 88 | * setValue(number) - Number (throws if n is outside int64 range) 89 | * setValue(hi, lo) - Raw bits as two 32-bit values 90 | */ 91 | setValue: function(hi, lo) { 92 | var negate = false; 93 | if (arguments.length == 1) { 94 | if (typeof(hi) == 'number') { 95 | // Simplify bitfield retrieval by using abs() value. We restore sign 96 | // later 97 | negate = hi < 0; 98 | hi = Math.abs(hi); 99 | lo = hi % VAL32; 100 | hi = hi / VAL32; 101 | if (hi > VAL32) throw new RangeError(hi + ' is outside Int64 range'); 102 | hi = hi | 0; 103 | } else if (typeof(hi) == 'string') { 104 | hi = (hi + '').replace(/^0x/, ''); 105 | lo = hi.substr(-8); 106 | hi = hi.length > 8 ? hi.substr(0, hi.length - 8) : ''; 107 | hi = parseInt(hi, 16); 108 | lo = parseInt(lo, 16); 109 | } else { 110 | throw new Error(hi + ' must be a Number or String'); 111 | } 112 | } 113 | 114 | // Technically we should throw if hi or lo is outside int32 range here, but 115 | // it's not worth the effort. Anything past the 32'nd bit is ignored. 116 | 117 | // Copy bytes to buffer 118 | var b = this.buffer, o = this.offset; 119 | for (var i = 7; i >= 0; i--) { 120 | b[o+i] = lo & 0xff; 121 | lo = i == 4 ? hi : lo >>> 8; 122 | } 123 | 124 | // Restore sign of passed argument 125 | if (negate) this._2scomp(); 126 | }, 127 | 128 | /** 129 | * Convert to a native JS number. 130 | * 131 | * WARNING: Do not expect this value to be accurate to integer precision for 132 | * large (positive or negative) numbers! 133 | * 134 | * @param allowImprecise If true, no check is performed to verify the 135 | * returned value is accurate to integer precision. If false, imprecise 136 | * numbers (very large positive or negative numbers) will be forced to +/- 137 | * Infinity. 138 | */ 139 | toNumber: function(allowImprecise) { 140 | var b = this.buffer, o = this.offset; 141 | 142 | // Running sum of octets, doing a 2's complement 143 | var negate = b[0] & 0x80, x = 0, carry = 1; 144 | for (var i = 7, m = 1; i >= 0; i--, m *= 256) { 145 | var v = b[o+i]; 146 | 147 | // 2's complement for negative numbers 148 | if (negate) { 149 | v = (v ^ 0xff) + carry; 150 | carry = v >> 8; 151 | v = v & 0xff; 152 | } 153 | 154 | x += v * m; 155 | } 156 | 157 | // Return Infinity if we've lost integer precision 158 | if (!allowImprecise && x >= Int64.MAX_INT) { 159 | return negate ? -Infinity : Infinity; 160 | } 161 | 162 | return negate ? -x : x; 163 | }, 164 | 165 | /** 166 | * Convert to a JS Number. Returns +/-Infinity for values that can't be 167 | * represented to integer precision. 168 | */ 169 | valueOf: function() { 170 | return this.toNumber(false); 171 | }, 172 | 173 | /** 174 | * Return string value 175 | * 176 | * @param radix Just like Number#toString()'s radix 177 | */ 178 | toString: function(radix) { 179 | return this.valueOf().toString(radix || 10); 180 | }, 181 | 182 | /** 183 | * Return a string showing the buffer octets, with MSB on the left. 184 | * 185 | * @param sep separator string. default is '' (empty string) 186 | */ 187 | toOctetString: function(sep) { 188 | var out = new Array(8); 189 | var b = this.buffer, o = this.offset; 190 | for (var i = 0; i < 8; i++) { 191 | out[i] = _HEX[b[o+i]]; 192 | } 193 | return out.join(sep || ''); 194 | }, 195 | 196 | /** 197 | * Pretty output in console.log 198 | */ 199 | inspect: function() { 200 | return '[Int64 value:' + this + ' octets:' + this.toOctetString(' ') + ']'; 201 | } 202 | }; 203 | -------------------------------------------------------------------------------- /lib/acceptor.js: -------------------------------------------------------------------------------- 1 | var net = require('net'); 2 | var myutil = require('./myutil'); 3 | 4 | var LOG = myutil.LOG; 5 | 6 | function Acceptor(port, cb) 7 | { 8 | this.port = port; 9 | this.server = null; 10 | this.newSockCB = cb; 11 | 12 | this.server = net.createServer(this.newSockCB); 13 | this.server.listen(this.port); 14 | LOG("acceptor init on port="+this.port); 15 | } 16 | 17 | Acceptor.prototype.init = function(){ 18 | } 19 | 20 | module.exports = Acceptor; 21 | -------------------------------------------------------------------------------- /lib/base_define.js: -------------------------------------------------------------------------------- 1 | var define = module.exports = {}; 2 | 3 | define.MSG_HEADER_SIZE = 6; 4 | define.UINT32MAX = 4294967296; -------------------------------------------------------------------------------- /lib/base_types.js: -------------------------------------------------------------------------------- 1 | var UINT32MAX = 4294967296; 2 | var Int64 = require('./Int64'); 3 | 4 | function ByteBuffer(para) 5 | { 6 | this.pos = 0; 7 | // read 8 | if(Buffer.isBuffer(para)){ 9 | this.buffer = para; 10 | } 11 | // write, len 12 | else{ 13 | this.buffer = new Buffer(para); 14 | } 15 | 16 | this.toString = function(){ 17 | return this.buffer.toString('hex', this.pos); 18 | }; 19 | this.readInt8 = function(){ 20 | var value = this.buffer.readInt8(this.pos); 21 | this.pos += 1; 22 | return value; 23 | }; 24 | this.readUInt8 = function(){ 25 | var value = this.buffer.readUInt8(this.pos); 26 | this.pos += 1; 27 | return value; 28 | }; 29 | this.readInt16 = function(){ 30 | var value = this.buffer.readInt16LE(this.pos); 31 | this.pos += 2; 32 | return value; 33 | }; 34 | this.readUInt16 = function(){ 35 | var value = this.buffer.readUInt16LE(this.pos); 36 | this.pos += 2; 37 | return value; 38 | }; 39 | this.readInt32 = function(){ 40 | var value = this.buffer.readInt32LE(this.pos); 41 | this.pos += 4; 42 | return value; 43 | }; 44 | this.readUInt32 = function(){ 45 | var value = this.buffer.readUInt32LE(this.pos); 46 | this.pos += 4; 47 | return value; 48 | }; 49 | this.readFloat = function(){ 50 | var value = this.buffer.readFloatLE(this.pos); 51 | this.pos += 4; 52 | return value; 53 | }; 54 | this.readInt64 = function(){ 55 | var lo = this.buffer.readInt32LE(this.pos); 56 | this.pos += 4; 57 | var hi = this.buffer.readInt32LE(this.pos); 58 | this.pos += 4; 59 | var x = new Int64(hi, lo); 60 | return x.toNumber(true); 61 | }; 62 | this.readUInt64 = function(){ 63 | var value = this.buffer.readUInt32LE(this.pos); 64 | this.pos += 4; 65 | var valueHigh = this.buffer.readUInt32LE(this.pos); 66 | this.pos += 4; 67 | return valueHigh*UINT32MAX+value; 68 | }; 69 | this.readStr = function(len){ 70 | if(len <= 0){ 71 | return ''; 72 | } 73 | else if(this.buffer.length - this.pos >= len){ 74 | var value = this.buffer.toString('utf8', this.pos, this.pos+len); 75 | this.pos += len; 76 | return value; 77 | } 78 | else{ 79 | return null; 80 | } 81 | }; 82 | 83 | /////////////////// 84 | this.writeInt8 = function(value){ 85 | this.buffer.writeInt8(value, this.pos); 86 | this.pos += 1; 87 | }; 88 | this.writeUInt8 = function(value){ 89 | this.buffer.writeUInt8(value, this.pos); 90 | this.pos += 1; 91 | }; 92 | this.writeInt16 = function(value){ 93 | this.buffer.writeInt16LE(value, this.pos); 94 | this.pos += 2; 95 | }; 96 | this.writeUInt16 = function(value){ 97 | this.buffer.writeUInt16LE(value, this.pos); 98 | this.pos += 2; 99 | }; 100 | this.writeInt32 = function(value){ 101 | this.buffer.writeInt32LE(value, this.pos); 102 | this.pos += 4; 103 | }; 104 | this.writeUInt32 = function(value){ 105 | this.buffer.writeUInt32LE(value, this.pos); 106 | this.pos += 4; 107 | }; 108 | this.writeFloat = function(value){ 109 | this.buffer.writeFloatLE(value, this.pos); 110 | this.pos += 4; 111 | }; 112 | this.writeInt64 = function(value){ 113 | var lo = value & 0xffffffff; 114 | var hi = value / UINT32MAX >> 0; 115 | this.buffer.writeInt32LE(lo, this.pos); 116 | this.pos += 4; 117 | this.buffer.writeInt32LE(hi, this.pos); 118 | this.pos += 4; 119 | }; 120 | this.writeUInt64 = function(value){ 121 | this.buffer.writeUInt32LE(value&0xffffffff, this.pos); 122 | this.pos += 4; 123 | value = value >>> 31; 124 | value = value >>> 1; 125 | this.buffer.writeUInt32LE(value, this.pos); 126 | this.pos += 4; 127 | }; 128 | this.writeStr = function(value){ 129 | if(value.length <= 0){ 130 | return; 131 | } 132 | this.buffer.write(value, this.pos, value.length); 133 | this.pos += value.length; 134 | }; 135 | this.writeBuffer = function(value){ 136 | if(value.length <= 0){ 137 | return; 138 | } 139 | value.copy(this.buffer, this.pos); 140 | this.pos += value.length; 141 | }; 142 | } 143 | 144 | exports.ByteBuffer = ByteBuffer; 145 | -------------------------------------------------------------------------------- /lib/myutil.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | var http = require('http'); 3 | var https = require('https'); 4 | var url = require('url'); 5 | var querystring = require('querystring'); 6 | var util = require('util'); 7 | 8 | var LOGS = new Array(); 9 | var ERRORS = new Array(); 10 | 11 | var CRASHS = new Array(); 12 | 13 | var filePre = "log"; 14 | 15 | function LOG(cxt) 16 | { 17 | var d = new Date(); 18 | var cnt = "("+d.getHours()+":"+d.getMinutes()+":"+d.getSeconds()+" "+d.getMilliseconds()+") "+" "+cxt+"\r\n"; 19 | LOGS.push(cnt); 20 | console.log(cnt); 21 | 22 | var filename = filePre+'-'+(d.getMonth()+1)+'-'+d.getDate()+'.log'; 23 | if(LOGS.length <= 1){ 24 | writeLOG(filename, LOGS); 25 | } 26 | } 27 | 28 | function writeLOG(filename, arr) 29 | { 30 | if(arr.length > 0){ 31 | var cnt = arr[0]; 32 | fs.appendFile(filename, cnt, function(err){ 33 | if(err) throw err; 34 | arr.shift(); 35 | setImmediate(function(){ 36 | writeLOG(filename, arr); 37 | }); 38 | }); 39 | } 40 | } 41 | 42 | function ERROR(cxt) 43 | { 44 | var d = new Date(); 45 | var cnt = "("+d.getHours()+":"+d.getMinutes()+":"+d.getSeconds()+" "+d.getMilliseconds()+") [ERROR]"+cxt+"\r\n"; 46 | ERRORS.push(cnt); 47 | console.error(cnt); 48 | 49 | var filename = 'error-'+filePre+'-'+(d.getMonth()+1)+'-'+d.getDate()+'.log'; 50 | if(ERRORS.length <= 1){ 51 | writeLOG(filename, ERRORS); 52 | } 53 | } 54 | 55 | function CRASH(cxt) 56 | { 57 | var d = new Date(); 58 | var cnt = "("+d.getHours()+":"+d.getMinutes()+":"+d.getSeconds()+" "+d.getMilliseconds()+") [CRASH]"+cxt+"\r\n"; 59 | CRASHS.push(cnt); 60 | console.log(cnt); 61 | 62 | var filename = 'crash-'+filePre+'-'+(d.getMonth()+1)+'-'+d.getDate()+'.log'; 63 | if(CRASHS.length <= 1){ 64 | writeLOG(filename, CRASHS); 65 | } 66 | } 67 | 68 | function DEBUG_BYTE(buf) 69 | { 70 | LOG(util.inspect(buf)); 71 | } 72 | 73 | function cbFunc(cb){ 74 | return function(){ 75 | try{ 76 | cb.apply(cb, arguments) 77 | } 78 | catch(e){ 79 | CRASH(e.stack); 80 | } 81 | } 82 | } 83 | 84 | exports.LOG = LOG; 85 | exports.ERROR = ERROR; 86 | exports.CRASH = CRASH; 87 | exports.DEBUG_BYTE = DEBUG_BYTE; 88 | exports.cbFunc = cbFunc; 89 | -------------------------------------------------------------------------------- /lib/socket.js: -------------------------------------------------------------------------------- 1 | var net = require('net'); 2 | 3 | var ByteBuffer = require('./base_types').ByteBuffer; 4 | var DEFINE = require('./base_define'); 5 | 6 | var myutil = require('./myutil'); 7 | var LOG = myutil.LOG; 8 | var ERROR = myutil.ERROR; 9 | var CRASH = myutil.CRASH; 10 | var DEBUG_BYTE = myutil.DEBUG_BYTE; 11 | 12 | function Socket(option) 13 | { 14 | this.option = option; 15 | 16 | this.inData = new Array(); 17 | this.outData = new Array(); 18 | this.writeBuffer = new ByteBuffer(1024); 19 | 20 | this.active = false; 21 | 22 | this.container = null; 23 | 24 | var self = this; 25 | // if client, connect to a address 26 | if(option.client){ 27 | this._sock = net.Socket(); 28 | this._sock.connect(option.port, option.host, function(){ 29 | LOG("connected to "+option.port+" "+option.host); 30 | self.active = true; 31 | option.connSuccCB(self); 32 | }); 33 | this._sockID = option.host+'('+option.port+')'; 34 | } 35 | else{ 36 | this._sock = option.sock; 37 | this.active = true; 38 | 39 | this._sockID = this._sock.remoteAddress+'('+this._sock.remotePort+')'; 40 | } 41 | 42 | this.msgCB = option.msgCB; 43 | this.errCB = option.errCB; 44 | 45 | // TODO: remove from this file 46 | // for game-server's gameclient 47 | this.account = ""; 48 | // end TODO 49 | 50 | this.init(); 51 | 52 | LOG("new socket "+this._sockID); 53 | } 54 | 55 | Socket.prototype.close = function(){ 56 | this.active = false; 57 | this.inData = null; 58 | this.outData = null; 59 | if(this._sock){ 60 | this._sock.destroy(); 61 | } 62 | this._sock = null; 63 | 64 | this._sockID = ''; 65 | 66 | this.account = ''; 67 | }; 68 | 69 | Socket.prototype.id = function(){ 70 | return this._sockID; 71 | }; 72 | 73 | Socket.prototype.sockErr = function(){ 74 | ERROR("sockErr "+this.id()); 75 | this.active = false; 76 | var self = this; 77 | this.errCB(self); 78 | self.close(); 79 | }; 80 | 81 | Socket.prototype.connect = function(ip, port){ 82 | var self = this; 83 | if(this.active == true){ 84 | ERROR("already connected "+this.option.host+" "+this.option.port); 85 | } 86 | }; 87 | 88 | Socket.prototype.init = function(){ 89 | // data is a Buffer, not a string 90 | var self = this; 91 | self._sock.on('data', function (data){ 92 | LOG(self._sockID + ' data recv ' + data.length); 93 | DEBUG_BYTE(data); 94 | self.inData.push(data); 95 | 96 | self.handleInData(); 97 | }); 98 | 99 | self._sock.on('close', function (data){ 100 | LOG(self._sockID + ' sock end'); 101 | //removeSockObj(sockObj); 102 | if(self._sock){ 103 | self.sockErr(); 104 | } 105 | }); 106 | 107 | self._sock.on('error', function (data){ 108 | LOG(self._sockID + ' sock error'); 109 | if(self._sock){ 110 | self.sockErr(); 111 | } 112 | }); 113 | }; 114 | 115 | 116 | // handle msg 117 | Socket.prototype.handleInData = function() 118 | { 119 | var self = this; 120 | var sockObj = self; 121 | 122 | if(self.active == false){ 123 | ERROR("self active false, enter handleInData"); 124 | return; 125 | } 126 | 127 | try{ 128 | //var inBufArray = self.inData; 129 | if(false == self.checkLenData(DEFINE.MSG_HEADER_SIZE)){ 130 | return; 131 | } 132 | var header = self.peekLenData(DEFINE.MSG_HEADER_SIZE); 133 | var msgID = header.readUInt16(); 134 | var msgSize = header.readUInt32(); 135 | 136 | if(false == self.checkLenData(msgSize+DEFINE.MSG_HEADER_SIZE)){ 137 | LOG(sockObj._sockID + ' not enough buffer msgsize='+msgSize+', id='+msgID); 138 | return; 139 | } 140 | 141 | LOG(sockObj._sockID + ' get msg ' + msgID + ' size ' + msgSize); 142 | 143 | self.skipLenData(DEFINE.MSG_HEADER_SIZE); 144 | var msgBody = self.readLenData(msgSize); 145 | 146 | if(false == self.msgCB(self, msgID, msgBody.buffer)){ 147 | ERROR('false!!! handle msg ' + msgID); 148 | } 149 | 150 | if(self.inData && self.inData.length > 0){ 151 | setImmediate(function(){ 152 | self.handleInData(); 153 | }); 154 | } 155 | } 156 | catch(e){ 157 | self.sockErr(); 158 | CRASH(e.stack); 159 | } 160 | }; 161 | 162 | 163 | Socket.prototype.checkLenData = function (len) 164 | { 165 | var bufArray = this.inData; 166 | for(var i = 0; i < bufArray.length; ++i){ 167 | var buf = bufArray[i]; 168 | // ok 169 | if(buf.length >= len){ 170 | return true; 171 | } 172 | // len -= buf.length 173 | else{ 174 | len -= buf.length; 175 | } 176 | } 177 | 178 | return false; 179 | }; 180 | 181 | // read and remove data from buffer array 182 | Socket.prototype.readLenData = function(len) 183 | { 184 | var bufArray = this.inData; 185 | var ret = new Buffer(len); 186 | var offset = 0; 187 | while(bufArray.length > 0){ 188 | var buf = bufArray[0]; 189 | if(buf.length == len){ 190 | buf.copy(ret, offset, 0, buf.length); 191 | bufArray.shift(); 192 | 193 | return new ByteBuffer(ret); 194 | } 195 | else if(buf.length > len){ 196 | buf.copy(ret, offset, 0, len); 197 | // slice source data 198 | bufArray[0] = buf.slice(len); 199 | 200 | return new ByteBuffer(ret); 201 | } 202 | else{ 203 | buf.copy(ret, offset, 0, buf.length); 204 | offset += buf.length; 205 | len -= buf.length; 206 | bufArray.shift(); 207 | } 208 | } 209 | return new ByteBuffer(ret); 210 | }; 211 | 212 | // do not remove data from buffer array 213 | Socket.prototype.peekLenData = function(len) 214 | { 215 | var bufArray = this.inData; 216 | var ret = new Buffer(len); 217 | var offset = 0; 218 | for(var i = 0; i < bufArray.length; ++i){ 219 | var buf = bufArray[i]; 220 | if(buf.length == len){ 221 | buf.copy(ret, offset, 0, buf.length); 222 | 223 | return new ByteBuffer(ret); 224 | } 225 | else if(buf.length > len){ 226 | buf.copy(ret, offset, 0, len); 227 | 228 | return new ByteBuffer(ret); 229 | } 230 | else{ 231 | buf.copy(ret, offset, 0, buf.length); 232 | offset += buf.length; 233 | len -= buf.length; 234 | } 235 | } 236 | return new ByteBuffer(ret); 237 | }; 238 | 239 | // read and remove data from buffer array 240 | Socket.prototype.skipLenData = function(len) 241 | { 242 | var bufArray = this.inData; 243 | while(bufArray.length > 0){ 244 | var buf = bufArray[0]; 245 | if(buf.length == len){ 246 | bufArray.shift(); 247 | return; 248 | } 249 | else if(buf.length > len){ 250 | // slice source data 251 | bufArray[0] = buf.slice(len); 252 | return; 253 | } 254 | else{ 255 | len -= buf.length; 256 | bufArray.shift(); 257 | } 258 | } 259 | }; 260 | 261 | Socket.prototype.sendByteBuffer = function(opcode, bufMsg){ 262 | if(this.active == false){ 263 | return; 264 | } 265 | 266 | var holyMsg = new ByteBuffer(DEFINE.MSG_HEADER_SIZE+bufMsg.length); 267 | 268 | holyMsg.writeUInt16(opcode); 269 | var pack = (DEFINE.PACKET_HEAD << 24 >>> 0) + bufMsg.length; 270 | 271 | holyMsg.writeUInt32(pack); 272 | holyMsg.writeBuffer(bufMsg); 273 | this.outData.push(holyMsg.buffer); 274 | 275 | LOG(this._sockID + ': send msg ' + opcode + ' size ' + bufMsg.length); 276 | 277 | DEBUG_BYTE(holyMsg.buffer); 278 | 279 | this.flushOutData(); 280 | }; 281 | 282 | Socket.prototype.flushOutData = function(){ 283 | var sockObj = this; 284 | var outBuf = sockObj.outData; 285 | if(outBuf && outBuf.length > 0){ 286 | var buf = outBuf[0]; 287 | var ret = this.writeData(buf); 288 | 289 | // send all ok 290 | if(true == ret){ 291 | LOG(sockObj._sockID + ': flush data full ' + buf.length); 292 | outBuf.shift(); 293 | setImmediate(function(){ 294 | sockObj.flushOutData(); 295 | }); 296 | } 297 | // wait 298 | else if(false == ret){ 299 | setImmediate(function(){ 300 | sockObj.flushOutData(); 301 | }); 302 | } 303 | // send partial 304 | else{ 305 | LOG(sockObj._sockID + ': flush data partial ' + ret); 306 | outBuf[0] = buf.slice(ret); 307 | setImmediate(function(){ 308 | sockObj.flushOutData(); 309 | }); 310 | } 311 | } 312 | }; 313 | 314 | // check if there any data pending 315 | Socket.prototype.writeData = function(data){ 316 | var sock = this._sock; 317 | if(sock.bufferSize > 0){ 318 | return false; 319 | } 320 | else{ 321 | // return ok 322 | if(true == sock.write(data)){ 323 | return true; 324 | } 325 | // or queue buffer size 326 | else{ 327 | return sock.bufferSize; 328 | } 329 | } 330 | }; 331 | 332 | module.exports = Socket; 333 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "episodegameserver", 3 | "version": "0.0.0", 4 | "description": "Episode =======", 5 | "main": "index.js", 6 | "directories": { 7 | "test": "test" 8 | }, 9 | "dependencies": { 10 | "cli-color": "^0.3.2", 11 | "protobufjs": "^3.4.0" 12 | }, 13 | "devDependencies": {}, 14 | "scripts": { 15 | "test": "echo \"Error: no test specified\" && exit 1" 16 | }, 17 | "repository": { 18 | "type": "git", 19 | "url": "https://github.com/zhuzhonghua/Episode.git" 20 | }, 21 | "author": "zhonghua (http://www.zhuzhonghua.com/)", 22 | "license": "ISC", 23 | "bugs": { 24 | "url": "https://github.com/zhuzhonghua/Episode/issues" 25 | }, 26 | "homepage": "https://github.com/zhuzhonghua/Episode" 27 | } 28 | -------------------------------------------------------------------------------- /test/op.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | var Protobuf = require('protobufjs'); 3 | 4 | var testBuilder = Protobuf.loadProtoFile('test.proto'); 5 | 6 | var test = testBuilder.build(); 7 | 8 | var op = module.exports = {}; 9 | 10 | op.testMessage = test.testMessage; 11 | op.testRPCMessage = test.testRPCMessage; 12 | op.testRPCMessage_RET = test.testRPCMessage_RET; 13 | -------------------------------------------------------------------------------- /test/test.proto: -------------------------------------------------------------------------------- 1 | message testMessage 2 | { 3 | optional string hello = 1; 4 | } 5 | 6 | message testRPCMessage 7 | { 8 | optional int32 index = 1; 9 | optional string hello = 2; 10 | } 11 | 12 | message testRPCMessage_RET 13 | { 14 | optional int32 index = 1; 15 | } -------------------------------------------------------------------------------- /test/testChildServer.js: -------------------------------------------------------------------------------- 1 | var myutil = require('../lib/myutil'); 2 | 3 | var LOG = myutil.LOG; 4 | var ERROR = myutil.ERROR; 5 | 6 | var op = require('./op'); 7 | 8 | var Socket = require('../lib/socket'); 9 | 10 | var connSocket = null; 11 | 12 | var state = 0; 13 | 14 | function succ(session) 15 | { 16 | //var inst = new op.testMessage({hello:"hello"}); 17 | //session.sendByteBuffer(1, inst.toBuffer()); 18 | } 19 | 20 | function err(sockObj) 21 | { 22 | ERROR("error"); 23 | } 24 | 25 | function msgCB(sockObj, msgID, buf) 26 | { 27 | if(msgID == 1){ 28 | var inst = op.testRPCMessage.decode(buf); 29 | 30 | var msg = new op.testRPCMessage_RET({index: inst.index}); 31 | sockObj.sendByteBuffer(2, msg.toBuffer()); 32 | } 33 | } 34 | 35 | var connectServer = function(ip, port){ 36 | var connOption = {} 37 | connOption.client = true; 38 | connOption.port = port; 39 | connOption.host = ip; 40 | connOption.errCB = err; 41 | connOption.connSuccCB = succ; 42 | connOption.msgCB = msgCB; 43 | 44 | connSocket = new Socket(connOption); 45 | 46 | LOG("connecting "+ip+" "+port); 47 | } 48 | 49 | connectServer("127.0.0.1", 1234); 50 | -------------------------------------------------------------------------------- /test/testClient.js: -------------------------------------------------------------------------------- 1 | var myutil = require('../lib/myutil'); 2 | 3 | var LOG = myutil.LOG; 4 | var ERROR = myutil.ERROR; 5 | 6 | var op = require('./op'); 7 | 8 | var Socket = require('../lib/socket'); 9 | 10 | var connSocket = null; 11 | 12 | var state = 0; 13 | 14 | var account = "2234"; 15 | var charname = "abc"; 16 | 17 | function succ(session) 18 | { 19 | var inst = new op.testMessage({hello:"hello"}); 20 | session.sendByteBuffer(1, inst.toBuffer()); 21 | } 22 | 23 | function err(sockObj) 24 | { 25 | ERROR("error"); 26 | } 27 | 28 | function msgCB(sockObj, msgID, buf) 29 | { 30 | if(msgID == 2){ 31 | LOG("recv msg 2 from server"); 32 | } 33 | 34 | } 35 | 36 | var connectServer = function(ip, port){ 37 | var connOption = {} 38 | connOption.client = true; 39 | connOption.port = port; 40 | connOption.host = ip; 41 | connOption.errCB = err; 42 | connOption.connSuccCB = succ; 43 | connOption.msgCB = msgCB; 44 | 45 | connSocket = new Socket(connOption); 46 | 47 | LOG("connecting "+ip+" "+port); 48 | } 49 | 50 | connectServer("127.0.0.1", 1234); 51 | -------------------------------------------------------------------------------- /test/testMasterServer.js: -------------------------------------------------------------------------------- 1 | var myutil = require('../lib/myutil'); 2 | var Acceptor = require('../lib/acceptor'); 3 | var Socket = require('../lib/socket'); 4 | var http = require('http'); 5 | 6 | var LOG = myutil.LOG; 7 | var ERROR = myutil.ERROR; 8 | var cbFunc = myutil.cbFunc; 9 | 10 | var op = require('./op'); 11 | 12 | var rpcMsgIndex = 0; 13 | var rpcMsgIndexHandler = {}; 14 | 15 | function msgCB(session, msgID, buf) 16 | { 17 | if(msgID == 2){ 18 | var inst = op.testRPCMessage_RET.decode(buf); 19 | LOG("recv "+inst.index); 20 | 21 | rpcMsgIndexHandler[inst.index](session, msgID, buf); 22 | } 23 | } 24 | 25 | function testSendRPCMsg(cb){ 26 | for(var i in allChild){ 27 | // this tempIndex is important 28 | // it's index for the callback function clozure 29 | var tempIndex = ++rpcMsgIndex; 30 | 31 | var toHand = setTimeout(cbFunc(function(){ 32 | // for timeout not response 33 | delete rpcMsgIndexHandler[tempIndex]; 34 | }), 10*1000); 35 | 36 | rpcMsgIndexHandler[tempIndex] = function(session, msgID, buf){ 37 | // clear the timeout handler 38 | clearTimeout(toHand); 39 | // remove this msg index 40 | delete rpcMsgIndexHandler[tempIndex]; 41 | LOG("handled====="+tempIndex); 42 | cb(); 43 | } 44 | 45 | // send to every child for test 46 | var inst = new op.testRPCMessage({index:tempIndex}); 47 | allChild[i].sendByteBuffer(1, inst.toBuffer()); 48 | } 49 | } 50 | 51 | var allChild = {} 52 | function errCB(session) 53 | { 54 | delete allChild[session.id()]; 55 | } 56 | function newSock(newSock) 57 | { 58 | var options = { sock:newSock, 59 | errCB:cbFunc(errCB), 60 | msgCB:cbFunc(msgCB)}; 61 | 62 | var session = new Socket(options); 63 | allChild[session.id()] = session; 64 | 65 | LOG("new child server "+session.id()); 66 | } 67 | 68 | var acceptorClient = new Acceptor(1234, newSock); 69 | 70 | //=================== 71 | // just for trigger push msg to child server 72 | function handleRequest(req, res){ 73 | testSendRPCMsg(cbFunc(function(){ 74 | res.writeHead(200, {'Content-Type': 'text/plain'}); 75 | res.end("OK"); 76 | res.end('\n'); 77 | })); 78 | } 79 | 80 | var server = http.createServer(cbFunc(handleRequest)); 81 | server.listen(9527); 82 | -------------------------------------------------------------------------------- /test/testServer.js: -------------------------------------------------------------------------------- 1 | var myutil = require('../lib/myutil'); 2 | var Acceptor = require('../lib/acceptor'); 3 | var Socket = require('../lib/socket'); 4 | 5 | var LOG = myutil.LOG; 6 | var ERROR = myutil.ERROR; 7 | var cbFunc = myutil.cbFunc; 8 | 9 | var op = require('./op'); 10 | 11 | var allClient = {} 12 | 13 | function msgCB(session, msgID, buf) 14 | { 15 | if(msgID == 1){ 16 | var inst = op.testMessage.decode(buf); 17 | LOG("recv "+msgID+" "+inst.hello); 18 | 19 | var msg = new op.testMessage({hello:"world"}); 20 | session.sendByteBuffer(2, msg.toBuffer()); 21 | } 22 | } 23 | 24 | function errCB(session) 25 | { 26 | delete allClient[session.id()]; 27 | } 28 | 29 | 30 | function newSock(newSock) 31 | { 32 | var options = { sock:newSock, 33 | errCB:cbFunc(errCB), 34 | msgCB:cbFunc(msgCB)}; 35 | 36 | var session = new Socket(options); 37 | allClient[session.id()] = session; 38 | 39 | LOG("new client "+session.id()); 40 | } 41 | 42 | var acceptorClient = new Acceptor(1234, newSock); 43 | --------------------------------------------------------------------------------