日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > linux >内容正文

linux

linux tty pty pts tts概念 区别

發(fā)布時間:2024/1/18 linux 43 豆豆
生活随笔 收集整理的這篇文章主要介紹了 linux tty pty pts tts概念 区别 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

1. tty(終端設(shè)備的統(tǒng)稱):
tty一詞源于Teletypes,或者teletypewriters,原來指的是電傳打字機,是通過串行線用打印機鍵盤通過閱讀和發(fā)送信息的東西,后 來這東西被鍵盤與顯示器取代,所以現(xiàn)在叫終端比較合適。
終端是一種字符型設(shè)備,它有多種類型,通常使用tty來簡稱各種類型的終端設(shè)備。


2. pty(虛擬終端):
但是如果我們遠程telnet到主機或使用xterm時不也需要一個終端交互么?是的,這就是虛擬終端pty(pseudo-tty)


3. pts/ptmx(pts/ptmx結(jié)合使用,進而實現(xiàn)pty):
pts(pseudo-terminal slave)是pty的實現(xiàn)方法,與ptmx(pseudo-terminal master)配合使用實現(xiàn)pty。

Linux終端:

在Linux系統(tǒng)的設(shè)備特殊文件目錄/dev/下,終端特殊設(shè)備文件一般有以下幾種:
1、串行端口終端(/dev/ttySn)
串行端口終端(Serial Port Terminal)是使用計算機串行端口連接的終端設(shè)備。計算機把每個串行端口都看作是一個字符設(shè)備。有段時間這些串行端口設(shè)備通常被稱為終端設(shè)備,因為那時它的最大用途就是用來連接終端。這些串行端口所對應(yīng)的設(shè)備名稱是/dev/tts/0(或/dev/ttyS0), /dev/tts/1(或/dev/ttyS1)等,設(shè)備號分別是(4,0), (4,1)等,分別對應(yīng)于DOS系統(tǒng)下的COM1、COM2等。若要向一個端口發(fā)送數(shù)據(jù),可以在命令行上把標(biāo)準(zhǔn)輸出重定向到這些特殊文件名上即可。例如,在命令行提示符下鍵入:echo test > /dev/ttyS1會把單詞”test”發(fā)送到連接在ttyS1(COM2)端口的設(shè)備上。可接串口來實驗。

2、偽終端(/dev/pty/)
偽終端(Pseudo Terminal)是成對的邏輯終端設(shè)備(即master和slave設(shè)備, 對master的操作會反映到slave上)。
例如/dev/ptyp3和/dev/ttyp3(或者在設(shè)備文件系統(tǒng)中分別是/dev/pty/m3和 /dev/pty/s3)。它們與實際物理設(shè)備并不直接相關(guān)。如果一個程序把ptyp3(master設(shè)備)看作是一個串行端口設(shè)備,則它對該端口的讀/ 寫操作會反映在該邏輯終端設(shè)備對應(yīng)的另一個ttyp3(slave設(shè)備)上面。而ttyp3則是另一個程序用于讀寫操作的邏輯設(shè)備。

這樣,兩個程序就可以通過這種邏輯設(shè)備進行互相交流,而其中一個使用ttyp3的程序則認(rèn)為自己正在與一個串行端口進行通信。這很象是邏輯設(shè)備對之間的管道操作。對于ttyp3(s3),任何設(shè)計成使用一個串行端口設(shè)備的程序都可以使用該邏輯設(shè)備。但對于使用ptyp3的程序,則需要專門設(shè)計來使用 ptyp3(m3)邏輯設(shè)備。

例如,如果某人在網(wǎng)上使用telnet程序連接到你的計算機上,則telnet程序就可能會開始連接到設(shè)備 ptyp2(m2)上(一個偽終端端口上)。此時一個getty程序就應(yīng)該運行在對應(yīng)的ttyp2(s2)端口上。當(dāng)telnet從遠端獲取了一個字符時,該字符就會通過m2、s2傳遞給 getty程序,而getty程序就會通過s2、m2和telnet程序往網(wǎng)絡(luò)上返回”login:”字符串信息。這樣,登錄程序與telnet程序就通過“偽終端”進行通信。通過使用適當(dāng)?shù)能浖?#xff0c;就可以把兩個甚至多個偽終端設(shè)備連接到同一個物理串行端口上。

在使用設(shè)備文件系統(tǒng) (device filesystem)之前,為了得到大量的偽終端設(shè)備特殊文件,使用了比較復(fù)雜的文件名命名方式。因為只存在16個ttyp(ttyp0—ttypf) 的設(shè)備文件,為了得到更多的邏輯設(shè)備對,就使用了象q、r、s等字符來代替p。例如,ttys8和ptys8就是一個偽終端設(shè)備對。不過這種命名方式目前仍然在RedHat等Linux系統(tǒng)中使用著。

但Linux系統(tǒng)上的Unix98并不使用上述方法,而使用了”pty master”方式,例如/dev/ptm3。它的對應(yīng)端則會被自動地創(chuàng)建成/dev/pts/3。這樣就可以在需要時提供一個pty偽終端。目錄 /dev/pts是一個類型為devpts的文件系統(tǒng),并且可以在被加載文件系統(tǒng)列表中看到。雖然“文件”/dev/pts/3看上去是設(shè)備文件系統(tǒng)中的一項,但其實它完全是一種不同的文件系統(tǒng)。
即: TELNET ---> TTYP3(S3: slave) ---> PTYP3(M3: master) ---> GETTY
=========================================================================
實驗:
1、在X下打開一個或N個終端窗口
2、#ls /dev/pt*
3、關(guān)閉這個X下的終端窗口,再次運行;比較兩次輸出信息就明白了。
在RHEL4環(huán)境下: 輸出為/dev/ptmx /dev/pts/1存在一(master)對多(slave)的情況
=========================================================================


3、控制終端(/dev/tty)
如 果當(dāng)前進程有控制終端(Controlling Terminal)的話,那么/dev/tty就是當(dāng)前進程的控制終端的設(shè)備特殊文件。可以使用命令”ps –ax”來查看進程與哪個控制終端相連。對于你登錄的shell,/dev/tty就是你使用的終端,設(shè)備號是(5,0)。使用命令”tty”可以查看它具體對應(yīng)哪個實際終端設(shè)備。/dev/tty有些類似于到實際所使用終端設(shè)備的一個聯(lián)接。


4、控制臺終端(/dev/ttyn, /dev/console)
在Linux 系統(tǒng)中,計算機顯示器通常被稱為控制臺終端 (Console)。它仿真了類型為Linux的一種終端(TERM=Linux),并且有一些設(shè)備特殊文件與之相關(guān)聯(lián):tty0、tty1、tty2 等。當(dāng)你在控制臺上登錄時,使用的是tty1。使用Alt+[F1—F6]組合鍵時,我們就可以切換到tty2、tty3等上面去。tty1–tty6等稱為虛擬終端,而tty0則是當(dāng)前所使用虛擬終端的一個別名,系統(tǒng)所產(chǎn)生的信息會發(fā)送到該終端上。因此不管當(dāng)前正在使用哪個虛擬終端,系統(tǒng)信息都會發(fā)送到控制臺終端上。你可以登錄到不同的虛擬終端上去,因而可以讓系統(tǒng)同時有幾個不同的會話期存在。只有系統(tǒng)或超級用戶root可以向 /dev/tty0進行寫操作 即下例:
1、# tty(查看當(dāng)前TTY)
/dev/tty1
2、#echo "test tty0" > /dev/tty0
test tty0


5 虛擬終端(/dev/pts/n)
在Xwindows模式下的偽終端.


