游戏服务器防护的一种实现方法(IOCP)

1.前言

目前市面上的服务器防护软件大部分都使用节点转发来实现,我们第一期产品也采用简单的单节点转发,代码比较简单。但是如果玩家端连接的节点被攻击,玩家必须重新启动切换新的节点后才能正常操作,体验很不好,所以第二期对代码进行了重构,独创“一王多后”模式,实现当前所连节点被攻击后,自动切换为下一个节点,且游戏不会掉线。

2.解决方案

一王多后要满足如下要求:
1.A节点被攻击后,A节点和同域内节点通信正常
2.A节点被攻击后,A节点和游戏服务器通信正常
我们假设现在有A节点(王),B节点(后),C节点(后),D节点(后)
创建通道如下:
1.玩家—A节点—游戏服务器
2.玩家—B节点—A节点
3.玩家—C节点—A节点
4.玩家—D节点—A节点
当A节点被攻击无法连接时,玩家端自动切换附加线路,如玩家—B节点—A节点—游戏服务器

3.代码实现

节点端部分代码:
multinode.h
/*
* Copyright (c) 2017,宁波云户信息科技有限公司
* All rights reserved.
*
* 文件名称: multinode.h
* 文件标识: 
* 摘    要: 节点端通过IOCP实现高效数据转发
*
* 当前版本: 1.0.0.1
* 作    者: 张瑞强
* 完成日期: 2017年04月08日
* 修改日期: 2017年04月09日
*/

#pragma once

#include "myiocp.h"
#include "mydefine.h"
#include <map>
#include <string>
#include <vector>

class CMULTINODE : public CMYIOCP
{
public:
    typedef struct stSocketGuid{
        SOCKET server;
        std::string strGuid;
    }S_SOCKET_GUID;

    typedef struct stNodeData{
        std::string strNodeIp;
        int nNodePort;
        std::string strServerIp;
        int nServerPort;
        std::string strTransNodeIp;
        int nTransNodePort;
        std::map<SOCKET, SOCKET> mapLocalNode;
        std::map<std::string, SOCKET> mapGuidLocal;
    }S_NODE_DATA;

    typedef struct stIpPort{
        std::string strip;
        int nport;
    }S_IP_PORT;

    typedef struct stMsgInfo{
        std::string strheader;
        std::vector<S_IP_PORT> vecall;
        std::string stroldguid;
        std::string strnewguid;
    }S_MSG_INFO;

public:
    CMULTINODE();
    ~CMULTINODE();

public:
    /*
    * 函数介绍:创建本地监听
    * 输入参数:nLocalPort 本地监听端口
    * 输出参数:
    * 返 回 值:true      成功
    *           false     失败
    */
    bool portmap(int nLocalPort);

private:
    void OnAccept(SOCKET server, SOCKET client);
    void OnRead(SOCKET s, char *buf, int len);
    void OnClose(SOCKET s);

private:
    std::string Msg2String(const S_MSG_INFO &msginfo);
    bool String2Msg(const std::string &strmsg, S_MSG_INFO &msginfo);

private:
    S_NODE_DATA m_stNodeData;
    S_NODE_DATA m_stTransNodeData;
};
multinode.cpp
#include "multinode.h"

CMULTINODE::CMULTINODE()
{
}

CMULTINODE::~CMULTINODE()
{
}

bool CMULTINODE::portmap(int nLocalPort)
{
    bool bret = false;
    if (nLocalPort > 0)
    {
        SOCKET server;
        bret = CMYIOCP::Listen(nLocalPort, server);
    }
    return bret;
}

void CMULTINODE::OnAccept(SOCKET server, SOCKET local)
{
    if (local != INVALID_SOCKET)
    {
        char szbuf[1024] = {0};
        recv(local, szbuf, 1024, 0);
        if (strlen(szbuf) > 0)
        {
            S_MSG_INFO msginfo;
            if (String2Msg(szbuf, msginfo))
            {
                if (msginfo.strheader.compare(gstrSendHeader) == 0 && msginfo.vecall.size() == 1)
                {
                    SOCKET game_server;
                    if (CMYIOCP::Connect((char *)msginfo.vecall[0].strip.c_str(), msginfo.vecall[0].nport, game_server)){
                        m_stNodeData.mapLocalNode[local] = game_server;
                        m_stNodeData.mapGuidLocal[msginfo.stroldguid] = local;

                        //printf("OnAccept local:%d guid:%s.\r\n", local, msginfo.stroldguid.c_str());
                    }
                }else if (msginfo.strheader.compare(gstrTransHeader) == 0 && msginfo.vecall.size() == 2){
                    SOCKET node;
                    if (CMYIOCP::Connect((char *)msginfo.vecall[0].strip.c_str(), msginfo.vecall[0].nport, node)){
                        m_stNodeData.mapLocalNode[local] = node;
                        m_stNodeData.mapGuidLocal[msginfo.stroldguid] = local;

                        S_MSG_INFO passinfo;
                        passinfo.strheader = gstrPassHeader;
                        passinfo.stroldguid = msginfo.stroldguid;
                        passinfo.strnewguid = msginfo.strnewguid;
                        std::string strsendinfo = Msg2String(passinfo);
                        send(node, strsendinfo.c_str(), strsendinfo.size(), 0);
                    }
                }else if (msginfo.strheader.compare(gstrPassHeader) == 0){
                    //这里只是信息的记录没什么用的
                    //m_stTransNodeData.mapLocalNode[local] = local;
                    m_stTransNodeData.mapGuidLocal[msginfo.stroldguid+msginfo.strnewguid] = local;
                    //printf("gstrPassHeader oldguid:%s newguid:%s.\r\n", msginfo.stroldguid.c_str(), msginfo.strnewguid.c_str());
                }else if (msginfo.strheader.compare(gstrChangeHeader) == 0 && msginfo.vecall.size() == 1){
                    //这里要发送到代理节点上去
                    SOCKET node;
                    if (CMYIOCP::Connect((char *)msginfo.vecall[0].strip.c_str(), msginfo.vecall[0].nport, node)){
                        S_MSG_INFO passinfo;
                        passinfo.strheader = gstrSwitchHeader;
                        passinfo.strnewguid = msginfo.strnewguid;
                        passinfo.stroldguid = msginfo.stroldguid;
                        std::string strsendinfo = Msg2String(passinfo);
                        send(node, strsendinfo.c_str(), strsendinfo.size(), 0);
                        //printf("gstrChangeHeader oldguid:%s newguid:%s.\r\n", msginfo.stroldguid.c_str(), msginfo.strnewguid.c_str());
                    }
                }else if (msginfo.strheader.compare(gstrSwitchHeader) == 0){
                    //std::string stroldguid = msginfo.stroldguid;
                    //printf("gstrSwitchHeader oldguid:%s newguid:%s.\r\n", msginfo.stroldguid.c_str(), msginfo.strnewguid.c_str());
                    SOCKET old_local = m_stNodeData.mapGuidLocal[msginfo.stroldguid];
                    SOCKET new_local = m_stTransNodeData.mapGuidLocal[msginfo.stroldguid+msginfo.strnewguid];
                    if (old_local > 0 && new_local > 0)
                    {
                        SOCKET old_server = m_stNodeData.mapLocalNode[old_local];
                        if (old_server > 0)
                        {
                            //这里要同步的否则可能会有问题哦
                            m_stNodeData.mapLocalNode.erase(old_local);
                            m_stNodeData.mapLocalNode[new_local] = old_server;
                            m_stNodeData.mapGuidLocal[msginfo.stroldguid] = new_local;
                            //printf("gstrSwitchEnd oldguid:%s newguid:%s.\r\n", msginfo.stroldguid.c_str(), msginfo.strnewguid.c_str());
                        }
                    }
                }
            }else
            {
                printf("failed in String2Msg.\r\n");
            }
        }
    }
}

void CMULTINODE::OnRead(SOCKET s, char *buf, int len)
{
    if (s != INVALID_SOCKET && buf != NULL && len > 0)
    {
        SOCKET node = m_stNodeData.mapLocalNode[s];
        if (node > 0)
        {
            char szbuf[8192] = {0};
            memcpy(szbuf, buf, len);
            send(node, szbuf, len, 0);
            return;
        }
        else
        {
            for (std::map<SOCKET, SOCKET>::iterator it = m_stNodeData.mapLocalNode.begin(); it != m_stNodeData.mapLocalNode.end(); ++it)
            {
                if (it->second == s)
                {
                    char szbuf[8192] = {0};
                    memcpy(szbuf, buf, len);
                    send(it->first, szbuf, len, 0);
                    return;
                }
            }
        }
    }
}

