74.在cocos2d-lua中使用我们的通信引擎

将客户端的功能,注册给lua脚本使用。

主要功能有:

1、创建客户端

2、连接服务端

3、运行客户端

4、写入字节流

5、读取字节流

--------------------------------------------------

简易客户端EasyTcpClient.hpp

#ifndef _EasyTcpClient_hpp_
#define _EasyTcpClient_hpp_

#ifdef _WIN32
    #include <windows.h>
    #include <WinSock2.h>
#else
    #include<unistd.h>
    #include<arpa/inet.h>
    #include<string.h>
    #define SOCKET int
    #define INVALID_SOCKET (SOCKET)(~0)
    #define SOCKET_ERROR (-1)
#endif

#include <stdio.h>
#include "DataHeader.hpp"
#include "CELLMsgStream.hpp"

class  EasyTcpClient
{
public:
    EasyTcpClient()
    {
        _sock = INVALID_SOCKET;
    }
    //虚析构函数
    virtual ~EasyTcpClient()
    {
        Close();
    }

    //初始化socket
    void InitSocket()
    {
#ifdef _WIN32
        WORD ver = MAKEWORD(2, 2);
        WSADATA dat;
        WSAStartup(ver, &dat);
#endif // _WIN32

        if (_sock != INVALID_SOCKET)
        {
            Close();
        }

        _sock = socket(AF_INET, SOCK_STREAM, 0);
        if (INVALID_SOCKET == _sock)
        {
            printf("错误,建立Socket失败...\n");
        }
        else
        {
            printf("建立Socket成功...\n");
        }

    }

    int Connect(const char* ip, unsigned short port)
    {
        if (INVALID_SOCKET == _sock)
        {
            InitSocket();
        }

        sockaddr_in _sin = {};
        _sin.sin_family = AF_INET;
        _sin.sin_port = htons(port);
#ifdef _WIN32
        _sin.sin_addr.S_un.S_addr = inet_addr(ip);
#else
        _sin.sin_addr.s_addr = inet_addr(ip);
#endif

        int ret = connect(_sock, (const sockaddr*)&_sin, sizeof(sockaddr_in));
        if (SOCKET_ERROR == ret)
        {
            printf("错误,连接服务端失败...\n");
        }
        else
        {
            printf("连接服务端成功...\n");
        }
        
        return ret;
    }

    bool isRun()
    {
        return (_sock != INVALID_SOCKET);
    }

    bool onRun()
    {
        if (isRun())
        {
            fd_set fdRead; 
            FD_ZERO(&fdRead);
            FD_SET(_sock, &fdRead);

            timeval t = {1, 0};
            int ret = select(_sock + 1, &fdRead, 0, 0, &t);
            if (ret < 0)
            {
                Close();
                printf("select任务结束1。\n");
                return false;
            }

            if ( FD_ISSET(_sock, &fdRead) )
            {
                if (-1 == RecvData())
                {
                    Close();
                    printf("select任务结束2。\n");
                    return false;
                }
            }

        }
    }

    //接收数据 处理粘包 拆分包
    int RecvData()
    {

        char szRecv[1024] = {};

        int nLen = recv(_sock, szRecv, sizeof(DataHeader), 0);
        if (nLen <= 0)
        {
            printf("服务端%d已退出。\n", _sock);
            return -1;
        }

        DataHeader* pHeader = (DataHeader*)szRecv;
        recv(_sock, szRecv + sizeof(DataHeader), pHeader->dataLength - sizeof(DataHeader), 0);

        onNetMsg(pHeader);

        return 0;
    }

    virtual void onNetMsg(DataHeader* pData)
    {
        switch (pData->cmd)
        {
        case CMD_LOGIN_RET:
        {
            //LoginResult *pLogin = (LoginResult*)pData;
            //printf("login result:%d\n", pLogin->ret);
        }
        break;
        case CMD_LOGOUT_RET:
        {
            CELLReadStream r(pData);
            //读取消息长度
            r.ReadInt16();
            //读取消息命令
            r.getNetCmd();
            auto n1 = r.ReadInt8();
            auto n2 = r.ReadInt16();
            auto n3 = r.ReadInt32();
            auto n4 = r.ReadFloat();
            auto n5 = r.ReadDouble();
            uint32_t n = 0;
            r.onlyRead(n);
            char name[32] = {};
            auto n6 = r.ReadArray(name, 32);
            char pw[32] = {};
            auto n7 = r.ReadArray(pw, 32);
            int ata[10] = {};
            auto n8 = r.ReadArray(ata, 10);
            
            printf("recv msg, name:%s pw:%s\n", name, pw);
        }
        break;
        case CMD_NEW_USER_JOIN:
        {
         
            printf("new user join.\n");
        }
        break;
        }
    }