6 其它類型
Linux系統(tǒng)中還針對很多不同的字符設(shè)備存在有很多其它種類的終端設(shè)備特殊文件。例如針對ISDN設(shè)備的/dev/ttyIn終端設(shè)備等。這里不再贅述。


FAQ: 終端和控制臺

RROM:http://blog.footoo.org/?p=73
Posted on Tuesday, November 28th, 2006 by CLIFF

吳晉 (cliffwoo@gmail.com)
FoOTOo OpenSource Lab

由于在很多朋友對終端的概念一直不是很清楚,因此寫了這個FAQ,希望能夠幫助大家理解這些概念。不妥之處,還請大家來信指出。

Q:/dev/console 是什么?

A:/dev/console即控制臺,是與操作系統(tǒng)交互的設(shè)備,系統(tǒng)將一些信息直接輸出到控制臺上。目前只有在單用戶模式下,才允許用戶登錄控制臺。


Q:/dev/tty是什么?

A:tty設(shè)備包括虛擬控制臺,串口以及偽終端設(shè)備。
/dev/tty代表當(dāng)前tty設(shè)備,在當(dāng)前的終端中輸入 echo “hello” > /dev/tty ,都會直接顯示在當(dāng)前的終端中。


Q:/dev/ttyS*是什么?

A:/dev/ttyS*是串行終端設(shè)備。


Q:/dev/pty*是什么?

A:/dev/pty*即偽終端,所謂偽終端是邏輯上的終端設(shè)備,多用于模擬終端程序。例如,我們在X Window下打開的終端,以及我們在Windows使用telnet 或ssh等方式登錄Linux主機,此時均在使用pty設(shè)備(準(zhǔn)確的說應(yīng)該pty從設(shè)備)。

Q:/dev/tty0與/dev/tty1 …/dev/tty63是什么?它們之間有什么區(qū)別?

A:/dev/tty0代表當(dāng)前虛擬控制臺,而/dev/tty1等代表第一個虛擬控制臺,例如當(dāng)使用ALT+F2進行切換時,系統(tǒng)的虛擬控制臺為 /dev/tty2 ,當(dāng)前的控制臺則指向/dev/tty2

Q:如何確定當(dāng)前所在的終端(或控制臺)?

A:使用tty命令可以確定當(dāng)前的終端或者控制臺。

Q:/dev/console是到/dev/tty0的符號鏈接嗎?

A: 目前的大多數(shù)文本中都稱/dev/console是到/dev/tty0的鏈接(包括《Linux內(nèi)核源代碼情景分析》),但是這樣說是不確切的。根據(jù)內(nèi)核文檔,在2.1.71之前,/dev/console根據(jù)不同系統(tǒng)的設(shè)定可以鏈接到/dev/tty0或者其他tty*上,在2.1.71版本之后則完全由內(nèi)核控制。目前,只有在單用戶模式下可以登錄/dev/console(可以在單用戶模式下輸入tty命令進行確認(rèn))。

Q:/dev/tty0與/dev/fb*有什么區(qū)別?

A: 在Framebuffer設(shè)備沒有啟用的系統(tǒng)中,可以使用/dev/tty0訪問顯卡。

Q:關(guān)于終端和控制臺的區(qū)別可以參考哪些文本

A: 可以參考內(nèi)核文檔中的 Documents/devices.txt 中關(guān)于”TERMINAL DEVICES” 的章節(jié)。另外,《Linux內(nèi)核源代碼情景分析》的8.7節(jié) 以及《Operating Systems : Design and Implementation》中的3.9節(jié)(第3版中為3.8節(jié))都對終端設(shè)備的概念和歷史做了很好的介紹。另外在《Modern Operating system》中也有對終端設(shè)備的介紹,由于與《Operating Systems : Design and Implementation》的作者相同,所以文本內(nèi)容也大致相同。需要注意的一點是《Operating Systems : Design and Implementation》中將終端設(shè)備分為3類,而《Modern Operating system》將終端硬件設(shè)備分為2類,差別在于前者將 X Terminal作為一個類別。

tts 與tty:
? ? com1或com2。。。在linux kernel下是dev/ttySn(n= 0,1,2分別為com對應(yīng)的口),在linux kernel with devfs 中是dev/tts/n(n = 0, 1, 2分別為對應(yīng)的com口)。 ??

串口:

串行口是計算機一種常用的接口,具有連接線少,通訊簡單,得到廣泛的使用。常用的串口是RS-232-C接口(又稱EIA RS-232-C)它是在1970年由美國電子工業(yè)協(xié)會(EIA)聯(lián)合貝爾系統(tǒng)、調(diào)制解調(diào)器廠家及計算機終端生產(chǎn)廠家共同制定的用于串行通訊的標(biāo)準(zhǔn)。串口通訊指的是計算機依次以位(bit)為單位來傳送數(shù)據(jù),串行通訊使用的范圍很廣,在嵌入式系統(tǒng)開發(fā)過程中串口通訊也經(jīng)常用到通訊方式之一。

Linux對所有設(shè)備的訪問是通過設(shè)備文件來進行的,串口也是這樣,為了訪問串口,只需打開其設(shè)備文件即可操作串口設(shè)備。在linux系統(tǒng)下面,每一個串口設(shè)備都有設(shè)備文件與其關(guān)聯(lián),設(shè)備文件位于系統(tǒng)的/dev目錄下面。如linux下的/ttyS0,/ttyS1分別表示的是串口1和串口2。下面來詳細介紹linux下是如何使用串口的:

??

1.??????串口操作需要用到的頭文件

#include?????<stdio.h>??????/*標(biāo)準(zhǔn)輸入輸出定義*/

#include?????<stdlib.h>?????/*標(biāo)準(zhǔn)函數(shù)庫定義*/

#include?????<unistd.h>?????/*Unix?標(biāo)準(zhǔn)函數(shù)定義*/

#include?????<sys/types.h>?

#include?????<sys/stat.h>??

#include?????<fcntl.h>??????/*文件控制定義*/

#include?????<termios.h>????/*POSIX?終端控制定義*/

#include?????<errno.h>??????/*錯誤號定義*/

#include???<string.h>???????/*字符串功能函數(shù)*/

2.??????串口通訊波特率設(shè)置

波特率的設(shè)置定義在<asm/termbits.h>,其包含在頭文件<termios.h>里。

常用的波特率常數(shù)如下:

B0-------à0??????????????????? ?B1800-------à1800

B50-----à50????????????????????B2400------à2400

B75-----à75????????????????????B4800------à4800

B110----à110?????????????????B9600------à9600

B134----à134.5??????????????B19200-----à19200

B200----à200?????????????????B38400------à38400

B300----à300?????????????????B57600------à57600

B600----à600?????????????????B76800------à76800

B1200---à1200??????????????B115200-----à115200

假定程序中想要設(shè)置通訊的波特率,使用cfsetispeed( )和cfsetospeed( )函數(shù)來操作,獲取波特率信息是通過cfgetispeed()和cfgetospeed()函數(shù)來完成的。比如可以這樣來指定串口通訊的波特率:

#include <stdio.h>????//頭文件定義

........

........

.......

struct termios opt;???????????/*定義指向termios?結(jié)構(gòu)類型的指針opt*/

?

/***************以下設(shè)置通訊波特率****************/

cfsetispeed(&opt,B9600 );?/*指定輸入波特率,9600bps*/

cfsetospeed(&opt,B9600);/*指定輸出波特率,9600bps*/

/************************************************/

.........

..........

一般來說,輸入、輸出的波特率應(yīng)該是一致的。

3.??????串口屬性配置

