ITPub博客

首页 > 架构设计 > 软件结构 > 网络通信1:字节流的封装

网络通信1:字节流的封装

原创 软件结构 作者:WolfHawk_ITPUB 时间:2020-05-20 11:04:46 0 删除 编辑

在网络通讯中,数据在网络传输的格式常以字节流的形式进行,因此需要我们对字节流进行写入和读出的操作。在几乎其他所有语言中,网络数据的收发在利用类似send(或write)和recv(或read)的方法时并没有明显的流处理。需要借助流才可以完成。数据流(data stream)是一组有序,有起点和终点的字节的数据序列。包括输入流和输出流。很多语言常将数据流分为输入流(InputStream)和输出流(OutputStream)两类。输入流只能读不能写,而输出流只能写不能读。通常程序中使用输入流读出数据,输出流写入数据,就好像数据流入到程序并从程序中流出。

为了提高数据的传输效率,通常使用缓冲流(Buffered Stream),即为一个流配有一个缓冲区(buffer),一个缓冲区就是专门用于传输数据的内存块。当向一个缓冲流写入数据时,系统不直接发送到外部设备,而是将数据发送到缓冲区。缓冲区自动记录数据,当缓冲区满时,系统将数据全部发送到相应的设备。当从一个缓冲流中读取数据时,系统实际是从缓冲区中读取数据。当缓冲区空时,系统就会从相关设备自动读取数据,并读取尽可能多的数据充满缓冲区。缓冲字节输入输出流,相对于基础的字节流有更高的效率,而效率更高的原理在于用空间换取时间。 也就是说使用缓冲流的时候,会先把一定的数据放到缓冲区,也就是内存中,然后read的时候直接从缓冲区读取,这样就减少了读写磁盘文件的次数,从而减少读写时间。

根据上面的原理能否实现字节流构造器。兼容输入流,输出流,缓冲流的功能。便于数据的组织和传输。同时兼容HTTP协议,TCP协议,UDP协议兼容的字节流。代码功能越独立越便于兼容。

C++实现网络数据流读取类:Gk8ByteMaker.h

//**************************************************************
//@创建者:冰剑
//@功能描述①:网络数据流读取类:支持脚本中直接根据模板使用
//@功能描述②:注意服务器JAVA的高低位问题
//@功能描述③:
//**************************************************************
#ifndef __GK8NETBREADER_H__
#define __GK8NETBREADER_H__
#pragma once
#include "Gk8Env.h"
#include "Gk8PlatformDefine.h"
#include "Gk8BaseObj.h"
class Gk8ByteMaker:public Gk8BaseObj
{
    DECLARE_TOSPP_MAP;    
protected:
    GK8_LPBYTE m_pBuf;        //[数据缓存]
    GK8_INT m_nUseSize;        //[使用大小]
    GK8_INT m_nBufSize;        //[缓存分配大小]
    GK8_INT m_nReadPos;        //[读取位置]
public:
    Gk8ByteMaker():m_pBuf(NULL),m_nReadPos(0),m_nUseSize(0),m_nBufSize(0){};
    ~Gk8ByteMaker();
    static Gk8ByteMaker* Create(Gk8BaseObj* pSuperObj=NULL);
    //[属性操作]
    TOSPP_MEMBER_INT_DECLARE(m_nReadPos,m_nReadPos)
    inline GK8_INT TOSPPFUNC GetStreamSize()const{return m_nUseSize;};
    GK8_LPBYTE WriteAlloc(GK8_INT nSize);
    //[读行为操作]
    GK8_BOOL Get(GK8_LPBYTE lpPtr,GK8_INT nLen)const;
    GK8_LPBYTE GetBuf(GK8_INT& nLen);
    inline GK8_LPBYTE GetBuf(){return m_pBuf;};
    inline operator GK8_LPBYTE (){return GetBuf();};
    GK8_VOID WriteBuf(GK8_LPCVOID lpPtr,GK8_INT nLen);
    GK8_VOID TOSPPFUNC WriteShort(GK8_INT nData);
    GK8_VOID TOSPPFUNC WriteInt(GK8_INT nData);
    GK8_VOID TOSPPFUNC WriteStr(GK8_LPCSTR lpStr);
    //[前面写入操作]
    GK8_VOID TOSPPFUNC WriteShortAt(GK8_INT nIndex,GK8_INT nData);
    GK8_VOID TOSPPFUNC WriteIntAt(GK8_INT nIndex,GK8_INT nData);
    GK8_VOID TOSPPFUNC WriteStrAt(GK8_INT nIndex,GK8_LPCSTR lpStr);
    //[读取操作]
    GK8_INT TOSPPFUNC ReadShort();
    GK8_INT TOSPPFUNC ReadInt();
    GK8_LPCSTR TOSPPFUNC ReadStr();
    GK8_LONG TOSPPFUNC ReadLong();
    //[其它行为操作]
    GK8_VOID ShiftTo(Gk8ByteMaker& iNetBReader);
    inline GK8_VOID SetReadPos(GK8_INT nReadPos){m_nReadPos=nReadPos;};
    inline GK8_VOID TOSPPFUNC ClearStream(){m_nUseSize=0;};
    GK8_VOID Pack();
    GK8_VOID Destroy();
};
#endif