    //发送数据
    int SendData(DataHeader* pHeader)
    {
        if (isRun() && pHeader)
        {
            return send(_sock, (const char*)pHeader, pHeader->dataLength, 0);
        }
        return SOCKET_ERROR;
    }
    
    int SendData(const char* pData, int len)
    {
        if (isRun() && pData)
        {
            return send(_sock, pData, len, 0);
        }
        return SOCKET_ERROR;
    }

    void Close()
    {
        if (_sock != INVALID_SOCKET)
        {
#ifdef _WIN32
            closesocket(_sock);
            //清除Windows socket环境
            WSACleanup();
#else
            close(_sock);
#endif
            _sock = INVALID_SOCKET;
        }
    }

private:
    SOCKET _sock;

};


#endif

 

 

cocos2d-x-3.16\tests\lua-empty-test\project\Classes\lua_CppNet100_register.hpp

lua中的函数,注册到客户端中,在消息处理中,回调处理消息。

cocos2d::LUA_FUNCTION _callBack

class NativeClient :public EasyTcpClient
{
private:
    cocos2d::LUA_FUNCTION _callBack = 0;

public:
    void setCallBack(cocos2d::LUA_FUNCTION cb)
    {
        _callBack = cb;
    }


    void onNetMsg(DataHeader* pData)
    {
        if (_callBack)
        {
            //执行lua的函数
            LuaEngine* engine = LuaEngine::getInstance();
            lua_State* L = engine->getLuaStack()->getLuaState();

            //给lua传递参数
            tolua_pushuserdata(L, pData);
            tolua_pushnumber(L, pData->dataLength);

            //执行lua的函数
            engine->getLuaStack()->executeFunctionByHandler(_callBack, 2);//指定lua函数的参数为2个
        }

    }
};

 

创建客户端、连接服务端方法,注册到lua中

static void* CellClient_Create(cocos2d::LUA_FUNCTION cb, int sendSize=1024, int recvSize=1024)
{
    NativeClient* obj = new NativeClient();
    obj->setCallBack(cb);
    obj->InitSocket();

    return obj;
}

//给lua调用的,创建客户端
int lua_CellClient_Create(lua_State* L)
{    
    //获取lua的函数
    cocos2d::LUA_FUNCTION cb = toluafix_ref_function(L, 1, 0);

    void* obj = CellClient_Create(cb);

    tolua_pushuserdata(L, obj);

    return 1;
}

static bool CellClient_Connect(NativeClient* obj, const char* ip, unsigned short port)
{
    return obj->Connect(ip, port);
}

//给lua调用的,连接服务器
int lua_CellClient_Connect(lua_State* L)
{
    //获取lua的参数
    //客户端
    NativeClient* obj = (NativeClient*)tolua_touserdata(L, 1, nullptr);
    //服务端ip地址
    const char* ip = tolua_tostring(L, 2,nullptr);
    //服务端端口号
    unsigned short port = 0;
    luaval_to_ushort(L, 3, &port);

    bool b = CellClient_Connect(obj, ip, port);

    tolua_pushboolean(L, b);

    return 1;
}

 

字节流的方法,举例:

//创建读取字节流
static void* CELLReadStream_Create(void* data)
{

    CELLReadStream* obj = new CELLReadStream((DataHeader*)data);

    return obj;
}

int lua_CellClient_ReadStream_Create(lua_State* L)
{
    void* data = tolua_touserdata(L, 1, nullptr);

    void* obj = CELLReadStream_Create(data);

    tolua_pushuserdata(L, obj);

    return 1;
}