在程序中,很容易配置串口的屬性,這些屬性定義在結(jié)構(gòu)體struct termios中。為在程序中使用該結(jié)構(gòu)體,需要包含文件<termbits.h>,該頭文件定義了結(jié)構(gòu)體struct termios。該結(jié)構(gòu)體定義如下:

#define NCCS 19

struct termios {

?????????????tcflag_t c_iflag;???????????????/*?輸入?yún)?shù)?*/

?????????????tcflag_t c_oflag;???????????????/*?輸出參數(shù)?*/

?????????????tcflag_t c_cflag;???????????????/*?控制參數(shù)*/

?????????????tcflag_t c_ispeed;??????????????/*?輸入波特率?*/

tcflag_t c_ospeed;??????????????/*?輸出波特率?*/

?????????????cc_t c_line;???????????????????/*?線控制?*/

?????????????cc_t c_cc[NCCS];??????????????/*?控制字符*/

};

其中成員c_line在POSIX(Portable Operating System Interface for UNIX)系統(tǒng)中不使用。對于支持POSIX終端接口的系統(tǒng)中,對于端口屬性的設(shè)置和獲取要用到兩個重要的函數(shù)是:

(1).int tcsetattr(int fd,int opt_DE,*ptr)

該函數(shù)用來設(shè)置終端控制屬性,其參數(shù)說明如下:

l????????fd:待操作的文件描述符

l????????opt_DE:選項值,有三個選項以供選擇:

TCSANOW:??不等數(shù)據(jù)傳輸完畢就立即改變屬性

TCSADRAIN:等待所有數(shù)據(jù)傳輸結(jié)束才改變屬性

TCSAFLUSH:清空輸入輸出緩沖區(qū)才改變屬性

l????????*ptr:指向termios結(jié)構(gòu)的指針

函數(shù)返回值:成功返回0,失敗返回-1。

(2).int tcgetattr(int fd,*ptr)

該函數(shù)用來獲取終端控制屬性,它把串口的默認(rèn)設(shè)置賦給了termios數(shù)據(jù)數(shù)據(jù)結(jié)構(gòu),其參數(shù)說明如下:

l?????fd:待操作的文件描述符

l????????*ptr:指向termios結(jié)構(gòu)的指針

函數(shù)返回值:成功返回0,失敗返回-1。

4.??????打開串口

在前面已經(jīng)提到linux下的串口訪問是以設(shè)備文件形式進行的,所以打開串口也即是打開文件的操作。函數(shù)原型可以如下所示:

int open(“DE_name”,int open_Status)

參數(shù)說明:

(1).DE_name:要打開的設(shè)備文件名

比如要打開串口1,即為/dev/ttyS0。

(2).open_Status:文件打開方式,可采用下面的文件打開模式:

l??????????O_RDONLY:以只讀方式打開文件

l??????????O_WRONLY:以只寫方式打開文件

l??????????O_RDWR:以讀寫方式打開文件

l??????????O_APPEND:寫入數(shù)據(jù)時添加到文件末尾

l??????????O_CREATE:如果文件不存在則產(chǎn)生該文件,使用該標(biāo)志需要設(shè)置訪問權(quán)限位mode_t

l??????????O_EXCL:指定該標(biāo)志,并且指定了O_CREATE標(biāo)志,如果打開的文件存在則會產(chǎn)生一個錯誤

l??????????O_TRUNC:如果文件存在并且成功以寫或者只寫方式打開,則清除文件所有內(nèi)容,使得文件長度變?yōu)?

l??????????O_NOCTTY:如果打開的是一個終端設(shè)備,這個程序不會成為對應(yīng)這個端口的控制終端,如果沒有該標(biāo)志,任何一個輸入,例如鍵盤中止信號等,都將影響進程。

l??????????O_NONBLOCK:該標(biāo)志與早期使用的O_NDELAY標(biāo)志作用差不多。程序不關(guān)心DCD信號線的狀態(tài),如果指定該標(biāo)志,進程將一直在休眠狀態(tài),直到DCD信號線為0。

函數(shù)返回值:

成功返回文件描述符,如果失敗返回-1

例如假定以可讀寫方式打開/dev/ttyS0設(shè)備,就可以這樣操作:

#include<stdio.h>????//頭文件包含

......

......

int fd; /*?文件描述符?*/

fd = open("/dev/ttyS0", O_RDWR | 0_NOCTTY);??/*以讀寫方式打開設(shè)備*/

if(fd == -1)

perror("Can not open Serial_Port 1/n")/*打開失敗時的錯誤提示*/

........

........

?

5.??????串口讀操作(接收端)

用open函數(shù)打開設(shè)備文件,函數(shù)返回一個文件描述符(file descriptors,fd),通過文件描述符來訪問文件。讀串口操作是通過read函數(shù)來完成的。函數(shù)原型如下:

int read(int fd, *buffer,length);

參數(shù)說明:

(1).int fd:文件描述符

(2).*buffer:數(shù)據(jù)緩沖區(qū)

(3).length:要讀取的字節(jié)數(shù)

函數(shù)返回值:

讀操作成功讀取返回讀取的字節(jié)數(shù),失敗則返回-1。

6.??????串口寫操作(發(fā)送端)

寫串口操作是通過write函數(shù)來完成的。函數(shù)原型如下:

write(int fd, *buffer,length);

參數(shù)說明:

(1).fd:文件描述符

(2).*buffer:存儲寫入數(shù)據(jù)的數(shù)據(jù)緩沖區(qū)

(3).length:寫入緩沖去的數(shù)據(jù)字節(jié)數(shù)

函數(shù)返回值:

成功返回寫入數(shù)據(jù)的字節(jié)數(shù),該值通常等于length,如果寫入失敗返回-1。

例如:向終端設(shè)備發(fā)送初始化命令

#include<stdio.h>????//頭文件包含

......

......

?

int n

sbuf[]={Hello,this is a Serial_Port test!/n };//待發(fā)送數(shù)據(jù)

int len_send="sizeof"(sbuf);//發(fā)送緩沖區(qū)字節(jié)數(shù)定義

n = write(fd,sbuf,len_send); //寫緩沖區(qū)

if(n == -1)

{

printf("Wirte sbuf error./n");

}

......

......

7.??????關(guān)閉串口

對設(shè)備文件的操作與對普通文件的操作一樣,打開操作之后還需要關(guān)閉,關(guān)閉串口用函數(shù)close( )來操作,函數(shù)原型為:

int close(int fd);

參數(shù)說明:

fd:文件描述符

函數(shù)返回值:

成功返回0,失敗返回-1。


NAME

termios, tcgetattr, tcsetattr, tcsendbreak, tcdrain, tcflush, tcflow, cfmakeraw, cfgetospeed, cfgetispeed, cfsetispeed, cfsetospeed - 獲取和設(shè)置終端屬性,行控制,獲取和設(shè)置波特率??

SYNOPSIS 總覽

#include <termios.h>?
#include <unistd.h>

int tcgetattr(int?fd, struct termios *termios_p);

int tcsetattr(int?fd, int?optional_actions, struct termios *termios_p);

int tcsendbreak(int?fd, int?duration);

int tcdrain(int?fd);

int tcflush(int?fd, int?queue_selector);

int tcflow(int?fd, int?action);

int cfmakeraw(struct termios *termios_p);

speed_t cfgetispeed(struct termios *termios_p);

speed_t cfgetospeed(struct termios *termios_p);

int cfsetispeed(struct termios *termios_p, speed_t?speed);

int cfsetospeed(struct termios *termios_p, speed_t?speed);??

DESCRIPTION 描述

termios 函數(shù)族提供了一個常規(guī)的終端接口,用于控制非同步通信端口。

這里描述的大部分屬性有一個?termios_p?類型的參數(shù),它是指向一個?termios?結(jié)構(gòu)的指針。這個結(jié)構(gòu)包含了至少下列成員:

?


tcflag_t c_iflag; /* 輸入模式 */ tcflag_t c_oflag; /* 輸出模式 */ tcflag_t c_cflag; /* 控制模式 */ tcflag_t c_lflag; /* 本地模式 */ cc_t c_cc[NCCS]; /* 控制字符 */

c_iflag?標(biāo)志常量:

IGNBRK
忽略輸入中的 BREAK 狀態(tài)。
BRKINT
如果設(shè)置了? IGNBRK,將忽略 BREAK。如果沒有設(shè)置,但是設(shè)置了? BRKINT,那么 BREAK 將使得輸入和輸出隊列被刷新,如果終端是一個前臺進程組的控制終端,這個進程組中所有進程將收到? SIGINT?信號。如果既未設(shè)置? IGNBRK?也未設(shè)置? BRKINT,BREAK 將視為與 NUL 字符同義,除非設(shè)置了? PARMRK,這種情況下它被視為序列 /377 /0 /0。
IGNPAR
忽略楨錯誤和奇偶校驗錯。
PARMRK
如果沒有設(shè)置? IGNPAR,在有奇偶校驗錯或楨錯誤的字符前插入 /377 /0。如果既沒有設(shè)置? IGNPAR?也沒有設(shè)置? PARMRK,將有奇偶校驗錯或楨錯誤的字符視為 /0。
INPCK
啟用輸入奇偶檢測。
ISTRIP
去掉第八位。
INLCR
將輸入中的 NL 翻譯為 CR。
IGNCR
忽略輸入中的回車。
ICRNL
將輸入中的回車翻譯為新行 (除非設(shè)置了? IGNCR)。
IUCLC
(不屬于 POSIX) 將輸入中的大寫字母映射為小寫字母。
IXON
啟用輸出的 XON/XOFF 流控制。
IXANY
(不屬于 POSIX.1;XSI) 允許任何字符來重新開始輸出。(?)
IXOFF
啟用輸入的 XON/XOFF 流控制。
IMAXBEL
(不屬于 POSIX) 當(dāng)輸入隊列滿時響零。Linux 沒有實現(xiàn)這一位,總是將它視為已設(shè)置。

POSIX.1 中定義的?c_oflag?標(biāo)志常量:

OPOST
啟用具體實現(xiàn)自行定義的輸出處理。

其余?c_oflag?標(biāo)志常量定義在 POSIX 1003.1-2001 中,除非另外說明。

OLCUC
(不屬于 POSIX) 將輸出中的小寫字母映射為大寫字母。
ONLCR
(XSI) 將輸出中的新行符映射為回車-換行。
OCRNL
將輸出中的回車映射為新行符
ONOCR
不在第 0 列輸出回車。
ONLRET
不輸出回車。
OFILL
發(fā)送填充字符作為延時,而不是使用定時來延時。
OFDEL
(不屬于 POSIX) 填充字符是 ASCII DEL (0177)。如果不設(shè)置,填充字符則是 ASCII NUL。
NLDLY
新行延時掩碼。取值為? NL0?和? NL1
CRDLY
回車延時掩碼。取值為? CR0,? CR1,? CR2, 或? CR3
TABDLY
水平跳格延時掩碼。取值為? TAB0,? TAB1,? TAB2,? TAB3?(或? XTABS)。取值為 TAB3,即 XTABS,將擴展跳格為空格 (每個跳格符填充 8 個空格)。(?)
BSDLY
回退延時掩碼。取值為? BS0?或? BS1。(從來沒有被實現(xiàn)過)
VTDLY
豎直跳格延時掩碼。取值為? VT0?或? VT1
FFDLY
進表延時掩碼。取值為? FF0?或? FF1

c_cflag?標(biāo)志常量:

CBAUD
(不屬于 POSIX) 波特率掩碼 (4+1 位)。
CBAUDEX
(不屬于 POSIX) 擴展的波特率掩碼 (1 位),包含在 CBAUD 中。

(POSIX 規(guī)定波特率存儲在 termios 結(jié)構(gòu)中,并未精確指定它的位置,而是提供了函數(shù)?cfgetispeed()?和cfsetispeed()?來存取它。一些系統(tǒng)使用?c_cflag?中 CBAUD 選擇的位,其他系統(tǒng)使用單獨的變量,例如sg_ispeed?和?sg_ospeed?。)

CSIZE
字符長度掩碼。取值為? CS5,? CS6,? CS7, 或? CS8
CSTOPB
設(shè)置兩個停止位,而不是一個。
CREAD
打開接受者。
PARENB
允許輸出產(chǎn)生奇偶信息以及輸入的奇偶校驗。
PARODD
輸入和輸出是奇校驗。
HUPCL
在最后一個進程關(guān)閉設(shè)備后,降低 modem 控制線 (掛斷)。(?)
CLOCAL
忽略 modem 控制線。
LOBLK
(不屬于 POSIX) 從非當(dāng)前 shell 層阻塞輸出(用于? shl?)。(?)
CIBAUD
(不屬于 POSIX) 輸入速度的掩碼。CIBAUD 各位的值與 CBAUD 各位相同,左移了 IBSHIFT 位。
CRTSCTS
(不屬于 POSIX) 啟用 RTS/CTS (硬件) 流控制。

c_lflag?標(biāo)志常量:

ISIG
當(dāng)接受到字符 INTR, QUIT, SUSP, 或 DSUSP 時,產(chǎn)生相應(yīng)的信號。
ICANON
啟用標(biāo)準(zhǔn)模式 (canonical mode)。允許使用特殊字符 EOF, EOL, EOL2, ERASE, KILL, LNEXT, REPRINT, STATUS, 和 WERASE,以及按行的緩沖。
XCASE
(不屬于 POSIX; Linux 下不被支持) 如果同時設(shè)置了? ICANON,終端只有大寫。輸入被轉(zhuǎn)換為小寫,除了以 / 前綴的字符。輸出時,大寫字符被前綴 /,小寫字符被轉(zhuǎn)換成大寫。
ECHO
回顯輸入字符。
ECHOE
如果同時設(shè)置了? ICANON,字符 ERASE 擦除前一個輸入字符,WERASE 擦除前一個詞。
ECHOK
如果同時設(shè)置了? ICANON,字符 KILL 刪除當(dāng)前行。
ECHONL
如果同時設(shè)置了? ICANON,回顯字符 NL,即使沒有設(shè)置 ECHO。
ECHOCTL
(不屬于 POSIX) 如果同時設(shè)置了? ECHO,除了 TAB, NL, START, 和 STOP 之外的 ASCII 控制信號被回顯為 ^X, 這里 X 是比控制信號大 0x40 的 ASCII 碼。例如,字符 0x08 (BS) 被回顯為 ^H。
ECHOPRT
(不屬于 POSIX) 如果同時設(shè)置了? ICANON?和? IECHO,字符在刪除的同時被打印。
ECHOKE
(不屬于 POSIX) 如果同時設(shè)置了? ICANON,回顯 KILL 時將刪除一行中的每個字符,如同指定了? ECHOE和? ECHOPRT?一樣。
DEFECHO
(不屬于 POSIX) 只在一個進程讀的時候回顯。
FLUSHO
(不屬于 POSIX; Linux 下不被支持) 輸出被刷新。這個標(biāo)志可以通過鍵入字符 DISCARD 來開關(guān)。
NOFLSH
禁止在產(chǎn)生 SIGINT, SIGQUIT 和 SIGSUSP 信號時刷新輸入和輸出隊列。
TOSTOP
向試圖寫控制終端的后臺進程組發(fā)送 SIGTTOU 信號。
PENDIN
(不屬于 POSIX; Linux 下不被支持) 在讀入下一個字符時,輸入隊列中所有字符被重新輸出。( bash?用它來處理 typeahead)
IEXTEN
啟用實現(xiàn)自定義的輸入處理。這個標(biāo)志必須與? ICANON?同時使用,才能解釋特殊字符 EOL2,LNEXT,REPRINT 和 WERASE, IUCLC?標(biāo)志才有效。

