基于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));
}
原文地址:https://www.cnblogs.com/codeloveme/p/4615051.html