解決Linux串列埠查詢一次只能返回8位的問題
問題描述:
專案中有定時查詢感測器並將查詢到的資料記錄下來的需要,在做的時候發現通過whlie迴圈配合select監測串列埠上的資料,然後將資料儲存在陣列的過程中,read函式的第三個引數即選擇讀取的位元組數,在大於8的情況下返回的個數仍然為8,而感測器返回的資料包一般都是十幾位,無法一次性返回,就需要記錄好幾次。更為嚴重的是,如果資料包的位元組數大於16的情況下,第二次返回8個位元組的同時,會將第一次的返回的8個位元組覆蓋掉,從而導致記錄的資料不完整。
解決思路:
串列埠每次查詢只能返回8位受制於緩衝的大小,一般情況下無法改變,那麼應該著手通過對返回的資料包進行處理,不要每次返回都進行記錄,而是在一次資料包返回完整之後,再將它傳遞給用於儲存的陣列進行記錄。
程式修改前如下:
int receive(char *str , unsigned int length) { fd_set fs_read; struct timeval time; FD_ZERO(&fs_read); FD_SET(fd,&fs_read); time.tv_sec=0; time.tv_usec=0; unsigned int i_counter=0; int len=0; while(select(fd+1,&fs_read,NULL,NULL,&time) > 0 ) { if((len=read(fd,str,128))<0) { perror("read"); return -1; } else{ i_counter+= len; } } return i_counter; }
上述程式碼中的str會傳遞到另外一個記錄資料包的函式裡面,本來以為將read的第三個引數設為128就可以完全滿足需要,返回全部的資料長度,但是實際上一次最多隻能返回8位,如果總的位元組數大於16位,還會將前面的資料重新整理掉,而只能夠記錄到最後小於16個位元組的包。
程式修改後如下:
unsigned int i_counter=0; int receive (char *str,unsigned int length) { int len=0; unsigned char str_house[2056]={0}; fd_set fs_read; struct timeval time; FD_ZERO(&fs_read); FD_SET(fd,&fs_read); time.tv_sec=0; time.tv_usec=0; int j_count=0; while(select(fd+1,&fs_read,NULL,NULL,&time)>0){ if((len=read(fd,str_house,8))<0) { perror("read"); return -1; } else{ i_counter+=len; if(i_counter>length) { i_counter=8; } printf("len is %d counter is %d\n",len,i_counter); if(len==8) { for(j_count=0;j_count<8;j_count++) { str[i_counter-8+j_count]=str_house[j_count]; } } else if(len<8) { for(j_count=0;j_count<len;j_count++) { str[i_counter-len+j_count]=str_house[j_count]; } } } } return i_counter; }
上述程式中,i_counter用來記錄當前已經收到的資料包中元素的個數,如果放在函式內部的話,每次呼叫該函式來查詢,該值都會被初始化為零,起不到計數的作用,所以應該作為全域性變數,但是當它計數超過我們本次查詢返回位元組的最大值之後,會被清零,否則會一直無限增長下去,然後就可以建立一個暫時存放資料包的倉庫,即陣列str_house,每次讀八位並記錄,直到它讀到的位元組大於零且小於八,說明它返回的是最後幾個位元組,這幾個位元組存完之後,這一條查詢指令所返回的資料包就全部存放到str_house這個數組裡了,該陣列通過被其他寫函式呼叫,就可以存放到SD卡或者SATA硬碟等儲存裝置,從而解決Linux下串列埠查詢一次只能返回8位的情況。