c_cc?數(shù)組定義了特殊的控制字符。符號下標(biāo) (初始值) 和意義為:

VINTR
(003, ETX, Ctrl-C, or also 0177, DEL, rubout) 中斷字符。發(fā)出 SIGINT 信號。當(dāng)設(shè)置 ISIG 時可被識別,不再作為輸入傳遞。
VQUIT
(034, FS, Ctrl-/) 退出字符。發(fā)出 SIGQUIT 信號。當(dāng)設(shè)置 ISIG 時可被識別,不再作為輸入傳遞。
VERASE
(0177, DEL, rubout, or 010, BS, Ctrl-H, or also #) 刪除字符。刪除上一個還沒有刪掉的字符,但不刪除上一個 EOF 或行首。當(dāng)設(shè)置 ICANON 時可被識別,不再作為輸入傳遞。
VKILL
(025, NAK, Ctrl-U, or Ctrl-X, or also @) 終止字符。刪除自上一個 EOF 或行首以來的輸入。當(dāng)設(shè)置 ICANON 時可被識別,不再作為輸入傳遞。
VEOF
(004, EOT, Ctrl-D) 文件尾字符。更精確地說,這個字符使得 tty 緩沖中的內(nèi)容被送到等待輸入的用戶程序中,而不必等到 EOL。如果它是一行的第一個字符,那么用戶程序的? read()?將返回 0,指示讀到了 EOF。當(dāng)設(shè)置 ICANON 時可被識別,不再作為輸入傳遞。
VMIN
非 canonical 模式讀的最小字符數(shù)。
VEOL
(0, NUL) 附加的行尾字符。當(dāng)設(shè)置 ICANON 時可被識別。
VTIME
非 canonical 模式讀時的延時,以十分之一秒為單位。
VEOL2
(not in POSIX; 0, NUL) 另一個行尾字符。當(dāng)設(shè)置 ICANON 時可被識別。
VSWTCH
(not in POSIX; not supported under Linux; 0, NUL) 開關(guān)字符。(只為? shl?所用。)
VSTART
(021, DC1, Ctrl-Q) 開始字符。重新開始被 Stop 字符中止的輸出。當(dāng)設(shè)置 IXON 時可被識別,不再作為輸入傳遞。
VSTOP
(023, DC3, Ctrl-S) 停止字符。停止輸出,直到鍵入 Start 字符。當(dāng)設(shè)置 IXON 時可被識別,不再作為輸入傳遞。
VSUSP
(032, SUB, Ctrl-Z) 掛起字符。發(fā)送 SIGTSTP 信號。當(dāng)設(shè)置 ISIG 時可被識別,不再作為輸入傳遞。
VDSUSP
(not in POSIX; not supported under Linux; 031, EM, Ctrl-Y) 延時掛起信號。當(dāng)用戶程序讀到這個字符時,發(fā)送 SIGTSTP 信號。當(dāng)設(shè)置 IEXTEN 和 ISIG,并且系統(tǒng)支持作業(yè)管理時可被識別,不再作為輸入傳遞。
VLNEXT
(not in POSIX; 026, SYN, Ctrl-V) 字面上的下一個。引用下一個輸入字符,取消它的任何特殊含義。當(dāng)設(shè)置 IEXTEN 時可被識別,不再作為輸入傳遞。
VWERASE
(not in POSIX; 027, ETB, Ctrl-W) 刪除詞。當(dāng)設(shè)置 ICANON 和 IEXTEN 時可被識別,不再作為輸入傳遞。
VREPRINT
(not in POSIX; 022, DC2, Ctrl-R) 重新輸出未讀的字符。當(dāng)設(shè)置 ICANON 和 IEXTEN 時可被識別,不再作為輸入傳遞。
VDISCARD
(not in POSIX; not supported under Linux; 017, SI, Ctrl-O) 開關(guān):開始/結(jié)束丟棄未完成的輸出。當(dāng)設(shè)置 IEXTEN 時可被識別,不再作為輸入傳遞。
VSTATUS
(not in POSIX; not supported under Linux; status request: 024, DC4, Ctrl-T).

這些符號下標(biāo)值是互不相同的,除了 VTIME,VMIN 的值可能分別與 VEOL,VEOF 相同。 (在 non-canonical 模式下,特殊字符的含義更改為延時含義。MIN 表示應(yīng)當(dāng)被讀入的最小字符數(shù)。TIME 是以十分之一秒為單位的計時器。如果同時設(shè)置了它們,read 將等待直到至少讀入一個字符,一旦讀入 MIN 個字符或者從上次讀入字符開始經(jīng)過了 TIME 時間就立即返回。如果只設(shè)置了 MIN,read 在讀入 MIN 個字符之前不會返回。如果只設(shè)置了 TIME,read 將在至少讀入一個字符,或者計時器超時的時候立即返回。如果都沒有設(shè)置,read 將立即返回,只給出當(dāng)前準(zhǔn)備好的字符。) (?)

tcgetattr()?得到與?fd?指向的對象相關(guān)的參數(shù),將它們保存于?termios_p?引用的?termios?結(jié)構(gòu)中。函數(shù)可以從后臺進程中調(diào)用;但是,終端屬性可能被后來的前臺進程所改變。

tcsetattr()?設(shè)置與終端相關(guān)的參數(shù) (除非需要底層支持卻無法滿足),使用?termios_p?引用的?termios?結(jié)構(gòu)。optional_actions?指定了什么時候改變會起作用:

TCSANOW
改變立即發(fā)生
TCSADRAIN
改變在所有寫入? fd?的輸出都被傳輸后生效。這個函數(shù)應(yīng)當(dāng)用于修改影響輸出的參數(shù)時使用。
TCSAFLUSH
改變在所有寫入? fd?引用的對象的輸出都被傳輸后生效,所有已接受但未讀入的輸入都在改變發(fā)生前丟棄。

tcsendbreak()?傳送連續(xù)的 0 值比特流,持續(xù)一段時間,如果終端使用異步串行數(shù)據(jù)傳輸?shù)脑挕H绻?duration是 0,它至少傳輸 0.25 秒,不會超過 0.5 秒。如果?duration?非零,它發(fā)送的時間長度由實現(xiàn)定義。

如果終端并非使用異步串行數(shù)據(jù)傳輸,tcsendbreak()?什么都不做。

tcdrain()?等待直到所有寫入?fd?引用的對象的輸出都被傳輸。

tcflush()?丟棄要寫入 引用的對象,但是尚未傳輸?shù)臄?shù)據(jù),或者收到但是尚未讀取的數(shù)據(jù),取決于queue_selector?的值:

TCIFLUSH
刷新收到的數(shù)據(jù)但是不讀
TCOFLUSH
刷新寫入的數(shù)據(jù)但是不傳送
TCIOFLUSH
同時刷新收到的數(shù)據(jù)但是不讀,并且刷新寫入的數(shù)據(jù)但是不傳送

tcflow()?掛起?fd?引用的對象上的數(shù)據(jù)傳輸或接收,取決于?action?的值:

