清空socket緩存
⑴ 如何清空Socket緩沖區
清空socket緩存區的數據的方法
由於socket是以數據流的形式發送數據,接收方不知道對方一次性發送了多少數據,也能保證對方一次性發送的數據能在同一刻接收到,所以Receive方法是這么工作的:
接受一個byye[]類型的參數作為緩沖區,在經過一定的時間後把接收到的數據填充到這個緩沖區裡面,並且返回實際接收到數據的長度,這個實際接收到的數據長度有可能為0(沒有接收到數據)、大於0小於緩沖區的長度(接收到數據,但是沒有我們預期的多)、等於緩沖區的長度(說明接收到的數據大於等於我們預期的長度)。
每次接收緩沖區都用同一個byte[] byteMessage,並且你沒有檢查接收到的數據長度,所以第一次你接收到的數據是123456,第二次你只接收到了8,但是緩沖區裡面還有23456,所以加起來就是823456了。
socket接收緩沖區的大小有講究,設置大了接收起來慢,因為它要等盡可能多的數據接收到了再返回;設置小了需要重復多次調用接收方法才能把數據接收完,socket有個屬性,標識了系統默認的接收緩沖區大小,可以參考這個!
還有就是用recv讀取,但是由於不知道緩存里有多少數據,如果是阻塞模式,到最後必然等到超時才知道數據已經讀取完畢,這是個問題。
另一個是用fgetc,通過返回判斷是否是feof:
whlie (1) { a=fgetc(f);if (feof(f)) break;//…
b=fgetc(f);if (feof(f)) break;//…}當然,我不知道讀取完畢後最後一次調用fgetc會不會堵塞,需要測試。
在非阻塞模式下,我們用recv就可以輕松搞定了,但是阻塞模式下,由於我們不知道緩沖區有多少數據,不能直接調用recv嘗試清除。
使用一個小小的技巧,利用select函數,我們可以輕松搞定這個問題:
select函數用於監視一個文件描述符集合,如果集合中的描述符沒有變化,則一直阻塞在這里,直到超時時間到達;在超時時間內,一旦某個描述符觸發了你所關心的事件,select立即返回,通過檢索文件描述符集合處理相應事件;select函數出錯則返回小於零的值,如果有事件觸發,則返回觸發事件的描述符個數;如果超時,返回0,即沒有數據可讀。
重點在於:我們可以用select的超時特性,將超時時間設置為0,通過檢測select的返回值,就可以判斷緩沖是否被清空。通過這個技巧,使一個阻塞的socket成了『非阻塞』socket.
現在就可以得出解決方案了:使用select函數來監視要清空的socket描述符,並把超時時間設置為0,每次讀取一個位元組然後丟棄(或者按照業務需要進行處理,隨你便了),一旦select返回0,說明緩沖區沒數據了(「超時」了)。
struct timeval tmOut;tmOut.tv_sec = 0;tmOut.tv_usec = 0;fd_set fds;FD_ZEROS(&fds);FD_SET(skt, &fds);
int nRet;
char tmp[2];
memset(tmp, 0, sizeof(tmp));
while(1)
{ nRet= select(FD_SETSIZE, &fds, NULL, NULL, &tmOut);if(nRet== 0) break;recv(skt, tmp, 1,0);}
這種方式的好處是,不再需要用recv、recvfrom等阻塞函數直接去讀取,而是使用select,利用其超時特性檢測緩沖區是否為空來判斷是否有數據,有數據時才調用recv進行清除。
有人說同樣可以用recv和超時設置去清空啊,這個沒錯,但是你需要直接對socket描述符設置超時時間,而為了清空數據而直接修改socket描述符的屬性,可能會影響到其他地方的使用,造成系統奇奇怪怪的問題,所以,不推薦使用。socket的
⑵ 請教一個socket緩沖區太小對性能影響的問題
會,每一次系統調運都要犧牲系統性能,緩存量太小,會導系統調運次數頻繁,進而影響性能。
可通過內核參數的調整來避免該問題: