咱們在使用TCP/IP編程的時候除了socket有收發數據緩衝區以外,一般咱們還要本身定一個數據的收發緩衝區。python
假設應用程序須要發送40kB數據,可是操做系統的TCP發送緩衝區只有25kB剩餘空間,那麼剩下的15kB數據怎麼辦?若是等待OS緩衝區可用,會阻塞當前線程,由於不知道對方何時收到並讀取數據。所以網絡庫應該把這15kB數據緩存起來,放到這個TCP鏈接的應用層發送緩衝區中,等socket變得可寫的時候馬上發送數據,這樣「發送」操做不會阻塞。若是應用程序隨後又要發送50kB數據,而此時發送緩衝區中尚有未發送的數據(若干kB),那麼網絡庫應該將這50kB數據追加到發送緩衝區的末尾,而不能馬上嘗試write(),由於這樣有可能打亂數據的順序。c++
另外的話,假如一次讀到的數據不夠一個完整的數據包,那麼這些已經讀到的數據是否是應該先暫存在某個地方,等剩餘的數據收到以後再一併處理。編程
每次接收到數據的時候開闢一個緩衝區,而後將接收到的數據填入緩衝區,把緩衝區和IP信息付給任務,壓入到任務隊列,等任務線程處理; 發送亦然;(小數據能夠用棧拷貝的形式) 好處:是接收線程能夠一直接收,任務線程一直處理,除了任務鎖沒有其餘交互; 缺點: 每次都從新申請空間,malloc(或new)消耗量大(可使用內存池優化);緩存
預先申請一塊大的緩衝區(每一個鏈接各申請一個接收緩衝區和發送緩衝區),接收線程有新數據到來的時候從緩衝區中數據結尾得到可用空間插入數據,把鏈接信息和整個緩衝區壓入任務隊列,任務線程處理一個任務的數據,就清空緩衝區該段的數據,而後將緩衝區中後面的數據前移(因此每次都是處理的第一個數據區的數據) 好處:減小了malloc 缺點:在數據插入和使用的時候都使用的鎖,並且有嚴重的拷貝複製狀況,(若是想任務處理和數據接收不互相鎖,必須使用多的一份兒數據拷貝,狀況就更糟)網絡
使用線程池,每一個線程獨立的讀數據,當數據知足一個包的時候就當作任務處理;而後將連接信息和用戶緩衝區添加到監聽隊列中;有新的數據來到就激活用一個新的線程處理。 好處:僅使用了線程間的鎖,(可使用無鎖隊列優化),減小數據拷貝; 缺點:線程上下文切換開銷大, 數據接收分散;併發
ssize_t readn(int fd, char *buf, int size)
{
char *pbuf = buf;
int total ,nread;
for(total = 0; total < size; )
{
nread=read(fd,pbuf,size-total);
if(nread==0)
return total;
if(nread == -1)
{
if(errno == EINTR)
continue;
else
return -1;
}
total += nread;
pbuf += nread;
}
return total;
}
複製代碼
ssize_t writen(int fd, char *buf, int size)
{
char *pbuf=buf;
int total ,nwrite;
for(total = 0; total < size; )
{
nwrite=write(fd,pbuf,size-total);
if( nwrite <= 0 )
{
if( nwrite == -1 && errno == EINTR )
continue;
else
return -1;
}
total += nwrite;
pbuf += nwrite;
}
return total;
}
複製代碼
更多c++及python系列文章,請關注個人公衆號:晟夏的葉。 socket