//读取字符串
int lua_CellClient_ReadStream_ReadString(lua_State* L)
{
    auto obj = (CELLReadStream*)tolua_touserdata(L, 1, nullptr);
    std::string str;
    obj->ReadString(str);
    tolua_pushstring(L, str.c_str());
    return 1;
}




static void* CELLWriteStream_Create(int nSize)
{
    CELLWriteStream* obj = new CELLWriteStream(nSize);

    return obj;
}

int lua_CELLWriteStream_Create(lua_State* L)
{
    int nSize = lua_tointeger(L, 1);
    void* obj = CELLWriteStream_Create(nSize);
    tolua_pushuserdata(L, obj);
    return 1;
}


static bool CELLWriteStream_WriteInt8(CELLWriteStream* obj, int8_t n)
{
    if (obj)
        return obj->Write(n);
    return false;
}

int lua_CellClient_WriteStream_WriteInt8(lua_State* L)
{
    CELLWriteStream* ws = (CELLWriteStream*)tolua_touserdata(L, 1, nullptr);

    int8_t n = (int8_t)tolua_tonumber(L, 2, 0);

    bool b = CELLWriteStream_WriteInt8(ws, n);

    tolua_pushboolean(L, b);

    return 1;
}

 

注册到lua中

//将函数注册到lua中
int lua_CppNet100_register(lua_State* L)
{
    tolua_open(L);
    tolua_module(L, nullptr, 0);
    tolua_beginmodule(L, nullptr);
        lua_register(L, "ClientCreate", lua_CellClient_Create);//创建客户端,注册回调函数
        lua_register(L, "ClientConnect", lua_CellClient_Connect);//连接服务器


        lua_register(L, "WriteStream_Create", lua_CELLWriteStream_Create);//创建写入字节流
        lua_register(L, "WriteStream_WriteInt8", lua_CellClient_WriteStream_WriteInt8);//字节流写入Int8

        lua_register(L, "ReadStream_Create", lua_CellClient_ReadStream_Create);//创建读取字节流
        lua_register(L, "ReadStream_ReadString", lua_CellClient_ReadStream_ReadString);//字节流读取

    tolua_endmodule(L);

    return 0;
}

在lua中使用

//回调函数
local function callback(data, len)
    cclog("callback_onNetMsg:len="..len)
    local rs = ReadStream_Create(data)//创建读取字节流
    -- 读取消息长度
    ReadStream_ReadInt16(rs)
    -- 读取消息类型
    ReadStream_ReadUInt16(rs)
    ReadStream_ReadInt8(rs)
    ReadStream_ReadInt16(rs)
    ReadStream_ReadInt32(rs)
    ReadStream_ReadFloat(rs)
    ReadStream_ReadDouble(rs)
    cclog(ReadStream_ReadString(rs))
    cclog(ReadStream_ReadString(rs))
    local len = ReadStream_ReadUInt32(rs)
    for n=1,len do
        ReadStream_ReadInt32(rs)
    end
end

    //创建客户端
    local _client = ClientCreate(callback)
    ClientConnect(_client, "127.0.0.1", 4567);
    
    //创建写入字节流
    local ws = WriteStream_Create(128)
    WriteStream_WriteUInt16(ws, 2)-- 消息类型
    WriteStream_WriteInt8(ws, 1)
    WriteStream_WriteInt16(ws, 2)
    WriteStream_WriteInt32(ws, 3)
    WriteStream_WriteFloat(ws, 4.5)
    WriteStream_WriteDouble(ws, 6.7)
    WriteStream_WriteString(ws, "usename01")
    WriteStream_WriteString(ws, "password")
    --
    --写数组长度
    WriteStream_WriteUInt32(ws, 5)
    --写数组元素
    WriteStream_WriteInt32(ws, 1)
    WriteStream_WriteInt32(ws, 2)
    WriteStream_WriteInt32(ws, 3)
    WriteStream_WriteInt32(ws, 4)
    WriteStream_WriteInt32(ws, 5)
    
    -- every frame
    local function tick()
        -- ClientSendData(_client, "yyy", 3)
        SendWriteStream(_client, ws)
        ClientOnRun(_client)
    end

 

上一篇:【Node】简单的websocket长连接


下一篇:mysql concat()拼接有null值