網絡服務器發送封包設計


接上篇,本文介紹發送封包的設計.

WPacket的構成與RPacket類似,實際數據都存放在buffer組成的鏈表中.發送時,如果一個WPacket的數據跨越了兩個buffer,可通過WSASend提交
多個緩沖,一次性將數據發出去.


WPacket還提供了一個傳入RPacket的構造函數,以方便網關類程序收到一個包就馬上將其轉發的需求.一般情況下,從一個RPacket構造的WPacket都
不需要向其寫入新的數據,而是直接轉發.所以.構造的這個WPacket和傳入的RPacket是共享buffer的.這樣大大減少了內存拷貝的次數.當第一次向這
個WPacket寫入數據時,將會觸發拷貝過程,將RPacket中的數據拷貝到一個生成的buffer之中,至此,WPacket與構造傳入的RPacket將不再共享buffer,
所有的數據將會被寫入到WPacket自己的buffer中.

 

代碼如下:

const static unsigned short sizeOfLen = sizeof(unsigned short);
const static unsigned short cmdlen = sizeof(unsigned short);

#define MAX_PACKET_SIZE 65535

class WPacket
{
friend class Connection;
public:
WPacket(const RPacket &rpk):m_copyOnWrite(true),m_writePos(0),m_head(rpk.m_head)
,m_buf(rpk.m_buf),m_writeBuf(rpk.m_buf),m_len(rpk.m_len)
{

}

WPacket():m_buf(0),m_writeBuf(0),m_head(0),m_writePos(sizeOfLen+cmdlen)
,m_len(sizeOfLen+cmdlen)
{

}

WPacket(const WPacket &wpk):m_buf(wpk.m_buf),m_writeBuf(wpk.m_writeBuf),
m_head(wpk.m_head),m_writePos(wpk.m_writePos),m_len(wpk.m_len),m_copyOnWrite(wpk.m_copyOnWrite)
{

}

WPacket & operator = (const WPacket &other)
{
if(this == &other)
return *this;
m_head = other.m_head;
m_len = other.m_len;
m_buf = other.m_buf;
m_writePos = other.m_writePos;
m_copyOnWrite = other.m_copyOnWrite;
return *this;
}

void WriteShort(unsigned short value)
{
Write<unsigned short>(value);
}

//.......其它Write

void WriteString(const char *str)
{
unsigned short strLen = strlen(str) + 1;
WriteBinary((const void *)str,strLen);
}

void WriteBinary(const void *bin,unsigned short len)
{
CopyOnWrite();
CreateBuffer();
//先寫入長度
WriteShort(len);
unsigned short sizeRemain = m_writeBuf->m_bufSize - m_writePos;
if(sizeRemain >=len)
{
memcpy(&m_writeBuf->m_buf[m_writePos],bin,len);
m_writePos += len;
m_writeBuf->m_dataSize += len;
}
else
{
const char *ptr = (const char *)bin;
unsigned short copySize = sizeRemain;
memcpy(&m_writeBuf->m_buf[m_writePos],ptr,copySize);
ptr += copySize;
m_writeBuf->m_dataSize += copySize;
m_writePos = 0;
copySize = len - copySize;
rptr<buffer> newbuf = new buffer(copySize);
m_writeBuf->m_next = newbuf;
m_writeBuf = newbuf;
memcpy(&m_writeBuf->m_buf[m_writePos],ptr,copySize);
m_writePos += copySize;
m_writeBuf->m_dataSize += copySize;
}
*(unsigned short*)&m_writeBuf->m_buf[m_head] += (len);
m_len = *(unsigned short*)&m_writeBuf->m_buf[m_head];
}

private:

void CreateBuffer()
{
if(m_buf._nil())
{
m_buf = m_writeBuf = new buffer(4096);
}
}


void CopyOnWrite()
{

if(!m_copyOnWrite)
return;

unsigned short totalSize = m_len;
rptr<buffer> tmp = new buffer(totalSize > 0 ? totalSize : 4096);
if(totalSize > 0)
{
//復制數據
unsigned short copySize = totalSize;
rptr<buffer> cur = m_buf;
while(copySize > 0)
{
unsigned short curDataRemian = cur->m_bufSize - m_head;
if(curDataRemian >= copySize)
{
memcpy(&tmp->m_buf[m_writePos],&cur->m_buf[m_head],copySize);
m_writePos += copySize;
m_buf = m_writeBuf = tmp;
m_head = 0;
copySize = 0;
}
else
{
memcpy(&tmp->m_buf[m_writePos],&cur->m_buf[m_head],curDataRemian);
m_writePos += curDataRemian;
copySize -= curDataRemian;
cur = cur->m_next;
m_head = 0;
}
}
}
else
{
m_buf = m_writeBuf = tmp;
m_head = 0;
m_writePos = m_head + sizeOfLen + cmdlen;
m_len = sizeOfLen + cmdlen;
}
m_buf->m_dataSize = m_len;
m_copyOnWrite = false;

}

template <typename T>
void Write(const T &value)
{
CopyOnWrite();
CreateBuffer();
unsigned short sizeRemain = m_writeBuf->m_bufSize - m_writePos;
if(sizeRemain >= sizeof(T))
{
*(T*)&m_writeBuf->m_buf[m_writePos] = value;
m_writePos += sizeof(T);
m_writeBuf->m_dataSize += sizeof(T);
}
else
{

char *ptr = (char*)&value;
unsigned short copySize = sizeRemain;
memcpy(&m_writeBuf->m_buf[m_writePos],ptr,copySize);
ptr += copySize;
m_writeBuf->m_dataSize += copySize;
m_writePos = 0;
copySize = sizeof(T) - copySize;
rptr<buffer> newbuf = new buffer(copySize);
m_writeBuf->m_next = newbuf;
m_writeBuf = newbuf;
memcpy(&m_writeBuf->m_buf[m_writePos],ptr,copySize);
m_writePos += copySize;
m_writeBuf->m_dataSize += copySize;

}
*(T*)&m_writeBuf->m_buf[m_head] += sizeof(T);
m_len = *(unsigned short*)&m_writeBuf->m_buf[m_head];
}

private:
bool m_copyOnWrite;//是否需要寫時拷貝
unsigned short m_len;
unsigned short m_writePos;
unsigned short m_head; //在buf中的起始下標
rptr<buffer> m_writeBuf;//當前writePos所在的buf
rptr<buffer> m_buf;//存放packet的數據,可能由一組m_buf構成鏈表
};

項目的完整代碼在這里:

http://download.csdn.net/detail/sniperhuangwei/4083117

尚未經過完整測試,Packet位移上的處理可能還有bug,后續會修正,整體結構基本不會改變,可能會加上組包和超時處理。

也就是當套接口要發送的數據量太小時暫時不發送,等待后續的寫請求或觸發超時才將數據寫出去。




免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM