因为历史缘由,咱们目前看到的大部分的网络协议都是基于ASCII码这种纯文本方式,也就是基于字符串的命令行方式,好比HTTP、FTP、POP三、SMTP、Telnet等。早期操做系统UNIX(或DOS),用户操做界面就是控制台,控制台的输入输出方式就决定了用户只能经过敲击键盘的方式将协议命令输入到网络,这也就致使了回车换行"\r\n"会做为一次命令结束的标识。html
好比HTTP协议,与主机创建链接后,输入"GET / HTTP/1.1\r\n"便可获取网站的主页。web
好比email协议,早期的电子邮件协议只支持ASCII码这种纯文本传输,但随着全世界人民对物质文化生活的不断向往,这种落后的传输方式,已经没法知足世界人民对美好生活的追求,好比图像、视频、音频、Office文件如何在邮件中展示?不一样国家(非英语国家)字符集该如何传输和展示?windows
换句话说,就是这种非ASCII的二进制富文本,该如何传输和呈现?缓存
此时MIME标准诞生了,MIME的出现更多的是一种向下兼容的无奈,而不是革命。经过对二进制数据或非ASCII码数据进行base64或quoted-printable编码,来实现纯ASCII码的传输。显然这种方式会让你的邮件体变大,传输效率降低。尤为附件不少时,经过MIME的boundary来解析邮件的附件也是一笔额外的负担。服务器
同时MIME的标准也被HTTP协议所采用,咱们能够经过content-type指定传输的内容是什么类型,经过MIME的boundary来对Form-Data数据进行扩展,让咱们Post数据时也可以在“表格”数据中插入文件,从而达到上传文件的效果。websocket
显然这种方式不如二进制简洁,但却很是的直观,所见即所得,一眼就能看明白。但就传输效率上不如二进制方式。网络
又好比websocket协议虽然创建会话时采用的是HTTP协议,但后续的数据帧格式倒是一个二进制格式。以下:
socket
在这种格式下,为了表示每帧数据长度,就必定会有一个“数据长度”项,好比上面的payload len,当该值小于126时,直接表示数据区(payload data)长度;为126时用后面的2个字节表示数据区长度,为127时用后面的8个字节表示数据区长度。此时就涉及到了网络字节序和主机字节序的转换,若是数据区是一个二进制内容的话,咱们就很难使用string的操做方式将整个数据报文拼接起来(能够用memcpy来拼接)。固然,咱们这篇文章不是对websocket协议的讲解,而是经过该协议的数据区引出二进制数据流封装的必要性。若是是文本协议,各类开发语言对string的封装已经足够强大,已经没有封装的必要。除非你想从新改造字符串操做来提高效率或其它目的,好比个人前一篇文章:
为什么写服务器程序须要本身管理内存,从改造std::string字符串操做提及。。。
话很少说,下面是一个简单的数据流的封装类CDataStream,很是简单。函数
.h头文件测试
#include <windows.h> // 数据流 class CDataStream { public: CDataStream(BOOL bNetworkOrder = FALSE); virtual ~CDataStream(); // 关联一块stream void Attach(const BYTE* pStream, int iStreamSize){ m_pStream = (BYTE*)pStream; m_iStreamSize = iStreamSize; m_iCurrPos = 0; } // 解除关联 void Detach(){ m_pStream = NULL; m_iStreamSize = 0; m_iCurrPos = 0; } void Reset(){ m_iCurrPos = 0; } // 获取流数据 const BYTE* GetStreamData(){ return m_pStream; } int GetStreamSize(){ return m_iCurrPos; } // 在当前位置上移动iDistance距离 int Offset(int iDistance); // 移动到新位置 int MoveTo(int iNewPos); void MoveToBegin(){ m_iCurrPos = 0; } void MoveToEnd(){ m_iCurrPos = m_iStreamSize; } // 读写字节 void WriteByte(BYTE byValue); BYTE ReadByte(); // 读写WORD void WriteWord(WORD wValue); WORD ReadWord(); // 读写DWORD void WriteDWord(DWORD dwValue); DWORD ReadDWord(); // 读写int64 void WriteInt64(__int64 i64Value); __int64 ReadInt64(); // 读写Float void WriteFloat(float fValue); float ReadFloat(); // 读写double void WriteDouble(double dValue); double ReadDouble(); // 读写数据流 void WriteData(unsigned char* pData, int iDataLen); BYTE* ReadData(int iDataLen); // 读写字符串 void WriteString(const char* pszValue); const char* ReadString(); // =============运算符重载============= CDataStream& operator<<(BYTE byValue) { WriteByte(byValue); return *this; } CDataStream& operator<<(WORD wValue) { WriteWord(wValue); return *this; } CDataStream& operator<<(DWORD dwValue) { WriteDWord(dwValue); return *this; } CDataStream& operator<<(__int64 i64Value) { WriteInt64(i64Value); return *this; } CDataStream& operator<<(float fValue) { WriteFloat(fValue); return *this; } CDataStream& operator<<(double dValue) { WriteDouble(dValue); return *this; } CDataStream& operator<<(const char* pszValue) { WriteString(pszValue); return *this; } CDataStream& operator>>(BYTE& byValue) { byValue = ReadByte(); return *this; } CDataStream& operator>>(WORD& wValue) { wValue = ReadWord(); return *this; } CDataStream& operator>>(DWORD& dwValue) { dwValue = ReadDWord(); return *this; } CDataStream& operator>>(__int64& i64Value) { i64Value = ReadInt64(); return *this; } CDataStream& operator>>(float& fValue) { fValue = ReadFloat(); return *this; } CDataStream& operator>>(double& dValue) { dValue = ReadDouble(); return *this; } CDataStream& operator>>(const char*& pszValue) { pszValue = ReadString(); return *this; } public: // WORD值反序 static WORD Swap(WORD wValue){ WORD wRet = 0; ((BYTE*)&wRet)[0] = ((BYTE*)&wValue)[1]; ((BYTE*)&wRet)[1] = ((BYTE*)&wValue)[0]; return wRet; } // DWORD反序 static DWORD Swap(DWORD dwValue){ DWORD dwRet = 0; ((BYTE*)&dwRet)[0] = ((BYTE*)&dwValue)[3]; ((BYTE*)&dwRet)[1] = ((BYTE*)&dwValue)[2]; ((BYTE*)&dwRet)[2] = ((BYTE*)&dwValue)[1]; ((BYTE*)&dwRet)[3] = ((BYTE*)&dwValue)[0]; return dwRet; } // i64(long long)反序 static __int64 Swap(__int64 i64Value){ __int64 i64Ret = 0; ((BYTE*)&i64Ret)[0] = ((BYTE*)&i64Value)[7]; ((BYTE*)&i64Ret)[1] = ((BYTE*)&i64Value)[6]; ((BYTE*)&i64Ret)[2] = ((BYTE*)&i64Value)[5]; ((BYTE*)&i64Ret)[3] = ((BYTE*)&i64Value)[4]; ((BYTE*)&i64Ret)[4] = ((BYTE*)&i64Value)[3]; ((BYTE*)&i64Ret)[5] = ((BYTE*)&i64Value)[2]; ((BYTE*)&i64Ret)[6] = ((BYTE*)&i64Value)[1]; ((BYTE*)&i64Ret)[7] = ((BYTE*)&i64Value)[0]; return i64Ret; } // 下面的函数也是将64位长整形反序,但比较难理解,不如上面的函数简单、粗暴和直观 // 即便你如今能整明白,下次未必能“见字如面” static __int64 Swap64(__int64 i64Value) { return i64Value >> 56| (i64Value & 0x00ff000000000000) >> 40 | (i64Value & 0x0000ff0000000000) >> 24 | (i64Value & 0x000000ff00000000) >> 8 | (i64Value & 0x00000000ff000000) << 8 | (i64Value & 0x0000000000ff0000) << 24 | (i64Value & 0x000000000000ff00) << 40 | i64Value << 56; } // 浮点型按照IEEE745标准不存在网络字节序和机器字节序,这里只是给出实现方法 // float反序 static float Swap(float fValue){ float fRet = fValue; Swap((BYTE*)&fRet, sizeof(float)); return fRet; } // double反序 static double Swap(double dValue){ double dRet = dValue; Swap((BYTE*)&dRet, sizeof(double)); return dRet; } // 内存数据反序 static void Swap(BYTE* pData, int iDataLen); // 内存反序后返回新内存 static BYTE* SwapClone(BYTE* pData, int iDataLen); protected: BOOL m_bNetworkOrder; // 数据流是否为网络字节序,缺省为FALSE BYTE *m_pStream; // stream缓存 int m_iStreamSize; // 缓存大小 int m_iCurrPos; // 当前数据位置 };
.cpp实现文件
#include "DataStream.h" #include <assert.h> #include <stdlib.h> // 将一块内存反序 void CDataStream::Swap(BYTE* pData, int iDataLen) { if(NULL == pData || iDataLen <= 0) return; for(int i = 0 ; i < iDataLen / 2; i++) { BYTE temp = pData[i]; pData[i] = pData[iDataLen - i - 1]; pData[iDataLen - i - 1] = temp; } } // 将一块内存反序后返回新内存 BYTE* CDataStream::SwapClone(BYTE* pData, int iDataLen) { if(NULL == pData || iDataLen <= 0) return NULL; BYTE* pSwap = (BYTE*)malloc(iDataLen); int j = 0; for(int i = iDataLen-1; i >= 0; i--) { pSwap[j] = pData[i]; j++; } return pSwap; } ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// CDataStream::CDataStream(BOOL bNetworkOrder) { m_bNetworkOrder = bNetworkOrder; m_pStream = NULL; m_iStreamSize = 0; m_iCurrPos = 0; } CDataStream::~CDataStream() { m_pStream = NULL; m_iStreamSize = 0; m_iCurrPos = 0; } // 在当前位置上移动iDistance距离 int CDataStream::Offset(int iDistance) { int iNewPos = m_iCurrPos+iDistance; if(iNewPos < 0) m_iCurrPos = 0; else if(iNewPos > m_iStreamSize) m_iCurrPos = m_iStreamSize; else m_iCurrPos = iNewPos; return m_iCurrPos; } // 移动到新位置 int CDataStream::MoveTo(int iNewPos) { if(iNewPos < 0) m_iCurrPos = 0; else if(iNewPos > m_iStreamSize) m_iCurrPos = m_iStreamSize; else m_iCurrPos = iNewPos; return m_iCurrPos; } // 读写字节 void CDataStream::WriteByte(BYTE byValue) { assert(m_iCurrPos+1 <= m_iStreamSize); // 越界断言 if(m_iCurrPos+1 > m_iStreamSize) return; *(m_pStream+m_iCurrPos) = byValue; m_iCurrPos++; } BYTE CDataStream::ReadByte() { assert(m_iCurrPos+1 <= m_iStreamSize); // 越界断言 if(m_iCurrPos+1 > m_iStreamSize) return 0; BYTE byValue = *(m_pStream+m_iCurrPos); m_iCurrPos++; return byValue; } // 读写WORD void CDataStream::WriteWord(WORD wValue) { assert(m_iCurrPos+2 <= m_iStreamSize); // 越界断言 if(m_iCurrPos+2 > m_iStreamSize) return; // 若是是网络字节流则反序 if(m_bNetworkOrder) wValue = Swap(wValue); *(WORD*)(m_pStream+m_iCurrPos) = wValue; m_iCurrPos += 2; } WORD CDataStream::ReadWord() { assert(m_iCurrPos+2 <= m_iStreamSize); // 越界断言 if(m_iCurrPos+2 > m_iStreamSize) return 0; WORD wValue = *(WORD*)(m_pStream+m_iCurrPos); m_iCurrPos += 2; // 若是是网络字节流则反序 if(m_bNetworkOrder) wValue = Swap(wValue); return wValue; } // 读写DWORD void CDataStream::WriteDWord(DWORD dwValue) { assert(m_iCurrPos+4 <= m_iStreamSize); // 越界断言 if(m_iCurrPos+4 > m_iStreamSize) return; // 若是是网络字节流则反序 if(m_bNetworkOrder) dwValue = Swap(dwValue); *(DWORD*)(m_pStream+m_iCurrPos) = dwValue; m_iCurrPos += 4; } DWORD CDataStream::ReadDWord() { assert(m_iCurrPos+4 <= m_iStreamSize); // 越界断言 if(m_iCurrPos+4 > m_iStreamSize) return 0; DWORD dwValue = *(DWORD*)(m_pStream+m_iCurrPos); m_iCurrPos += 4; // 若是是网络字节流则反序 if(m_bNetworkOrder) dwValue = Swap(dwValue); return dwValue; } // 读写int64 void CDataStream::WriteInt64(__int64 i64Value) { assert(m_iCurrPos+8 <= m_iStreamSize); // 越界断言 if(m_iCurrPos+8 > m_iStreamSize) return; // 若是是网络字节流则反序 if(m_bNetworkOrder) i64Value = Swap(i64Value); *(__int64*)(m_pStream+m_iCurrPos) = i64Value; m_iCurrPos += 8; } __int64 CDataStream::ReadInt64() { assert(m_iCurrPos+8 <= m_iStreamSize); // 越界断言 if(m_iCurrPos+8 > m_iStreamSize) return 0; __int64 i64Value = *(__int64*)(m_pStream+m_iCurrPos); m_iCurrPos += 8; // 若是是网络字节流则反序 if(m_bNetworkOrder) i64Value = Swap(i64Value); return i64Value; } // 读写float void CDataStream::WriteFloat(float fValue) { int iFloatSize = sizeof(float); assert(m_iCurrPos+iFloatSize <= m_iStreamSize); if(m_iCurrPos+iFloatSize > m_iStreamSize) return; *(float*)(m_pStream+m_iCurrPos) = fValue; m_iCurrPos += iFloatSize; } float CDataStream::ReadFloat() { int iFloatSize = sizeof(float); assert(m_iCurrPos+iFloatSize <= m_iStreamSize); if(m_iCurrPos+iFloatSize > m_iStreamSize) return 0; float fValue = *(float*)(m_pStream+m_iCurrPos); m_iCurrPos += iFloatSize; return fValue; } // 读写double void CDataStream::WriteDouble(double dValue) { int iDoubleSize = sizeof(double); assert(m_iCurrPos+iDoubleSize <= m_iStreamSize); if(m_iCurrPos+iDoubleSize > m_iStreamSize) return; *(double*)(m_pStream+m_iCurrPos) = dValue; m_iCurrPos += iDoubleSize; } double CDataStream::ReadDouble() { int iDoubleSize = sizeof(double); assert(m_iCurrPos+iDoubleSize <= m_iStreamSize); if(m_iCurrPos+iDoubleSize > m_iStreamSize) return 0; double dValue = *(double*)(m_pStream+m_iCurrPos); m_iCurrPos += iDoubleSize; return dValue; } // 读写数据流 void CDataStream::WriteData(unsigned char* pData, int iDataLen) { if(NULL == pData || iDataLen <= 0) return; assert(m_iCurrPos + iDataLen <= m_iStreamSize); // 越界断言 if(m_iCurrPos + iDataLen > m_iStreamSize) return; memcpy(m_pStream+m_iCurrPos, pData, iDataLen); m_iCurrPos += iDataLen; } BYTE* CDataStream::ReadData(int iDataLen) { if(iDataLen <= 0 || m_iCurrPos >= m_iStreamSize) return NULL; assert(m_iCurrPos + iDataLen <= m_iStreamSize); // 越界断言 if(m_iCurrPos + iDataLen > m_iStreamSize) return NULL; BYTE* pData = m_pStream+m_iCurrPos; m_iCurrPos += iDataLen; return pData; } // 读写字符串 void CDataStream::WriteString(const char* pszValue) { if(NULL == pszValue) return ; int iStrLen = strlen(pszValue)+1; // 末尾0 assert(m_iCurrPos+iStrLen <= m_iStreamSize); // 越界断言 if(m_iCurrPos+iStrLen > m_iStreamSize) return; memcpy(m_pStream+m_iCurrPos, pszValue, iStrLen); m_iCurrPos += iStrLen; } const char* CDataStream::ReadString() { if(m_iCurrPos >= m_iStreamSize) return NULL; int iCurrPos = m_iCurrPos; char* psz = (char*)(m_pStream+m_iCurrPos); // 字符串位置 while(iCurrPos < m_iStreamSize) { if(!m_pStream[iCurrPos]) // 字符串最后一个字符为0 { m_iCurrPos = iCurrPos; break; } iCurrPos++; } // 判断是否合法 if(m_iCurrPos < m_iStreamSize) { m_iCurrPos++; // skip 0 return psz; } assert(FALSE); // 越界断言 return NULL; }
测试代码
void TestDataStream() { // 一、测试数据流,写入数据 BYTE szBuff[1024] = {0}; CDataStream ds; ds.Attach(szBuff, 1024); ds.WriteByte(1); ds.WriteWord(2); ds.WriteDWord(1000); ds.WriteInt64(5678); ds.WriteData((BYTE*)"ASDF\0", 5); ds.WriteFloat(1234567890.12f); ds.WriteDouble(1234567890.123); ds.WriteString("Hello word!"); // 读取数据流 ds.Reset(); // 指向流的头 BYTE byValue = ds.ReadByte(); WORD wValue = ds.ReadWord(); DWORD dwValue = ds.ReadDWord(); __int64 i64Value = ds.ReadInt64(); BYTE* pData = ds.ReadData(5); float fValue = ds.ReadFloat(); double dValue = ds.ReadDouble(); const char* psz = ds.ReadString(); printf("CDataStream读写测试:\r\n"); printf("BYTE=%d, WORD=%d, DWORD = %d, INT64 = %I64u, FLOAT = %f, DOUBLE = %f, %s\r\n", byValue, wValue, dwValue, i64Value, fValue, dValue, psz); printf("pData = %s\r\n", (char*)pData); // 二、测试数据流,重载运算符(<<,>>)的测试 // 测试运算符重载 CDataStream dds; dds.Attach(szBuff, 1024); BYTE byRet = 0; WORD wRet = 0; DWORD dwRet = 0; __int64 i64Ret = 0; float fRet = 0; double dRet = 0; char* pszRet; dds << (BYTE)1 << (WORD)2 << (DWORD)3 << (__int64)100 << 30.1f << 128.12 << "Hello word!"; dds.Reset(); dds >> byRet >> wRet >> dwRet >> i64Ret >> fRet >> dRet >> pszRet; printf("CDataStream测试,运算符重载:\r\n"); printf("by1 = %d, WORD = %d, DWORD = %d, INT64 = %I64u, FLOAT = %f, DOUBLE = %f, %s\r\n", byRet, wRet, dwRet, i64Ret, fRet, dRet, pszRet); }
输出结果