TCOOFF
掛起輸出
TCOON
重新開始被掛起的輸出
TCIOFF
發(fā)送一個 STOP 字符,停止終端設(shè)備向系統(tǒng)傳送數(shù)據(jù)
TCION
發(fā)送一個 START 字符,使終端設(shè)備向系統(tǒng)傳輸數(shù)據(jù)

打開一個終端設(shè)備時的默認(rèn)設(shè)置是輸入和輸出都沒有掛起。

波特率函數(shù)被用來獲取和設(shè)置?termios?結(jié)構(gòu)中,輸入和輸出波特率的值。新值不會馬上生效,直到成功調(diào)用了tcsetattr()?函數(shù)。

設(shè)置速度為?B0?使得 modem "掛機"。與?B38400?相應(yīng)的實際比特率可以用?setserial(8) 調(diào)整。

輸入和輸出波特率被保存于?termios?結(jié)構(gòu)中。

cfmakeraw?設(shè)置終端屬性如下:

termios_p->c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);termios_p->c_oflag &= ~OPOST;termios_p->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);termios_p->c_cflag &= ~(CSIZE|PARENB);termios_p->c_cflag |= CS8;

cfgetospeed()?返回?termios_p?指向的?termios?結(jié)構(gòu)中存儲的輸出波特率

cfsetospeed()?設(shè)置?termios_p?指向的?termios?結(jié)構(gòu)中存儲的輸出波特率為?speed。取值必須是以下常量之一:

B0B50B75B110B134B150B200B300B600B1200B1800B2400B4800B9600B19200B38400B57600B115200B230400

零值?B0?用來中斷連接。如果指定了 B0,不應(yīng)當(dāng)再假定存在連接。通常,這樣將斷開連接。CBAUDEX?是一個掩碼,指示高于 POSIX.1 定義的速度的那一些 (57600 及以上)。因此,B57600?&?CBAUDEX?為非零。

cfgetispeed()?返回?termios?結(jié)構(gòu)中存儲的輸入波特率。

cfsetispeed()?設(shè)置?termios?結(jié)構(gòu)中存儲的輸入波特率為?speed。如果輸入波特率被設(shè)為0,實際輸入波特率將等于輸出波特率。??

RETURN VALUE 返回值

cfgetispeed()?返回?termios?結(jié)構(gòu)中存儲的輸入波特率。

cfgetospeed()?返回?termios?結(jié)構(gòu)中存儲的輸出波特率。

其他函數(shù)返回:

0
成功
-1
失敗,并且為? errno?置值來指示錯誤。

注意?tcsetattr()?返回成功,如果任何所要求的修改可以實現(xiàn)的話。因此,當(dāng)進行多重修改時,應(yīng)當(dāng)在這個函數(shù)之后再次調(diào)用?tcgetattr()?來檢測是否所有修改都成功實現(xiàn)。

?

NOTES 注意

Unix V7 以及很多后來的系統(tǒng)有一個波特率的列表,在十四個值 B0, ..., B9600 之后可以看到兩個常數(shù) EXTA, EXTB ("External A" and "External B")。很多系統(tǒng)將這個列表擴展為更高的波特率。

tcsendbreak?中非零的?duration?有不同的效果。SunOS 指定中斷?duration*N?秒,其中?N?至少為 0.25,不高于 0.5 。Linux, AIX, DU, Tru64 發(fā)送?duration?微秒的 break 。FreeBSD, NetBSD, HP-UX 以及 MacOS 忽略duration?的值。在 Solaris 和 Unixware 中,?tcsendbreak?搭配非零的?duration?效果類似于?tcdrain。??

所有的范例來源自?miniterm.c. The type ahead 暫存器被限制在 255 個字元, 就跟標(biāo)準(zhǔn)輸入程序的最大字串長度相同 (<linux/limits.h>?或?<posix1_lim.h>).

參考程序碼中的注解它會解釋不同輸入模式的使用. 我希望這些程序碼都能被了解. 標(biāo)準(zhǔn)輸入程序的程序范例的注解寫得最好, 其它的范例都只在不同于其它范例的地方做注解.

敘述不是很完整, 但可以激勵你對這范例做實驗, 以延生出合于你所需應(yīng)用程序的最佳解.

別忘記要把序列埠的權(quán)限設(shè)定正確 (也就是:?chmod a+rw /dev/ttyS1)!

?

?

3.1 標(biāo)準(zhǔn)輸入程序

?

#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <termios.h> #include <stdio.h>/* 鮑率設(shè)定被定義在 <asm/termbits.h>, 這在 <termios.h> 被引入 */ #define BAUDRATE B38400 /* 定義正確的序列埠 */ #define MODEMDEVICE "/dev/ttyS1" #define _POSIX_SOURCE 1 /* POSIX 系統(tǒng)兼容 */#define FALSE 0 #define TRUE 1volatile int STOP=FALSE; main() {int fd,c, res;struct termios oldtio,newtio;char buf[255]; /* 開啟數(shù)據(jù)機裝置以讀取并寫入而不以控制 tty 的模式因為我們不想程序在送出 CTRL-C 后就被殺掉. */fd = open(MODEMDEVICE, O_RDWR | O_NOCTTY ); if (fd <0) {perror(MODEMDEVICE); exit(-1); }tcgetattr(fd,&oldtio); /* 儲存目前的序列埠設(shè)定 */bzero(&newtio, sizeof(newtio)); /* 清除結(jié)構(gòu)體以放入新的序列埠設(shè)定值 *//* BAUDRATE: 設(shè)定 bps 的速度. 你也可以用 cfsetispeed 及 cfsetospeed 來設(shè)定.CRTSCTS : 輸出資料的硬件流量控制 (只能在具完整線路的纜線下工作參考 Serial-HOWTO 第七節(jié))CS8 : 8n1 (8 位元, 不做同位元檢查,1 個終止位元)CLOCAL : 本地連線, 不具數(shù)據(jù)機控制功能CREAD : 致能接收字元 */newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD;/*IGNPAR : 忽略經(jīng)同位元檢查后, 錯誤的位元組ICRNL : 比 CR 對應(yīng)成 NL (否則當(dāng)輸入信號有 CR 時不會終止輸入)在不然把裝置設(shè)定成 raw 模式(沒有其它的輸入處理) */newtio.c_iflag = IGNPAR | ICRNL;/*Raw 模式輸出. */newtio.c_oflag = 0;/*ICANON : 致能標(biāo)準(zhǔn)輸入, 使所有回應(yīng)機能停用, 并不送出信號以叫用程序 */newtio.c_lflag = ICANON;/* 初始化所有的控制特性預(yù)設(shè)值可以在 /usr/include/termios.h 找到, 在注解中也有,但我們在這不需要看它們 */newtio.c_cc[VINTR] = 0; /* Ctrl-c */ newtio.c_cc[VQUIT] = 0; /* Ctrl-/ */newtio.c_cc[VERASE] = 0; /* del */newtio.c_cc[VKILL] = 0; /* @ */newtio.c_cc[VEOF] = 4; /* Ctrl-d */newtio.c_cc[VTIME] = 0; /* 不使用分割字元組的計時器 */newtio.c_cc[VMIN] = 1; /* 在讀取到 1 個字元前先停止 */newtio.c_cc[VSWTC] = 0; /* '/0' */newtio.c_cc[VSTART] = 0; /* Ctrl-q */ newtio.c_cc[VSTOP] = 0; /* Ctrl-s */newtio.c_cc[VSUSP] = 0; /* Ctrl-z */newtio.c_cc[VEOL] = 0; /* '/0' */newtio.c_cc[VREPRINT] = 0; /* Ctrl-r */newtio.c_cc[VDISCARD] = 0; /* Ctrl-u */newtio.c_cc[VWERASE] = 0; /* Ctrl-w */newtio.c_cc[VLNEXT] = 0; /* Ctrl-v */newtio.c_cc[VEOL2] = 0; /* '/0' *//* 現(xiàn)在清除數(shù)據(jù)機線并啟動序列埠的設(shè)定 */tcflush(fd, TCIFLUSH);tcsetattr(fd,TCSANOW,&newtio);/*終端機設(shè)定完成, 現(xiàn)在處理輸入信號在這個范例, 在一行的開始處輸入 'z' 會退出此程序. */while (STOP==FALSE) { /* 回圈會在我們發(fā)出終止的信號后跳出 *//* 即使輸入超過 255 個字元, 讀取的程序段還是會一直等到行終結(jié)符出現(xiàn)才停止.如果讀到的字元組低于正確存在的字元組, 則所剩的字元會在下一次讀取時取得.res 用來存放真正讀到的字元組個數(shù) */res = read(fd,buf,255); buf[res]=0; /* 設(shè)定字串終止字元, 所以我們能用 printf */printf(":%s:%d/n", buf, res);if (buf[0]=='z') STOP=TRUE;}/* 回存舊的序列埠設(shè)定值 */tcsetattr(fd,TCSANOW,&oldtio); }

?

3.2 非標(biāo)準(zhǔn)輸入程序

在非標(biāo)準(zhǔn)的輸入程序模式下, 輸入的資料不會被組合成一行而輸入后的處理功能 (清除, 殺掉, 刪除, 等等.) 都不能使用. 這個模式有兩個功能控制參數(shù):?c_cc[VTIME]?設(shè)定字元輸入時間計時器, 及?c_cc[VMIN]?設(shè)定滿足讀取功能的最低字元接收個數(shù).

如果 MIN > 0 且 TIME = 0, MIN 設(shè)定為滿足讀取功能的最低字元接收個數(shù). 由于 TIME 是 零, 所以計時器將不被使用.

如果 MIN = 0 且 TIME > 0, TIME 將被當(dāng)做逾時設(shè)定值. 滿足讀取功能的情況為讀取到單一字元, 或者超過 TIME 所定義的時間 (t = TIME *0.1 s). 如果超過 TIME 所定義的時間, 則不會傳回任何字元.

如果 MIN > 0 且 TIME > 0, TIME 將被當(dāng)做一個分割字元組的計時器. 滿足讀取功能的條件為接收到 MIN 個數(shù)的字元, 或兩個字元的間隔時間超過 TIME 所定義的值. 計時器會在每讀到一個字元后重新計時, 且只會在第一個字元收到后才會啟動.

如果 MIN = 0 且 TIME = 0, 讀取功能就馬上被滿足. 目前所存在的字元組個數(shù), 或者 將回傳的字元組個數(shù). 根據(jù) Antonino (參考 貢獻) 所說, 你可以用?fcntl(fd, F_SETFL, FNDELAY);?在讀取前得到相同的結(jié)果.

藉由修改?newtio.c_cc[VTIME]?及?newtio.c_cc[VMIN]?上述的模式就可以測試了.

?

#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <termios.h> #include <stdio.h>#define BAUDRATE B38400 #define MODEMDEVICE "/dev/ttyS1" #define _POSIX_SOURCE 1 /* POSIX 系統(tǒng)兼容 */ #define FALSE 0 #define TRUE 1volatile int STOP=FALSE; main() {int fd,c, res;struct termios oldtio,newtio;char buf[255];fd = open(MODEMDEVICE, O_RDWR | O_NOCTTY ); if (fd <0) {perror(MODEMDEVICE); exit(-1); }tcgetattr(fd,&oldtio); /* 儲存目前的序列埠設(shè)定 */bzero(&newtio, sizeof(newtio));newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD;newtio.c_iflag = IGNPAR;newtio.c_oflag = 0;/* 設(shè)定輸入模式 (非標(biāo)準(zhǔn)型, 不回應(yīng),...) */newtio.c_lflag = 0;newtio.c_cc[VTIME] = 0; /* 不使用分割字元組計時器 */newtio.c_cc[VMIN] = 5; /* 在讀取到 5 個字元前先停止 */tcflush(fd, TCIFLUSH);tcsetattr(fd,TCSANOW,&newtio);while (STOP==FALSE) { /* 輸入回圈 */res = read(fd,buf,255); /* 在輸入 5 個字元后即返回 */buf[res]=0; /* 所以我們能用 printf... */printf(":%s:%d/n", buf, res);if (buf[0]=='z') STOP=TRUE;}tcsetattr(fd,TCSANOW,&oldtio); }

?

3.3 非同步式輸入

?

#include <termios.h> #include <stdio.h> #include <unistd.h> #include <fcntl.h> #include <sys/signal.h> #include <sys/types.h>#define BAUDRATE B38400 #define MODEMDEVICE "/dev/ttyS1" #define _POSIX_SOURCE 1 /* POSIX 系統(tǒng)兼容 */ #define FALSE 0 #define TRUE 1volatile int STOP=FALSE; void signal_handler_IO (int status); /* 定義信號處理程序 */ int wait_flag=TRUE; /* 沒收到信號的話就會是 TRUE */main() {int fd,c, res;struct termios oldtio,newtio;struct sigaction saio; /* definition of signal action */char buf[255];/* 開啟裝置為 non-blocking (讀取功能會馬上結(jié)束返回) */fd = open(MODEMDEVICE, O_RDWR | O_NOCTTY | O_NONBLOCK);if (fd <0) {perror(MODEMDEVICE); exit(-1); }/* 在使裝置非同步化前, 安裝信號處理程序 */saio.sa_handler = signal_handler_IO;saio.sa_mask = 0;saio.sa_flags = 0;saio.sa_restorer = NULL;sigaction(SIGIO,&saio,NULL);/* 允許行程去接收 SIGIO 信號*/fcntl(fd, F_SETOWN, getpid());/* 使文檔ake the file descriptor 非同步 (使用手冊上說只有 O_APPEND 及O_NONBLOCK, 而 F_SETFL 也可以用...) */fcntl(fd, F_SETFL, FASYNC);tcgetattr(fd,&oldtio); /* 儲存目前的序列埠設(shè)定值 *//* 設(shè)定新的序列埠為標(biāo)準(zhǔn)輸入程序 */newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD;newtio.c_iflag = IGNPAR | ICRNL;newtio.c_oflag = 0;newtio.c_lflag = ICANON;newtio.c_cc[VMIN]=1;newtio.c_cc[VTIME]=0;tcflush(fd, TCIFLUSH);tcsetattr(fd,TCSANOW,&newtio);/* 等待輸入信號的回圈. 很多有用的事我們將在這做 */ while (STOP==FALSE) {printf("./n");usleep(100000);/* 在收到 SIGIO 后, wait_flag = FALSE, 輸入信號存在則可以被讀取 */if (wait_flag==FALSE) { res = read(fd,buf,255);buf[res]=0;printf(":%s:%d/n", buf, res);if (res==1) STOP=TRUE; /* 如果只輸入 CR 則停止回圈 */wait_flag = TRUE; /* 等待新的輸入信號 */}}/* 回存舊的序列埠設(shè)定值 */tcsetattr(fd,TCSANOW,&oldtio); }/*************************************************************************** * 信號處理程序. 設(shè)定 wait_flag 為 FALSE, 以使上述的回圈能接收字元 * ***************************************************************************/void signal_handler_IO (int status) {printf("received SIGIO signal./n");wait_flag = FALSE; }

?

