網路程式,為了提高程式的效能,應儘量減少記憶體的拷貝次數。
以windows iocp為例,complete執行緒在接收到資料後,應該馬上將接收到的資料拷貝到
解包快取,然後立即發起一次新的wsarecv操作。然後再對解包快取執行操作,解析出邏輯
包。通常的方法是將資料拷貝到乙個環形緩衝中,以減少資料的拷貝次數。但在解出乙個資料
包之後,免不了還要將乙個完整的資料報拷貝到另乙個包快取中,再將這個包提交給應用層處理.
本文介紹一種,拼包方式,以避免從解包快取copy資料到邏輯包中.
首先介紹邏輯包的組織結構:
//rpacket資料可跨越多個buffer
class rpacket
~rpacket()
bool _nil()
rpacket& operator = (const rpacket &other)
return *this;
}char readchar()
short readshort()
long readlong()
float readfloat()
double readdouble()
short readcmd()
const
char* readstring()
unsigned int sizeremain = m_readbuf->m_bufsize - m_readpos;//
當前buf還有多少有效資料
char *str;
if(sizeremain >= strlen)
else
str = &m_binbuffer[m_binbufferpos];
unsigned int copysize = sizeremain;
memcpy(&m_readbuf->m_buf[m_readpos],&m_binbuffer[m_binbufferpos],copysize);
m_readbuf = m_readbuf->m_next;
m_readpos = 0;
m_binbufferpos += copysize;
copysize = strlen - copysize;
memcpy(&m_readbuf->m_buf[m_readpos],&m_binbuffer[m_binbufferpos],copysize);
m_readpos += copysize;
}m_dataremain -= strlen;
arrange();
return str;
}const
void* readbinary(unsigned short &len)
if(m_dataremain < len)
return
0;//
應提示錯誤,可能讀包順序與發包不一致了
void *bin;
unsigned int sizeremain = m_readbuf->m_bufsize - m_readpos;//
當前buf還有多少有效資料
if(sizeremain >= len)
else
bin = &m_binbuffer[m_binbufferpos];
unsigned int copysize = sizeremain;
memcpy(&m_readbuf->m_buf[m_readpos],&m_binbuffer[m_binbufferpos],copysize);
m_readbuf = m_readbuf->m_next;
m_readpos = 0;
m_binbufferpos += copysize;
copysize = len - copysize;
memcpy(&m_readbuf->m_buf[m_readpos],&m_binbuffer[m_binbufferpos],copysize);
m_readpos += copysize;
}m_dataremain -= len;
arrange();
return bin;
}private:
template
t read()
else
m_dataremain -= typesize;
arrange();
return ret;
}rpacket(rptr&buf,unsigned short head)
:m_buf(buf),m_readbuf(buf),m_head(head),m_readpos(head+sizeoflen+cmdlen)
,m_len(0),m_dataremain(0),m_binbuffer(0),m_binbufferpos(0)
}void arrange()
}private:
unsigned short m_readpos;
unsigned short m_head; //
在buf中的起始下標
unsigned short m_len; //
packet的總長度
unsigned short m_dataremain;
////用於處理readstring,和readbin時資料跨越buffer的情況
char * m_binbuffer;
unsigned short m_binbufferpos;
////
rptrm_readbuf;//
當前readpos所在的buf
rptrm_buf;//
存放packet的資料,可能由一組m_buf構成鍊錶
};
如**所示,資料存放在由m_buf組成的list中,m_head表明屬於本rpacket的資料在m_buf中的起始位置.
乙個buf塊的大小為65535位元組。如果包的長度不大,則n個rpacket可以共享同乙個buf,如果rpacket的資料
大於65535,則乙個rpacket的資料則可能會使用超過一塊buf。由同乙個套介面收到的所有rpacket,其實際資料
被乙個buf煉錶鏈接著。
buf由基於引用計數的指標指向,當引用同乙個buf塊的rpacket都被釋放之後,buf也將會被釋放。
下面介紹資料接收和解包處理過程:
bool connection::recv()unsigned short bufcount = 0;
unsigned short recvsize = max_packet_size;
unsigned short freebufsize = m_currecvbuf->m_bufsize - m_writepos;
m_wrecvbuf[bufcount].buf = &m_currecvbuf->m_buf[m_writepos];
m_wrecvbuf[bufcount].len = freebufsize;
recvsize -= freebufsize;
if(recvsize > 0)
}else
m_totaldatasize += dwbytestransfered;
//recv();
}rpacket connection::unpack()
if(m_totaldatasize < packetlen)
return rpacket(rptr(0),0);//
沒有足夠的資料
//ok,資料充足,返回封包
rpacket rpk(m_head,(unsigned short)m_pos);
m_totaldatasize -= packetlen;
//調整m_head和m_pos
m_pos += packetlen;
while(m_pos >= max_packet_size)
else
m_pos -= max_packet_size;
}return rpk;
}
完成例程在onrecvcomplete中,
把接收到的資料拷貝到buf鍊錶中,馬上啟動新的recv操作.
後續的解包過程是unpack函式,其作用就是將buf鍊錶中的資料解包,並將rpacket返回以**用
層處理,從**中可以看出,解包過程是沒有資料拷貝的,只需要正確設定rpacket中的字段就可以了.
網路接收快取的設計
網路程式,為了提高程式的效能,應儘量減少記憶體的拷貝次數。以windows iocp為例,complete執行緒在接收到資料後,應該馬上將接收到的資料拷貝到 解包快取,然後立即發起一次新的wsarecv操作。然後再對解包快取執行操作,解析出邏輯 包。通常的方法是將資料拷貝到乙個環形緩衝中,以減少資料...
快取 網路中的快取。
網路中的快取位於客戶端和服務端之間,或響應客戶端的網路請求,從而對重複的請求返回快取中的資料資源。同時,接受服務端的請求,更新快取中的內容。web 幾乎是伴隨著網際網路誕生的,常用的web 分為正向 反向 和透明 web 是將web 作為快取的一種技術。一般情況下,web 預設說的是正向 如下圖所示...
網路接收流程描述
在2.6.24.4中所有的網絡卡,不管是否支援napi,都是通過struct napi struct結構進行。所有我們先說一下這個結果。struct napi struct 對應支援napi的網絡卡,自己填充這個結構體 而非napi網絡卡,則使用per cpu的softnet data backlo...