基于google protobuf 的 socket udp 通信
SocketClient.cpp
#include "SocketClient.h" #include "ClientInfoSave.h" #include "serverMsg.pb.h" using namespace Message; string SocketClient::m_strHeatMsg = ""; set<BaseView*> SocketClient::m_set_BaseView; int SocketClient::m_nHeatFailCount = 0; SocketClient::SocketClient() { } SocketClient::~SocketClient() { } SocketClient* SocketClient::instance() { static SocketClient* pInstance =NULL; if(!pInstance) { pInstance = new SocketClient(); } return pInstance; } void SocketClient::insertBaseView(BaseView* pBaseView) { m_set_BaseView.insert(pBaseView); } void SocketClient::removeBaseView(BaseView *pBaseView) { m_set_BaseView.erase(pBaseView); } void SocketClient::sendTableMsgToServer(eEvent event , google::protobuf::MessageLite *msg) { sendMsgToServer(event , msg); } void SocketClient::sendMsgToServer(eEvent event ,google::protobuf::MessageLite *msg) { MsgBase msgBase; msgBase.set_eventid(event); msgBase.set_msg(msg->SerializeAsString()); string str = msgBase.SerializeAsString(); sendMsg(str); } void SocketClient::recvMsg(string msg) { MsgBase msgBase; msgBase.ParseFromString(msg); switch (msgBase.eventid()) { case eLogin: onLoginSucceess(msgBase.msg()); break; case eHeat: onHeat(); break; case eTable: recvTableMsg(msgBase.msg()); break; default: break; } } void SocketClient::reqLogin() { Login login; login.set_userid(ClientInfoSave::instance()->getUserId()); MsgBase msgBase; msgBase.set_eventid(eLogin); msgBase.set_msg(login.SerializeAsString()); loginServer(msgBase.SerializeAsString()); } void SocketClient::reqLeave() { Leave leave; leave.set_userid(ClientInfoSave::instance()->getUserId()); sendMsgToServer(eLeave,&leave); } void* SocketClient::reqHeat(void *arg) { string msg = *((string*)arg); for(m_nHeatFailCount =0; m_nHeatFailCount<10 ; ) { sendMsg(msg); CCLog("sendheat count:%d",m_nHeatFailCount); ++m_nHeatFailCount; Sleep(1500); } onLoginFail(); return NULL; } void SocketClient::onLoginSucceess(string msg) { Login login; login.ParsePartialFromString(msg); ClientInfoSave::instance()->setUserId(login.userid()); CCLog(" longin success :%d", login.userid()); AnsHeatBeat heat; heat.set_userid(login.userid()); sendMsgToServer(eHeat,&heat); MsgBase msgBase; msgBase.set_eventid(eHeat); msgBase.set_msg(heat.SerializeAsString()); m_strHeatMsg = msgBase.SerializeAsString(); for (set<BaseView*>::iterator it = m_set_BaseView.begin() ; it!=m_set_BaseView.end() ; ++it) { BaseView* pBaseView = *it; pBaseView->loginSuceess(); } pthread_t tid; pthread_create(&tid,NULL,SocketClient::reqHeat,(void*)&m_strHeatMsg);//创建一个线程 接受客户端消息 } void SocketClient::onHeat() { CCLog("send event %d",eHeat); m_nHeatFailCount = 0; } void SocketClient::onLoginFail() { for (set<BaseView*>::iterator it = m_set_BaseView.begin() ; it!=m_set_BaseView.end() ; ++it) { BaseView* pBaseView = *it; pBaseView->loginFail(); } }
SocketClient.h
#pragma once #include "SocketAdmin.h" #include "cocos2d.h" #include "google/protobuf/message_lite.h" #include "MessageEvent.h" #include "pthread.h" #include "BaseView.h" #include "table/TableBase.h" USING_NS_CC; using namespace std; #define UserID unsigned int #define BYTE unsigned char class BaseView; class SocketClient : public BaseSocket , public TableSocket { private: static string m_strHeatMsg; static set<BaseView*> m_set_BaseView; static int m_nHeatFailCount;//心跳失败的次数 >10 次说明掉线了 private: SocketClient(); void sendMsgToServer( eEvent event ,google::protobuf::MessageLite *msg); static void *reqHeat(void *arg); public: ~SocketClient(); static SocketClient* instance(); virtual void recvMsg(string msg); void sendTableMsgToServer(eEvent event , google::protobuf::MessageLite *msg); void insertBaseView(BaseView *pBaseView); void removeBaseView(BaseView *pBaseView); void reqLogin();//登陆 void reqLeave();//离开 void reqHeat(float fTime);//心跳协议 void onLoginSucceess(string msg);//登陆反馈 用于首次登陆客户端 void onHeat(); static void onLoginFail(); };
SocketAdmin.h
#pragma once #include "cocos2d.h" #include "pthread.h" #include <string> #if(CC_TARGET_PLATFORM==CC_PLATFORM_WIN32) #ifndef _WINSOCKAPI_ #define _WINSOCKAPI_ #ifndef _WINSOCK2API_ #define _WINSOCK2API_ #include <WinSock2.h> #endif #endif #else #include <sys/socket.h> #include <netinet/in.h> #include <sys/types.h> #include <arpa/inet.h> typedef unsigned int SOCKET; #endif class SocketAdmin; class BaseSocket { public: BaseSocket(); ~BaseSocket(); virtual void recvMsg(std::string msg) = 0; static void sendMsg(std::string &msg); void loginServer(std::string &msg ); }; class SocketAdmin { private: static BaseSocket* m_pBaseSocket; static SocketAdmin* m_pInstance; SOCKET m_clientSocket;//客户端 socket static SOCKADDR_IN m_serverAddr;//服务器地址 public: SocketAdmin(); static SocketAdmin* instance(); virtual ~SocketAdmin(); void sendMsg(std::string &msg); static void* thread_recv(void* arg); static void setBaseSocket(BaseSocket *pBaseSocket) { m_pBaseSocket = pBaseSocket; } static void clearBaseSocket() { m_pBaseSocket = NULL; } void loginServer(std::string &msg);//登陆服务器 };
SocketAdmin.cpp
#include "SocketAdmin.h" BaseSocket* SocketAdmin::m_pBaseSocket = NULL; SocketAdmin* SocketAdmin::m_pInstance = NULL; SOCKADDR_IN SocketAdmin::m_serverAddr; BaseSocket::BaseSocket() { SocketAdmin::setBaseSocket(this); } BaseSocket::~BaseSocket() { SocketAdmin::clearBaseSocket(); } void BaseSocket::sendMsg( std::string &msg ) { SocketAdmin::instance()->sendMsg(msg); } void BaseSocket::loginServer(std::string &msg) { SocketAdmin::instance()->loginServer(msg); } SocketAdmin* SocketAdmin::instance() { if(!m_pInstance) m_pInstance = new SocketAdmin(); return m_pInstance; } SocketAdmin::SocketAdmin() { //初始化socket库 #if(CC_TARGET_PLATFORM==CC_PLATFORM_WIN32) WSADATA wsaData; if ( 0 != WSAStartup( MAKEWORD(1,1), &wsaData) ) { return ; } if (LOBYTE(wsaData.wVersion) !=1 || HIBYTE(wsaData.wVersion)!=1 ) { WSACleanup(); return ; } #endif m_serverAddr.sin_addr.S_un.S_addr = inet_addr("113.91.54.51"); //htonl函数是将主机字节序(小端序)转换为网络字节序(大端序) m_serverAddr.sin_port = htons(6100); m_serverAddr.sin_family = AF_INET; m_clientSocket = socket(AF_INET,SOCK_DGRAM,0); } SocketAdmin::~SocketAdmin() { WSACleanup(); closesocket(m_clientSocket); } void SocketAdmin::loginServer(std::string &msg) { sendMsg(msg); pthread_t tid; pthread_create(&tid,NULL,SocketAdmin::thread_recv,(void*)m_clientSocket);//创建一个线程 接受客户端消息 } void* SocketAdmin::thread_recv(void* arg) { SOCKET sockfd = (SOCKET) arg; int len = sizeof(SOCKADDR); std::string str; SOCKADDR_IN addr; char buf[2000]; while (true) { str=""; int retval = recvfrom(sockfd , (buf) , 2000 , 0 ,(SOCKADDR*)&addr , &len); if (SOCKET_ERROR != retval){ for (int i = 0; i < retval-1; i++) { str.append("0"); str[i]=buf[i]; } m_pBaseSocket->recvMsg(str); }else{ CCLOG("*********************************** recvMsg fail "); break; } } return NULL;; } void SocketAdmin::sendMsg(std::string &msg) { sendto(m_clientSocket , msg.c_str() , msg.length()+1 ,0 ,(SOCKADDR*)&m_serverAddr , sizeof(SOCKADDR)); }