void CMULTINODE::OnClose(SOCKET s)
{
    auto delguid = [&](SOCKET local){
        for (std::map<std::string, SOCKET>::iterator it = m_stNodeData.mapGuidLocal.begin(); it != m_stNodeData.mapGuidLocal.end();++it){
            if (it->second == local)
            {
                m_stNodeData.mapGuidLocal.erase(it);
                break;
            }
        }
    };

    SOCKET node = m_stNodeData.mapLocalNode[s];
    if (node > 0)
    {
        delguid(s);
        closesocket(node);
        m_stNodeData.mapLocalNode.erase(s);
        //printf("OnClose local:%d.\r\n", s);
    }
    else
    {
        for (std::map<SOCKET, SOCKET>::iterator it = m_stNodeData.mapLocalNode.begin(); it != m_stNodeData.mapLocalNode.end(); ++it)
        {
            if (it->second == s)
            {
                //printf("OnClose local:%d.\r\n", it->first);
                delguid(it->first);
                closesocket(it->first);
                m_stNodeData.mapLocalNode.erase(it);
                break;
            }
        }
    }
}

#include "enc_dec.h"
std::string CMULTINODE::Msg2String(const S_MSG_INFO &msginfo)
{
    std::string strmsg = msginfo.strheader;
    for (std::vector<S_IP_PORT>::const_iterator it = msginfo.vecall.begin(); it != msginfo.vecall.end(); ++it)
    {
        strmsg += CENCDEC::new_ip_encode(it->strip);
        char szport[64] = {0};
        sprintf(szport, "%05d", it->nport);
        strmsg += CENCDEC::new_port_encode(szport);
    }
    strmsg += msginfo.stroldguid;
    strmsg += msginfo.strnewguid;
    return strmsg;
}

bool CMULTINODE::String2Msg(const std::string &strmsg, S_MSG_INFO &msginfo)
{
    bool bret = false;
    if (!strmsg.empty())
    {
        msginfo.strheader = strmsg.substr(0, 4);
        std::string strallinfo = strmsg.substr(4);
        if (strallinfo.size() >= 32)
        {
            msginfo.stroldguid = strallinfo.substr(strallinfo.size() - 64, 32);
            msginfo.strnewguid = strallinfo.substr(strallinfo.size() - 32, 32);
            std::string strallip = strallinfo.substr(0, strallinfo.size() - 64);
            if (!strallip.empty() && strallip.size() % 17 == 0)
            {
                int ncount = strallip.size() / 17;
                for (int nindex = 0; nindex < ncount; ++nindex){
                    std::string strencip = strallip.substr(nindex * 17, 12);
                    std::string strencport = strallip.substr(nindex * 17 + 12, 5);
                    S_IP_PORT stport;
                    stport.strip = CENCDEC::new_ip_decode(strencip);
                    stport.nport = atoi(CENCDEC::new_port_decode(strencport).c_str());
                    msginfo.vecall.push_back(stport);
                }
            }
            bret = true;
        }
    }
    return bret;
}
客户端部分代码:
mymultiportmap.h
/*
* Copyright (c) 2017,宁波云户信息科技有限公司
* All rights reserved.
*
* 文件名称: mymultiportmap.h
* 文件标识: 客户端创建映射
* 摘    要: 客户端创建映射
*
* 当前版本: 1.0.0.1
* 作    者: 张瑞强
* 完成日期: 2017年04月08日
* 修改日期: 2017年04月09日
*/

#pragma once

#include "myiocp.h"
#include "mydefine.h"
#include <vector>
#include <map>

class CMYMULTIPORTMAP : public CMYIOCP
{
public:
    typedef struct stNodeData{
        std::string strNodeIp;
        int nNodePort;
        std::string strServerIp;
        int nServerPort;
        std::string strTransNodeIp;
        int nTransNodePort;
        std::map<SOCKET, SOCKET> mapLocalNode;
        std::map<SOCKET, std::string> mapNodeOldGuid;
        std::map<SOCKET, std::string> mapNodeNewGuid;
    }S_NODE_DATA;

    typedef struct stIpPort{
        std::string strip;
        int nport;
    }S_IP_PORT;

    typedef struct stMsgInfo{
        std::string strheader;
        std::vector<S_IP_PORT> vecall;
        std::string stroldguid;
        std::string strnewguid;
    }S_MSG_INFO;

public:
    CMYMULTIPORTMAP();
    ~CMYMULTIPORTMAP();

public:
    /*
    * 函数介绍:创建和节点端映射
    * 输入参数:nLocalPort   本地监听端口
    *           strServerIp  游戏服务器ip地址
    *           nServerPort  游戏服务器端口
    * 输出参数:bool
    * 返 回 值:true         成功
    *           false        失败
    */
    bool portmap(int nLocalPort, const std::string &strServerIp, int nServerPort);

