1. 程式人生 > >Linux如何清空Socket緩衝區

Linux如何清空Socket緩衝區

最近碰到一個問題,對於阻塞模式的socket通訊,如果要實現裝置的命令控制,那麼進入命令流前,緩衝區不能存有上次通訊沒有取回的資訊,否則一旦命令發出,然後讀取緩衝區,很顯然會讀到上一次的剩餘資料。做法當然很簡單,就是先清除接收區的緩衝資料,可是如何清除?

socket是這麼接收資料的
由於socket是以資料流的形式傳送資料,接收方不知道對方一次性發送了多少資料,不能保證對方一次性發送的資料能在同一刻接收到,所以Receive方法是這麼工作的:
接受一個byte[]型別的引數作為緩衝區,在經過一定的時間後把接收到的資料填充到這個緩衝區裡面,並且返回實際接收到資料的長度,這個實際接收到的資料長度有可能為0(沒有接收到資料)、大於0小於緩衝區的長度(接收到資料,但是沒有我們預期的多)、等於緩衝區的長度(說明接收到的資料大於等於我們預期的長度)。

每次接收緩衝區都用同一個byte[] byteMessage,並且你沒有檢查接收到的資料長度,所以第一次你接收到的資料是123456,第二次你只接收到了8,但是緩衝區裡面還有23456,所以加起來就是823456了。

socket接收緩衝區的大小有講究,設定大了接收起來慢,因為它要等儘可能多的資料接收到了再返回;

設定小了需要重複多次呼叫接收方法才能把資料接收完,socket有個屬性,標識了系統預設的接收緩衝區大小,可以參考這個!

  網上有很多這樣的問題,但都沒什麼規範的解決辦法,有的甚至為了達到清空的目的,建議先close一下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描述符的屬性,可能會影響到其他地方的使用,造成系統奇奇怪怪的問題,所以,不推薦使用。


相關推薦

Linux如何Socket緩衝區

最近碰到一個問題,對於阻塞模式的socket通訊,如果要實現裝置的命令控制,那麼進入命令流前,緩衝區不能存有上次通訊沒有取回的資訊,否則一旦命令發出,然後讀取緩衝區,很顯然會讀到上一次的剩餘資料。做法當然很簡單,就是先清除接收區的緩衝資料,可是如何清除? socket是這

LinuxDNS快取,重新整理DNS的方法(ubuntu,debian)

前言 在Linux系統裡查詢DNS使用如下命令 dig baidu.com @114.114.114.114 或者使用系統預設的DNS伺服器查詢 nslookup baidu.com 下文中的方法不一定全管用,但你總能找到管用的一個 1.network-manag

linux 歷史命令

vi編輯 -c 執行 清空 目錄 tor dell 歷史 ech 系統版本:CentOS 6 history -c 命令可以清空當前窗口的歷史輸出命令。 要徹底刪除歷史命令可以有如下幾種方式: 在當前用戶的~目錄下執行: 方式1: echo > .bash_

linux日誌檔案內容 (轉)

隨著系統執行時間越來越長,日誌檔案的大小也會隨之變得越來越大。如果長期讓這些歷史日誌儲存在系統中,將會佔用大量的磁碟空間。使用者可以直接把這些日誌檔案刪除,但刪除日誌檔案可能會造成一些意想不到的後果。為了能釋放磁碟空間的同時又不影響系統的執行,可以使用echo命令清空日誌檔案

linux catalina.out日誌 不需要重啟tomcat

1.重定向方法清空檔案 [[email protected] logs]# du -h catalina.out  檢視檔案大小 17M catalina.out [[email protected] logs]# > catalina.out

C語言輸入緩衝區

先來看一段程式碼: #include <stdio.h> int main() { int num; char ch ; scanf("%d", &num); scanf("%c", &ch); printf("hello world

linux歷史命令方法

前幾天弄了個Linux伺服器做網站,發現在不同終端登陸時,上下鍵都會出現一堆無用的命令,搜了一下解決方法,做個筆記。 在Linux中,每個使用者目錄下都有一個.bash_history檔案用於儲存歷史命令,當每次登出時,本次登陸所執行的命令將被寫入該檔案。所以可以清空該檔

