標籤:style color 使用 os io strong 檔案 資料
眾所周知,在Linux系統下所有裝置都是以檔案的形式存在,串口也一樣。
通常I/O操作都是有阻塞與非阻塞的兩種方式。
其中"逾時"這個概念其實是阻塞中的一種處理手段,本質還是屬於阻塞的I/O模式.
在Linux中串口的IO操作 本文將它分為三種狀態:
阻塞狀態
逾時狀態
非阻塞狀態
這三種狀態的轉換組合有這麼幾種:
阻塞 --> 逾時
阻塞 --> 非阻塞
逾時 --> 阻塞
逾時 --> 非阻塞
非阻塞 --> 阻塞
我們一個一個來分析
首先在一個串口的描述符開啟的時候指定它的模式是阻塞還是阻塞
fd = open("/dev/tttyS0",O_RDWR | O_NOCTTY);//以阻塞模式開啟串口fd = open("/dev/tttyS0",O_RDWR | O_NOCTTY | O_NDELAY);//以非阻塞模式開啟串口//O_NDELAY 等價於 O_NOBLOCK
當一個串口是阻塞狀態的時候便可以設定它為逾時狀態。
利用 struct termios 的 cc_t c_cc[NCCS] 成員
c_cc[VTIME] 非規範模式讀取時的逾時時間(單位:百毫秒)
c_cc[VMIN] 非規範模式讀取時的最小字元數
如需需要設定逾時則c_cc[VMIN] 必須等於0
??這代表能夠讀取的最小字元是0個,即使用read讀取資料逾時read返回0??
有一個需要注意的地方!
當c_cc[VTIME] 設定為 0 且 c_cc[VMIN] == 0 的時候,代表逾時0秒(姑且這麼叫吧!)
這個時候使用read讀取資料會立即返回(有讀到資料時返回位元組數,沒有資料和一般逾時一樣返回0)
但是!
雖然這時候在現象上看起來和非阻塞模式一樣(read都不會阻塞)但傳回值不同
非阻塞模式: read沒有讀到資料立即返回-1
逾時0秒時: read沒有讀到資料立即返回 0 (設定了逾時的阻塞模式)
ret = read(fd,recvbuf,BUF_SIZE);if(ret == -1)//非阻塞模式時"無資料返回"{ //do something}ret = read(fd,recvbuf,BUF_SIZE);if(ret == 0)//阻塞模式設定逾時0秒時"逾時返回"{ //do something}
雖然表現形式一樣,但在編程時必須要瞭解自己使用的是哪一種模式和串口當前的狀態才能更好的分析和處理問題。
這裡說一下我曾經遇到過的一個問題:
我在開啟串口時使用阻塞模式開啟,但是沒有設定c_cc[VMIN]的值,而它初始化後就是0,所以發現串口沒有被阻塞,其實原因就是串口模式還是阻塞模式沒錯,但是它是逾時0秒的狀態,所以在沒有資料到達時read也返回了。
阻塞狀態和非阻塞狀態的切換
非阻塞狀態時使用
fcntl(fd,F_SETFL,0);
即可轉換成阻塞狀態,同樣可以設定逾時
當非阻塞狀態已經設定了逾時時,在轉換成阻塞狀態後逾時也隨同生效
阻塞狀態時使用
fcntl(fd,F_SETFL,FNDELAY);//FNDELAY等價於FNONBLOCK
即可轉換成非阻塞狀態,逾時失效
這裡提一下 fcntl.h中幾個宏的定義
/* Define some more compatibility macros to be backward compatible with BSD systems which did not managed to hide these kernel macros. */#ifdef__USE_BSD# define FAPPENDO_APPEND# define FFSYNCO_FSYNC# define FASYNCO_ASYNC# define FNONBLOCKO_NONBLOCK# define FNDELAYO_NDELAY#endif /* Use BSD. */
現在一目瞭然了吧?開啟串口時非阻塞模式的O_NDELAY或O_NONBLOCK選項
fcntl設定非阻塞模式的第3個參數FNDELAY或者FNONBLOCK 其實都是O_NONBLOCK主要就是為了相容