    /*
    * 函数介绍:添加节点
    * 输入参数:strNodeIp   节点地址
    *           nNodePort   节点端口号
    * 输出参数:
    * 返 回 值:
    */
    void insertnode(const std::string &strNodeIp, int nNodePort);

    /*
    * 函数介绍:切换节点
    * 输入参数:
    * 输出参数:
    * 返 回 值:
    */
    void changenode();

public:
    void OnAccept(SOCKET server, SOCKET client);
    void OnRead(SOCKET s, char *buf, int len);
    void OnClose(SOCKET s);

private:
    std::string getGuid();
    std::string Msg2String(const S_MSG_INFO &msginfo);
    bool String2Msg(const std::string &strmsg, S_MSG_INFO &msginfo);

private:
    S_NODE_DATA m_stNodeData;
    std::vector<S_NODE_DATA*> m_vecNodeData;
    std::map<SOCKET, S_SERVER_INFO*> m_mapSocketInfo;
    int m_nNodeIndex;     //这是当前切换的序号
    std::string m_strGameIp;
    int m_nGamePort;
};
mymultiportmap.cpp
#include "stdafx.h"
#include "mymultiportmap.h"
#include <Objbase.h>
#include "enc_dec.h"
#pragma comment(lib, "Ole32.lib")

CMYMULTIPORTMAP::CMYMULTIPORTMAP()
{
    m_nNodeIndex = 0;
    m_strGameIp = "";
}

CMYMULTIPORTMAP::~CMYMULTIPORTMAP()
{
    CMYIOCP::m_workThread = false;
    CMYIOCP::m_acceptThread = false;

    for (std::map<SOCKET, S_SERVER_INFO*>::iterator it = m_mapSocketInfo.begin(); it != m_mapSocketInfo.end(); ++it){
        closesocket(it->first);
        delete it->second;
    }

    for (std::map<SOCKET, SOCKET>::iterator it = m_stNodeData.mapLocalNode.begin(); it != m_stNodeData.mapLocalNode.end(); ++it){
        closesocket(it->first);
    }

    for (std::vector<S_NODE_DATA *>::iterator it = m_vecNodeData.begin(); it != m_vecNodeData.end(); ++it){
        S_NODE_DATA *pdata = *it;
        for (std::map<SOCKET, SOCKET>::iterator itmap = pdata->mapLocalNode.begin(); itmap != pdata->mapLocalNode.end(); ++itmap){
            closesocket(itmap->second);
        }
        delete pdata;
    }
    m_vecNodeData.clear();
}

bool CMYMULTIPORTMAP::portmap(int nLocalPort, const std::string &strServerIp, int nServerPort)
{
    bool bret = false;
    if (nLocalPort > 0 && !strServerIp.empty() && nServerPort > 0)
    {
        SOCKET server;
        if (CMYIOCP::Listen(nLocalPort, server))
        {
            char szinfo[256] = {0};
            sprintf(szinfo, "%s:%d", strServerIp.c_str(), nServerPort);
            S_SERVER_INFO *pstInfo = new S_SERVER_INFO;
            pstInfo->strSendInfo = szinfo;
            pstInfo->strServerIp = strServerIp;
            pstInfo->nServerPort = nServerPort;
            m_mapSocketInfo[server] = pstInfo;
            bret = true;
        }
    }
    return bret;
}