linux歷史命令(history)

有時候發現上下鍵出現太多沒有用的命令或者打錯的命令,可以使用以下兩種方法清空命令 一、$ history -c 該命令可以清空本次登入的所有輸出命令,但不清空.bash_history檔案,所以下次登陸

C 輸入緩衝區,以及fflush(stdin)的使用誤區和解決方法

對C 語言初學者來說,fflush(stdin)函式被解釋為會清空輸入緩衝區的一個系統函式,這是一個曾經幾乎對過一半的說法,隨著電腦科學的進步,在學習的過程中的逐步完善,將fflush(stdin)函式的過去與現在分析一下。 Personal th

Linux下標準緩衝區

當我們在使用scanf()函式讀取標準輸入時,其結果並不總是正確。有時,為了防止緩衝區資料對結果的影響,我們需要清空標準緩衝區。首先我們得知道在LINUX下標準I/O為我們提供了那幾中型別的緩衝區。

linuxc++ cin無效流的方式

ignore cpp () lang -cp print code ng- cin cin.clear(); cin.ignore(10000,‘\n‘);//這裏面的參數很重要linux下清空c++ cin無效流的方式

linux下文件夾的創建、復制、剪切、重命名、和刪除命令

roo 下載 更多 定位在 多少 多個 壓縮 刪除 由於 在home目錄下有wwwroot目錄,wwwroot下有sinozzz目錄,即/home/wwwroot/sinozzz 一、目錄創建 在/home/wwwroot目錄下新建一個sinozzz123的文件夾 m

stringstream緩衝區

今天在一個for迴圈使用string stream,每次結果只有第一個正確,檢視發現ss.clear()沒有清空緩衝區,不知道什麼原因沒有起作用,後來使用 ss.str(“”) 方法.成功。 另外,如果需要把格式化後的字串通過>>輸出到字串, 必須每次都呼叫clear()方

Linux使用者登入記錄和命令歷史的方法

清除登陸系統成功的記錄,也就是last命令看到的記錄 [[email protected] ~]# echo > /var/log/wtmp 此檔案預設開啟時亂碼的,裡面可以看到ip等等資訊 [[email protected] ~]# echo >/va

[譯]在Linux或刪除大檔案內容的5種方法

原文來源: https://www.tecmint.com/empty-delete-file-content-linux/ 有時,在處理Linux終端中的檔案時,您可能希望清除檔案的內容,而無需使用任何Linux命令列編輯器開啟它。怎麼能實現這一目標?在本文中,我們將藉助一些有用的命令,通過幾種不同的方式

linux下 mysql資料表中的內容sql語句

truncate gk_portal;   delete from  gk_portal;    這兩者都是將gk_portal表中資料清空,不過也是有區別的,如下: truncate是整體刪除(速度

Linux清除使用者登入記錄和命令歷史擦除痕跡

Linux清除使用者登入記錄和命令歷史,清除痕跡必備 清除登陸系統成功的記錄 [[email protected] root]# echo > /var/log/wtmp //此檔案預設開啟時亂碼,可查到ip等資訊 [[email protected] ro

linux 定時日誌

/usr/local/scriptTask目錄下   建立檔案 vi cleanlog.sh > /opt/cbggege/18-8-25/nohup.out 賦予許可權 chmod a+x /usr/local/scriptTask/cleanlog.sh 將指

linux編寫定時日誌檔案的指令碼檔案,並新增定時任務

--------例如在/ usr / spider / logs /下新增一個clearlog.sh指令碼 1.建立clearlog.sh指令碼檔案touch clearlog.sh 2.編寫clearlog.sh指令碼內容:vi clearlog.sh, 3.儲存退出並賦予許可權

linux查詢當前目錄下的所有檔案大小和檔案內容命令

  查詢當前目錄下的所有檔案大小:du -sh *  刪除檔案:rm - rf xxx.log 列印日誌:tail -f xxx.log 檢視程序ps -ef | grep java | grep -v grep 殺死客戶端kill -9 14569 - 啟動