網路接收快取的設計

2021-09-08 03:06:44 字數 4189 閱讀 4207

網路程式,為了提高程式的效能,應儘量減少記憶體的拷貝次數。

以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...