void CMYMULTIPORTMAP::OnAccept(SOCKET server, SOCKET local)
{
    SOCKET node = m_stNodeData.mapLocalNode[local];
    if (node <= 0)
    {
        //SOCKET node;
        S_SERVER_INFO *pstInfo = (S_SERVER_INFO *)m_mapSocketInfo[server];
        if (pstInfo != NULL)
        {
            std::string stroldguid = getGuid();
            if (CMYIOCP::Connect((char *)m_stNodeData.strNodeIp.c_str(),  m_stNodeData.nNodePort, node))
            {
                m_stNodeData.mapLocalNode[local] = node;
                m_stNodeData.mapNodeOldGuid[node] = stroldguid;
                m_stNodeData.mapNodeNewGuid[node] = stroldguid;
                S_MSG_INFO msginfo;
                msginfo.stroldguid = stroldguid;
                msginfo.strnewguid = stroldguid;
                msginfo.strheader = gstrSendHeader;
                S_IP_PORT ip_node;
                ip_node.strip = pstInfo->strServerIp;
                ip_node.nport = pstInfo->nServerPort;
                msginfo.vecall.push_back(ip_node);
                std::string strsendinfo = Msg2String(msginfo);
                send(node, strsendinfo.c_str(), strsendinfo.size(), 0);
            }

            int nsize = m_vecNodeData.size();
            for (int nindex = 0; nindex < nsize; ++nindex){
                S_NODE_DATA *pdata = m_vecNodeData[nindex];
                if (CMYIOCP::Connect((char *)(pdata->strNodeIp.c_str()),  pdata->nNodePort, node)){
                    std::string strguid = getGuid();
                    S_MSG_INFO msginfo;
                    msginfo.strheader = gstrTransHeader;
                    msginfo.stroldguid = stroldguid;
                    msginfo.strnewguid = strguid;
                    S_IP_PORT ip_node;
                    ip_node.strip = m_stNodeData.strNodeIp;
                    ip_node.nport = m_stNodeData.nNodePort;
                    msginfo.vecall.push_back(ip_node);
                    S_IP_PORT ip_server;
                    ip_server.strip = pstInfo->strServerIp;
                    ip_server.nport = pstInfo->nServerPort;
                    msginfo.vecall.push_back(ip_server);
                    std::string strsendinfo = Msg2String(msginfo);
                    pdata->mapLocalNode[local] = node;
                    pdata->mapNodeOldGuid[node] = stroldguid;
                    pdata->mapNodeNewGuid[node] = strguid;
                    pdata->strServerIp = pstInfo->strServerIp;
                    pdata->nServerPort = pstInfo->nServerPort;
                    pdata->strTransNodeIp = m_stNodeData.strNodeIp;
                    pdata->nTransNodePort = m_stNodeData.nNodePort;
                    send(node, strsendinfo.c_str(), strsendinfo.size(), 0);
                }
            }
        }
    }
}

void CMYMULTIPORTMAP::OnRead(SOCKET s, char *buf, int len)
{
    if (s != INVALID_SOCKET && buf != NULL && len > 0)
    {
        SOCKET node = m_stNodeData.mapLocalNode[s];
        if (node > 0)
        {
            char szbuf[8192] = {0};
            memcpy(szbuf, buf, len);
            send(node, szbuf, len, 0);
            return;
        }
        else
        {
            for (std::map<SOCKET, SOCKET>::iterator it = m_stNodeData.mapLocalNode.begin(); it != m_stNodeData.mapLocalNode.end(); ++it)
            {
                if (it->second == s)
                {
                    char szbuf[8192] = {0};
                    memcpy(szbuf, buf, len);
                    send(it->first, szbuf, len, 0);
                    return;
                }
            }
        }
    }
}

void CMYMULTIPORTMAP::OnClose(SOCKET s)
{
    SOCKET node = m_stNodeData.mapLocalNode[s];
    if (node > 0)
    {
        closesocket(node);
        m_stNodeData.mapLocalNode.erase(s);
    }
    else
    {
        for (std::map<SOCKET, SOCKET>::iterator it = m_stNodeData.mapLocalNode.begin(); it != m_stNodeData.mapLocalNode.end(); ++it)
        {
            if (it->second == s)
            {
                closesocket(it->first);
                m_stNodeData.mapLocalNode.erase(it);
                break;
            }
        }
    }
}

void CMYMULTIPORTMAP::changenode()
{
    if (!m_vecNodeData.empty())
    {
        if (m_nNodeIndex + 1 >= m_vecNodeData.size())
            m_nNodeIndex = 0;
        else
            m_nNodeIndex += 1;

        S_NODE_DATA *pdata = m_vecNodeData[m_nNodeIndex];
        if (pdata != NULL)
        {
            //这里没有乱换阵容的时候 要求直接返回 否则有问题的.
            if (pdata->strNodeIp.compare(m_stNodeData.strNodeIp) == 0 && pdata->nNodePort == m_stNodeData.nNodePort)
                return;

            for (std::map<SOCKET, std::string>::iterator it = pdata->mapNodeOldGuid.begin(); it != pdata->mapNodeOldGuid.end(); ++it)
            {
                S_MSG_INFO msginfo;
                msginfo.strheader = gstrChangeHeader;
                msginfo.stroldguid = it->second;
                msginfo.strnewguid = pdata->mapNodeNewGuid[it->first];
                S_IP_PORT ip_server;
                ip_server.strip = pdata->strTransNodeIp;
                ip_server.nport = pdata->nTransNodePort;
                msginfo.vecall.push_back(ip_server);
                std::string strsendinfo = Msg2String(msginfo);
                SOCKET node;
                if (CMYIOCP::Connect((char *)pdata->strNodeIp.c_str(),  pdata->nNodePort, node))
                    send(node, strsendinfo.c_str(), strsendinfo.size(), 0);
            }

            if (m_stNodeData.strNodeIp.compare(m_strGameIp) == 0 && m_stNodeData.nNodePort == m_nGamePort)
                m_stNodeData = *pdata;
            else {
                S_NODE_DATA tempdata = *pdata;
                *pdata = m_stNodeData;
                m_stNodeData = tempdata;
            }

        }
    }
}