C++实现网络数据流读取类:Gk8ByteMaker.cpp

#include "Gk8ByteMaker.h"
#include "Gk8MemSpy.h"
#include "Gk8Str.h"
#include "Gk8Helper.h"
/////////////////////////////////////////////CLASS-TOLUA////////////////////////////////////////////////////
TOLUA_CLASS_COLLECT_FUNC(Gk8ByteMaker)
BEGIN_TOLUA_CLASS_FUNC(Gk8ByteMaker,Create)
    if(!CheckToLuaFunParam(L,"Create",Gk8Var()<<ISUSERTABLE("Gk8ByteMaker"))) return 0;
    Gk8BaseObj* pSuperObj=NULL;
    if(IFUSERTYPE(2,Gk8BaseObj)) pSuperObj=TOLUAGETOBJ(Gk8BaseObj,2);
    Gk8ByteMaker* pByteMaker=Gk8ByteMaker::Create(pSuperObj);
    toluafix_pushusertype_ccobject(L,TOLUAOBJID(pByteMaker),TOLUALPLUAID(pByteMaker),(GK8_LPVOID)pByteMaker,"Gk8ByteMaker");
END_TOLUA_CLASS_FUNC
BEGIN_TOLUA_CLASS_FUNC(Gk8ByteMaker,GetStreamSize)
    if(!CheckToLuaFunParam(L,"GetStreamSize",Gk8Var()<<ISUSERTYPE("Gk8ByteMaker")<<ISNOOBJ)) return 0;
    tolua_pushnumber(L,(lua_Number)TOLUAGETOBJ(Gk8ByteMaker,1)->GetStreamSize());
END_TOLUA_CLASS_FUNC
BEGIN_TOLUA_CLASS_FUNC(Gk8ByteMaker,WriteShort)
    if(!CheckToLuaFunParam(L,"WriteShort",Gk8Var()<<ISUSERTYPE("Gk8ByteMaker")<<ISNUMBER<<ISNOOBJ)) return 0;
    TOLUAGETOBJ(Gk8ByteMaker,1)->WriteShort(TOLUAGETINT(2));
END_TOLUA_CLASS_FUNC
BEGIN_TOLUA_CLASS_FUNC(Gk8ByteMaker,WriteInt)
    if(!CheckToLuaFunParam(L,"WriteInt",Gk8Var()<<ISUSERTYPE("Gk8ByteMaker")<<ISNUMBER<<ISNOOBJ)) return 0;
    TOLUAGETOBJ(Gk8ByteMaker,1)->WriteInt(TOLUAGETINT(2));
END_TOLUA_CLASS_FUNC
BEGIN_TOLUA_CLASS_FUNC(Gk8ByteMaker,WriteStr)
    if(!CheckToLuaFunParam(L,"WriteStr",Gk8Var()<<ISUSERTYPE("Gk8ByteMaker")<<ISSTRING<<ISNOOBJ)) return 0;
    TOLUAGETOBJ(Gk8ByteMaker,1)->WriteStr(TOLUAGETSTRING(2));
