最近碰到乙個問題,對於阻塞模式的socket通訊,如果要實現裝置的命令控制,那麼進入命令流前,緩衝區不能存有上次通訊沒有取回的資訊,否則一旦命令發出,然後讀取緩衝區,很顯然會讀到上一次的剩餘資料。做法當然很簡單,就是先清除接收區的緩衝資料,可是如何清除?
網上有很多這樣的問題,但都沒什麼規範的解決辦法,有的甚至為了達到清空的目的,建議先close一下socket,這個太大手筆了,為了解決乙個小問題而大動干戈,根本不是個合理的解決辦法。
還有就是用recv讀取,但是由於不知道快取裡有多少資料,如果是阻塞模式,到最後必然等到超時才知道資料已經讀取完畢,這是個問題。
另乙個是用fgetc,通過返回判斷是否是feof:
whlie (1)
當然,我不知道讀取完畢後最後一次呼叫fgetc會不會堵塞,需要測試。
在非阻塞模式下,我們用recv就可以輕鬆搞定了,但是阻塞模式下,由於我們不知道緩衝區有多少資料,不能直接呼叫recv嘗試清除。
使用乙個小小的技巧,利用select函式,我們可以輕鬆搞定這個問題:
select函式用於監視乙個檔案描述符集合,如果集合中的描述符沒有變化,則一直阻塞在這裡,直到超時時間到達;在超時時間內,一旦某個描述符觸 發了你所關心的事件,select立即返回,通過檢索檔案描述符集合處理相應事件;select函式出錯則返回小於零的值,如果有事件觸發,則返回觸發事 件的描述符個數;如果超時,返回0,即沒有資料可讀。
重點在於:我們可以用select的超時特性,將超時時間設定為0,通過檢測select的返回值,就可以判斷緩衝是否被清空。通過這個技巧,使乙個阻塞的socket成了『非阻塞』socket。
現在就可以得出解決方案了:使用select函式來監視要清空的socket描述符,並把超時時間設定為0,每次讀取乙個位元組然後丟棄(或者按照業務需要進行處理,隨你便了),一旦select返回0,說明緩衝區沒資料了(「超時」了)。
struct timeval tmout;這種方式的好處是,不再需要用recv、recvfrom等阻塞函式直接去讀取,而是使用select,利用其超時特性檢測緩衝區是否為空來判斷是否有資料,有資料時才呼叫recv進行清除。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)
有人說同樣可以用recv和socket的超時設定去清空啊,這個沒錯,但是你需要直接對socket描述符設定超時時間,而為了清空資料而直接修改socket描述符的屬性,可能會影響到其他地方的使用,造成系統奇奇怪怪的問題,所以,不推薦使用。
Linux下如何清空檔案內容
root localhost logs file name.log2 使用 true 命令重定向清空檔案 root localhost logs file name.log 或者 root localhost logs ture file name.log 符號,它是 shell 的乙個內建命令,等...
Linux下如何清空輸入緩衝區
今天在linux下編寫資料結構課程的乙個旅遊管理程式時,遇到了一些有關鍵盤輸入緩衝區的問題。使用scanf函式進行等待使用者輸入時,使用者輸入完會在緩衝區裡遺留乙個換行符 n 如果不清除掉這個換行符,就會在下一次的scanf中被作為輸入,直接跳過,不會等待使用者的輸入,所以,一般在呼叫scanf後一...
Linux下經常使用的C C 開源Socket庫
1.linux socket programming in c 2.ace ace採用ace os適配層遮蔽各種不同的 複雜繁瑣的作業系統api。ace是乙個大型的中介軟體產品,20萬行左右,過於巨集大,一堆的設計模式,架構了一層又一層。它龐大 複雜。適合大型專案。開源 免費。不依賴第三方庫。使用的...