void CMYMULTIPORTMAP::insertnode(const std::string &strNodeIp, int nNodePort)
{
    if (m_stNodeData.strNodeIp.empty())
    {
        m_stNodeData.strNodeIp = strNodeIp;
        m_stNodeData.nNodePort = nNodePort;
        m_strGameIp = strNodeIp;
        m_nGamePort = nNodePort;
    }
    else
    {
        S_NODE_DATA *pdata = new S_NODE_DATA;
        pdata->nNodePort = nNodePort;
        pdata->strNodeIp = strNodeIp;
        m_vecNodeData.push_back(pdata);
    }
}

std::string CMYMULTIPORTMAP::getGuid()
{
    GUID guid;
#ifdef WIN32
    CoCreateGuid(&guid);
#else
    uuid_generate(reinterpret_cast<unsigned char *>(&guid));
#endif
    //return guid;

    char buf[64] = {0};
#ifdef __GNUC__
    snprintf(
#else // MSVC
    _snprintf_s(
#endif
        buf,
        sizeof(buf),
        "%08X%04X%04X%02X%02X%02X%02X%02X%02X%02X%02X",
        guid.Data1, guid.Data2, guid.Data3,
        guid.Data4[0], guid.Data4[1],
        guid.Data4[2], guid.Data4[3],
        guid.Data4[4], guid.Data4[5],
        guid.Data4[6], guid.Data4[7]);
    return std::string(buf);
}


std::string CMYMULTIPORTMAP::Msg2String(const S_MSG_INFO &msginfo)
{
    std::string strmsg = msginfo.strheader;
    for (std::vector<S_IP_PORT>::const_iterator it = msginfo.vecall.begin(); it != msginfo.vecall.end(); ++it)
    {
        strmsg += CENCDEC::new_ip_encode(it->strip);
        char szport[64] = {0};
        sprintf(szport, "%05d", it->nport);
        strmsg += CENCDEC::new_port_encode(szport);
    }
    strmsg += msginfo.stroldguid;
    strmsg += msginfo.strnewguid;
    return strmsg;
}

bool CMYMULTIPORTMAP::String2Msg(const std::string &strmsg, S_MSG_INFO &msginfo)
{
    bool bret = false;
    if (!strmsg.empty())
    {
        msginfo.strheader = strmsg.substr(0, 4);
        std::string strallinfo = strmsg.substr(4);
        if (strallinfo.size() >= 64)
        {
            msginfo.stroldguid = strallinfo.substr(strallinfo.size() - 64, 32);
            msginfo.strnewguid = strallinfo.substr(strallinfo.size() - 32, 32);
            std::string strallip = strallinfo.substr(0, strallinfo.size() - 64);
            if (!strallip.empty() && strallip.size() % 17 == 0)
            {
                int ncount = strallip.size() / 17;
                for (int nindex = 0; nindex < ncount; ++nindex){
                    std::string strencip = strallip.substr(nindex * 17, 12);
                    std::string strencport = strallip.substr(nindex * 17 + 12, 5);
                    S_IP_PORT stport;
                    stport.strip = CENCDEC::new_ip_decode(strencip);
                    stport.nport = atoi(CENCDEC::new_port_decode(strencport).c_str());
                    msginfo.vecall.push_back(stport);
                }
            }
            bret = true;
        }
    }
    return bret;
}

4.参考

1.http://blog.csdn.net/sky04/article/details/5667190
2.http://www.cnblogs.com/Hybird3D/archive/2012/02/04/2337652.html
3.实例下载地址:http://download.csdn.net/detail/zhang_ruiqiang/9808787
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值