END_TOLUA_CLASS_FUNC
BEGIN_TOLUA_CLASS_FUNC(Gk8ByteMaker,WriteShortAt)
    if(!CheckToLuaFunParam(L,"WriteShortAt",Gk8Var()<<ISUSERTYPE("Gk8ByteMaker")<<ISNUMBER<<ISNUMBER<<ISNOOBJ)) return 0;
    TOLUAGETOBJ(Gk8ByteMaker,1)->WriteShortAt(TOLUAGETINT(2),TOLUAGETINT(3));
END_TOLUA_CLASS_FUNC
BEGIN_TOLUA_CLASS_FUNC(Gk8ByteMaker,WriteIntAt)
    if(!CheckToLuaFunParam(L,"WriteIntAt",Gk8Var()<<ISUSERTYPE("Gk8ByteMaker")<<ISNUMBER<<ISNUMBER<<ISNOOBJ)) return 0;
    TOLUAGETOBJ(Gk8ByteMaker,1)->WriteIntAt(TOLUAGETINT(2),TOLUAGETINT(3));
END_TOLUA_CLASS_FUNC
BEGIN_TOLUA_CLASS_FUNC(Gk8ByteMaker,WriteStrAt)
    if(!CheckToLuaFunParam(L,"WriteStrAt",Gk8Var()<<ISUSERTYPE("Gk8ByteMaker")<<ISSTRING<<ISNUMBER<<ISNOOBJ)) return 0;
    TOLUAGETOBJ(Gk8ByteMaker,1)->WriteStrAt(TOLUAGETINT(2),TOLUAGETSTRING(3));
END_TOLUA_CLASS_FUNC
BEGIN_TOLUA_CLASS_FUNC(Gk8ByteMaker,ReadShort)
    if(!CheckToLuaFunParam(L,"ReadShort",Gk8Var()<<ISUSERTYPE("Gk8ByteMaker")<<ISNOOBJ)) return 0;
    tolua_pushnumber(L,(lua_Number)TOLUAGETOBJ(Gk8ByteMaker,1)->ReadShort());
END_TOLUA_CLASS_FUNC
BEGIN_TOLUA_CLASS_FUNC(Gk8ByteMaker,ReadInt)
    if(!CheckToLuaFunParam(L,"ReadInt",Gk8Var()<<ISUSERTYPE("Gk8ByteMaker")<<ISNOOBJ)) return 0;
    tolua_pushnumber(L,(lua_Number)TOLUAGETOBJ(Gk8ByteMaker,1)->ReadInt());
END_TOLUA_CLASS_FUNC
BEGIN_TOLUA_CLASS_FUNC(Gk8ByteMaker,ReadStr)
    if(!CheckToLuaFunParam(L,"ReadStr",Gk8Var()<<ISUSERTYPE("Gk8ByteMaker")<<ISNOOBJ)) return 0;
    tolua_pushstring(L,TOLUAGETOBJ(Gk8ByteMaker,1)->ReadStr());
END_TOLUA_CLASS_FUNC
BEGIN_TOLUA_CLASS_FUNC(Gk8ByteMaker,ReadLong)
    if(!CheckToLuaFunParam(L,"ReadLong",Gk8Var()<<ISUSERTYPE("Gk8ByteMaker")<<ISNOOBJ)) return 0;
    tolua_pushnumber(L,(lua_Number)TOLUAGETOBJ(Gk8ByteMaker,1)->ReadLong());
END_TOLUA_CLASS_FUNC
BEGIN_TOLUA_CLASS_FUNC(Gk8ByteMaker,SetReadPos)
    if(!CheckToLuaFunParam(L,"SetReadPos",Gk8Var()<<ISUSERTYPE("Gk8ByteMaker")<<ISNUMBER<<ISNOOBJ)) return 0;
    TOLUAGETOBJ(Gk8ByteMaker,1)->SetReadPos(TOLUAGETINT(2));
END_TOLUA_CLASS_FUNC
BEGIN_TOLUA_CLASS_FUNC(Gk8ByteMaker,ClearStream)
    if(!CheckToLuaFunParam(L,"ClearStream",Gk8Var()<<ISUSERTYPE("Gk8ByteMaker")<<ISNOOBJ)) return 0;
    TOLUAGETOBJ(Gk8ByteMaker,1)->ClearStream();
