ネットワークサーバ送信パッケージ設計

11716 ワード

前編に続いて、本文はパッケージを送る設計を紹介する.
WPacketの構成はRPacketと同様であり、実際のデータはbufferからなるチェーンテーブルに格納.送信時に、1つのWPacketのデータが2つのbufferを越えた場合、WSASEndで複数のバッファをコミットし、一度にデータを送信することができる.WPacketはまた、RPacketに転送する構造関数を提供し、ゲートウェイクラスプログラムがパケットを受け取るとすぐに転送する需要を容易にする.一般に、1つの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シフトの処理にバグがある可能性があり、その後修正され、全体の構造は基本的に変更されず、パケットとタイムアウト処理が加わる可能性があります.
すなわち,ソケットインタフェースが送信するデータ量が小さすぎると一時的に送信されず,後続の書き込み要求やトリガタイムアウトを待ってからデータが書き込まれる.