3.4 等待來自多個信號來源的輸入

這一段很短. 它只能被拿來當(dāng)成寫程序時的提示, 故范例程序也很簡短. 但這個范例不只能用在序列埠上, 還可以用在被當(dāng)成文檔來使用的裝置上.

select 呼叫及伴隨它所引發(fā)的巨集共用?fd_set.?fd_set?則是一個位元陣列, 而其中每一個位元代表一個有效的文檔敘述結(jié)構(gòu).?select?呼叫接受一個有效的文檔敘述結(jié)構(gòu)并傳回?fd_set?位元陣列, 而該位元陣列中若有某一個位元為 1, 就表示相對映的文檔敘述結(jié)構(gòu)的文檔發(fā)生了輸入, 輸出或有例外事件. 而這些巨集提供了所有處理?fd_set的功能. 亦可參考手冊 select(2).

?

#include <sys/time.h> #include <sys/types.h> #include <unistd.h>main() {int fd1, fd2; /* 輸入源 1 及 2 */fd_set readfs; /* 文檔敘述結(jié)構(gòu)設(shè)定 */int maxfd; /* 最大可用的文檔敘述結(jié)構(gòu) */int loop=1; /* 回圈在 TRUE 時成立 */ /* open_input_source 開啟一個裝置, 正確的設(shè)定好序列埠,并回傳回此文檔敘述結(jié)構(gòu)體 */fd1 = open_input_source("/dev/ttyS1"); /* COM2 */if (fd1<0) exit(0);fd2 = open_input_source("/dev/ttyS2"); /* COM3 */if (fd2<0) exit(0);maxfd = MAX (fd1, fd2)+1; /* 測試最大位元輸入 (fd) *//* 輸入回圈 */while (loop) {FD_SET(fd1, &readfs); /* 測試輸入源 1 */FD_SET(fd2, &readfs); /* 測試輸入源 2 *//* block until input becomes available */select(maxfd, &readfs, NULL, NULL, NULL);if (FD_ISSET(fd1)) /* 如果輸入源 1 有信號 */handle_input_from_source1();if (FD_ISSET(fd2)) /* 如果輸入源 2 有信號 */handle_input_from_source2();}}

這個范例程序在等待輸入信號出現(xiàn)前, 不能確定它會停頓下來. 如果你需要在輸入時加入逾時功能, 只需把 select 呼叫換成:

int res; struct timeval Timeout;/* 設(shè)定輸入回圈的逾時值 */ Timeout.tv_usec = 0; /* 毫秒 */ Timeout.tv_sec = 1; /* 秒 */ res = select(maxfd, &readfs, NULL, NULL, &Timeout); if (res==0) /* 文檔敘述結(jié)構(gòu)數(shù)在 input = 0 時, 會發(fā)生輸入逾時. */

這個程序會在 1 秒鐘后逾時. 如果超過時間, select 會傳回 0, 但是應(yīng)該留意?Timeout?的時間遞減是由?select?所等待輸入信號的時間為基準(zhǔn). 如果逾時的值是 0, select 會馬上結(jié)束返回.

?

?

Linux 環(huán)境下使用RS-232接口

RS是英文 "推薦標(biāo)準(zhǔn)"的縮寫
232為標(biāo)識號
RS-485?

串口通信表示計算機一次傳送一個位的數(shù)據(jù),
當(dāng)使用串行通信時,每個字的數(shù)據(jù)是一個位一個位的傳輸或接收的,
每個位不是高電平,就是低電平.

串行通信的速率通常是使用"位/每秒"的方式來表示的,即波特率。


全雙工--計算機可以同時收發(fā)數(shù)據(jù),
它有兩個獨立的數(shù)據(jù)通道,一個輸入,一個輸出,

半雙工意味著計算機不能同時收發(fā)信息,
只能有一人通道進行通信.


流控:

??? 通常,當(dāng)數(shù)據(jù)在兩個串行接口之間進行傳輸時需要對其進行控制.
??? 這通常依賴于串行通信連接的各種規(guī)定,
????
??? 對異步數(shù)據(jù)傳輸?shù)目刂朴袃煞N方法.
????
??? 一種叫:“軟件”流控 。
??? 一種叫: “硬件"流控 。

串口設(shè)備:

?打開一個串行口

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>? // 文件控制定義
#include <errno.h>
#include <termios.h>? //POSIX終端控制定義

/*
?* open_port() --打開串行口
?*?
?* 成功的話,返回文件描述符,錯誤則返回 -1.
*/

int? open_port(void)
{
??? int fd;
??? fd=open("/dev/ttyS0",O_RDWR|O_NOCTTY|O_NDELAY);
??? if (fd == -1)
??? {
??? /*無法打開串口*/
??? perror("open_port : Unable to open /dev/ttyS0");
??? }
??? else
??? ??? fcntl(fd,F_SETFL,0);
??? return (fd);
}

//O_NOCTTY 標(biāo)志 ,該程序不想成為此端口的“控制終端"。
????????????????? 如果沒有強調(diào)這一點,
//O_NDELAY標(biāo)志 , 標(biāo)志告訴Linux ,該程序并不關(guān)注DCD信叼線所處的狀態(tài),
即不管另外一端的設(shè)備是在運行還是被掛起。如果沒有指定該標(biāo)志,那么程序就會被設(shè)置睡
眠狀態(tài),

(2)向端口寫數(shù)據(jù)
??? 向端口寫數(shù)據(jù)是很容易的,只要使用write()系統(tǒng)調(diào)用就可以了。
??? 例如:
??? ???? n=write(fd,"ATZ/r",4);
??? if (n<0)
??? ??? fputs("write() of 4 bytes failed!/n",stderr);
????
??? write函數(shù)返回發(fā)送數(shù)據(jù)的個數(shù),如果出現(xiàn)錯誤,則返回 -1。

(3) 讀端口數(shù)據(jù)

??? 從端口讀數(shù)據(jù)則需要些技巧。如果在原始數(shù)據(jù)的模式下對端口進行操作,
??? read()系統(tǒng)調(diào)用將返回串行口輸入緩沖區(qū)中所有的字符數(shù)據(jù),不管有多少,
????
??? 如果沒有數(shù)據(jù),那么該調(diào)用將被阻塞.處于等待狀態(tài),直到有字符輸入,
??? 或者到了規(guī)定的時限和出現(xiàn)錯誤為止,
??? 通過以下方法,能使read函數(shù)立即返回。

??? fcntl(fd,F_SETFL,FNDELAY);

??? FNDELAY 函數(shù)使read函數(shù)在端口沒月字符存在的情況下,立刻返回0,
??? 如果要恢復(fù)正常(阻塞)狀態(tài),可以調(diào)用fcntl()函數(shù),不要FNDELAY參數(shù),
??? 如下所示:
??? ??? fcntl(Fd,F_SETFL,0);
??? 在使用O_NDELAY參數(shù)打開串行口后,同樣與使用了該函數(shù)調(diào)用。
????
??? fcntl(fd,F_SETFL,0);

POSIX終端接口
??? 串口,波特率,字符大小等, <termios.h>

??? POSIX函數(shù)是 tcgetattr()和tcsetattr()?
????
??? 獲取和設(shè)置終端的屬性,
??? ??? 可以提供 structrure termios的指針,
??? ????
??? termios結(jié)構(gòu)的成員 :
????
??? ?參數(shù)?????? 功能
??? C_cflag???? 控制參數(shù)
??? C_

?

本文轉(zhuǎn)自:http://blog.csdn.net/chenchao03/article/details/3219791


總結(jié)

以上是生活随笔為你收集整理的linux tty pty pts tts概念 区别的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。