END_TOLUA_CLASS_FUNC
//[启动注册类的全部TOLUA函数]
BEGIN_TOLUA_FUN_MAP(Gk8ByteMaker)
    TOLUA_CLASS(Gk8ByteMaker,"","[]","[]")
    TOLUA_CLASS_FUNC(Gk8ByteMaker,Create,"[Gk8ByteMaker* Create(pSuperObj=NULL)?创建对象]")
    TOLUA_CLASS_FUNC(Gk8ByteMaker,GetStreamSize,"[]")
    TOLUA_CLASS_FUNC(Gk8ByteMaker,WriteShort,"[]")
    TOLUA_CLASS_FUNC(Gk8ByteMaker,WriteInt,"[]")
    TOLUA_CLASS_FUNC(Gk8ByteMaker,WriteStr,"[]")
    TOLUA_CLASS_FUNC(Gk8ByteMaker,WriteShortAt,"[]")
    TOLUA_CLASS_FUNC(Gk8ByteMaker,WriteIntAt,"[]")
    TOLUA_CLASS_FUNC(Gk8ByteMaker,WriteStrAt,"[]")
    TOLUA_CLASS_FUNC(Gk8ByteMaker,ReadShort,"[]")
    TOLUA_CLASS_FUNC(Gk8ByteMaker,ReadInt,"[]")
    TOLUA_CLASS_FUNC(Gk8ByteMaker,ReadStr,"[]")
    TOLUA_CLASS_FUNC(Gk8ByteMaker,ReadLong,"[]")
    TOLUA_CLASS_FUNC(Gk8ByteMaker,SetReadPos,"[]")
    TOLUA_CLASS_FUNC(Gk8ByteMaker,ClearStream,"[]")
END_TOLUA_FUN_MAP
/////////////////////////////////////////////CLASS-TOSPP////////////////////////////////////////////////////
BEGIN_TOSPP_MAP(Gk8ByteMaker,Gk8BaseObj)
    TOSPP_INT(Gk8ByteMaker,m_nReadPos,"m_nReadPos" ,"")
    TOSPP_FUNC(Gk8ByteMaker,GetStreamSize,'d'," ","GetStreamSize()")
    TOSPP_FUNC(Gk8ByteMaker,WriteShort,' ',"d","WriteShort(nData)")
    TOSPP_FUNC(Gk8ByteMaker,WriteInt,' ',"d","WriteInt(nData)")
    TOSPP_FUNC(Gk8ByteMaker,WriteStr,' ',"s","WriteStr(lpStr)")
    TOSPP_FUNC(Gk8ByteMaker,WriteShortAt,' ',"dd","WriteShortAt(nIndex,nData)")
    TOSPP_FUNC(Gk8ByteMaker,WriteIntAt,' ',"dd","WriteIntAt(nIndex,nData)")
    TOSPP_FUNC(Gk8ByteMaker,WriteStrAt,' ',"ds","WriteStrAt(nIndex,lpStr)")
    TOSPP_FUNC(Gk8ByteMaker,ReadShort,'d'," ","ReadShort()")
    TOSPP_FUNC(Gk8ByteMaker,ReadInt,'d'," ","ReadInt()")
    TOSPP_FUNC(Gk8ByteMaker,ReadStr,'s'," ","ReadStr()")
    TOSPP_FUNC(Gk8ByteMaker,ReadLong,'P'," ","ReadLong()")
    TOSPP_FUNC(Gk8ByteMaker,ClearStream,' '," ","ClearStream()")
END_TOSPP_MAP()
///////////////////////////[网络二进制读取逻辑]///////////////////
Gk8ByteMaker::~Gk8ByteMaker()
{
    if(m_pBuf) _Gk8Free(m_pBuf);
}
Gk8ByteMaker* Gk8ByteMaker::Create(Gk8BaseObj* pSuperObj)
{
    Gk8ByteMaker* pByteMaker=new Gk8ByteMaker();
    if(pSuperObj) pByteMaker->SetSuper(pSuperObj);
    return pByteMaker;
}
TOSPP_MEMBER_INT_FUN(Gk8ByteMaker,m_nReadPos,m_nReadPos)
//[提前增加指定长度的内存块]
GK8_LPBYTE Gk8ByteMaker::WriteAlloc(GK8_INT nSize)
{
    if(nSize>=1)
    {
        if(nSize+m_nUseSize>=m_nBufSize)
        {
            GK8_UINT nNewSize;
            m_pBuf=(GK8_LPBYTE)_Gk8ReAlloc(m_pBuf,m_nUseSize+nSize+32,nNewSize);
            m_nBufSize=nNewSize;
        }
        m_nUseSize+=nSize;
        return m_pBuf+m_nUseSize-nSize;
    }
    return NULL;
}
//[获取指定长度的二进制数据]
GK8_BOOL Gk8ByteMaker::Get(GK8_LPBYTE lpPtr,GK8_INT nLen)const
{
    if(m_nUseSize>=nLen) memcpy(lpPtr,m_pBuf,nLen);
    return true;
}
//[获取数据的内存指针]
GK8_LPBYTE Gk8ByteMaker::GetBuf(GK8_INT& nLen)
{
    nLen=m_nUseSize;
    return m_pBuf;
}
//[增加指定长度的二进制数据]
GK8_VOID Gk8ByteMaker::WriteBuf(GK8_LPCVOID lpPtr,GK8_INT nLen)
{
    GK8_LPBYTE pMem=WriteAlloc(nLen);
    memcpy(pMem,lpPtr,nLen);
}
GK8_VOID Gk8ByteMaker::WriteShort(GK8_INT nData)
{
    GK8_LPBYTE pMem=WriteAlloc(sizeof(GK8_WORD));
    GK8_LPBYTE pDataMem=(GK8_LPBYTE)&nData;
    pMem[0]=pDataMem[1];
    pMem[1]=pDataMem[0];
}
GK8_VOID Gk8ByteMaker::WriteInt(GK8_INT nData)
{
    GK8_LPBYTE pMem=WriteAlloc(sizeof(GK8_INT));
    GK8_LPBYTE pDataMem=(GK8_LPBYTE)&nData;
    pMem[0]=pDataMem[3];
    pMem[1]=pDataMem[2];
    pMem[2]=pDataMem[1];
    pMem[3]=pDataMem[0];
}
GK8_VOID Gk8ByteMaker::WriteStr(GK8_LPCSTR lpStr)
{
    Gk8Str iStr=lpStr;
    WriteShort(iStr.GetLength());
    WriteBuf(iStr,iStr.GetLength());
}
GK8_VOID Gk8ByteMaker::WriteShortAt(GK8_INT nIndex,GK8_INT nData)
{
    GK8_INT nLen=sizeof(GK8_WORD);
    WriteAlloc(nLen);
    memmove(m_pBuf+nIndex+nLen,m_pBuf+nIndex,m_nUseSize-nLen-nIndex);
    GK8_LPBYTE pDataMem=(GK8_LPBYTE)&nData;
    m_pBuf[nIndex]=pDataMem[1];
    m_pBuf[nIndex+1]=pDataMem[0];
}
GK8_VOID Gk8ByteMaker::WriteIntAt(GK8_INT nIndex,GK8_INT nData)
{
    GK8_INT nLen=sizeof(GK8_INT);
    WriteAlloc(nLen);
    memmove(m_pBuf+nIndex+nLen,m_pBuf+nIndex,m_nUseSize-nLen-nIndex);
    GK8_LPBYTE pDataMem=(GK8_LPBYTE)&nData;
    m_pBuf[nIndex]=pDataMem[3];
    m_pBuf[nIndex+1]=pDataMem[2];
    m_pBuf[nIndex+2]=pDataMem[1];
    m_pBuf[nIndex+3]=pDataMem[0];
}
GK8_VOID Gk8ByteMaker::WriteStrAt(GK8_INT nIndex,GK8_LPCSTR lpStr)
{
    Gk8Str iStr=lpStr;
    GK8_INT nStrLen=iStr.GetLength();
    GK8_INT nLen=sizeof(GK8_WORD)+nStrLen;
    WriteAlloc(nLen);
    memmove(m_pBuf+nIndex+nLen,m_pBuf+nIndex,m_nUseSize-nLen-nIndex);
    GK8_LPBYTE pDataMem=(GK8_LPBYTE)&nStrLen;
    m_pBuf[nIndex]=pDataMem[1];
    m_pBuf[nIndex+1]=pDataMem[0];
    memcpy(m_pBuf+nIndex+sizeof(GK8_WORD),iStr,nStrLen);
}
GK8_INT Gk8ByteMaker::ReadShort()
{
    if(m_nReadPos>m_nUseSize-sizeof(GK8_WORD)) return NULL;
    GK8_INT nData;
    GK8_LPBYTE pDataMem=(GK8_LPBYTE)&nData;
    memset(pDataMem,0,sizeof(GK8_INT));
    pDataMem[1]=m_pBuf[m_nReadPos];
    pDataMem[0]=m_pBuf[m_nReadPos+1];
    m_nReadPos+=sizeof(GK8_WORD);
    return nData;
}
GK8_INT Gk8ByteMaker::ReadInt()
{
    if(m_nReadPos>m_nUseSize-sizeof(GK8_INT)) return 0;
    GK8_INT nData;
    GK8_LPBYTE pDataMem=(GK8_LPBYTE)&nData;
    memset(pDataMem,0,sizeof(GK8_INT));
    pDataMem[3]=m_pBuf[m_nReadPos];
    pDataMem[2]=m_pBuf[m_nReadPos+1];
    pDataMem[1]=m_pBuf[m_nReadPos+2];
    pDataMem[0]=m_pBuf[m_nReadPos+3];
    m_nReadPos+=sizeof(GK8_INT);
    return nData;
}
GK8_LPCSTR Gk8ByteMaker::ReadStr()
{
    if(m_nReadPos>m_nUseSize-sizeof(GK8_WORD)) return NULL;
    GK8_INT nLen;
    GK8_LPBYTE pDataMem=(GK8_LPBYTE)&nLen;
    memset(pDataMem,0,sizeof(GK8_INT));
    pDataMem[1]=m_pBuf[m_nReadPos];
    pDataMem[0]=m_pBuf[m_nReadPos+1];
    m_nReadPos+=sizeof(GK8_WORD);
    Gk8Str iStr;
    iStr.SetStr((GK8_LPCSTR)(m_pBuf+m_nReadPos),nLen);
    m_nReadPos+=nLen;
    return iStr;
}
GK8_LONG Gk8ByteMaker::ReadLong()
{
    return 0;
}
//[克隆到另外一个实体中]
GK8_VOID Gk8ByteMaker::ShiftTo(Gk8ByteMaker& iBReader)
{
    iBReader.Destroy();
    iBReader.m_pBuf=m_pBuf;
    iBReader.m_nUseSize=m_nUseSize;
    iBReader.m_nBufSize=m_nBufSize;
    iBReader.m_nReadPos=m_nReadPos;
    m_pBuf=NULL;
    m_nBufSize=0;
    m_nUseSize=0;
    m_nReadPos=0;
}
//[整理数据:前面有内存已读取后面空余前移动]
GK8_VOID Gk8ByteMaker::Pack()
{
    if(m_nReadPos==m_nUseSize)
    {
        m_nUseSize=0;
        m_nReadPos=0;
        return;
    }
    memmove(m_pBuf,m_pBuf+m_nReadPos,m_nUseSize-m_nReadPos);
    m_nUseSize-=m_nReadPos;
    m_nReadPos=0;
}
//[销毁]
GK8_VOID Gk8ByteMaker::Destroy()
{
    if(m_pBuf) _Gk8Free(m_pBuf);
    m_pBuf=NULL;
    m_nUseSize=0;
    m_nBufSize=0;
    m_nReadPos=0;
}

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/69975060/viewspace-2693162/,如需转载,请注明出处,否则将追究法律责任。

上一篇: 表结构对比版本
全部评论
从事游戏研发10年。经历端游,页游,手游的时代。精通游戏技术架构和丰富的游戏项目经验。自己写过服务器框架和客户端引擎。希望沉淀的经验和大家交流与分享。

注册时间:2020-05-19

  • 博文量
    11
  • 访问量
    3222