文章目录
1. 终端IO 数据结构
- 每个终端设备都有相应的输入/输出队列
输入队列数据可能来自于键盘,串口等输入设备。也可能来自于其它进程
输出队列数据可能递送给显示器,也可能递送给其它进程
输入队列:
可能工作在两种模式下,规范输入处理和非规范输入处理
- 数据控制
- 来自键盘/串口的数据输入递送到输入队列后,可能拷贝到输出队列(回显)
- 来自键盘/串口的数据输入过多,超过MAX_INPUT(大多数系统在输出队列递送响铃字符)。
- 规范输入处理,最大行字节数为MAX_CANON
- 向缓冲写,当写队列满时,写进程会睡眠
- 缓冲队列可以进行刷新操作!属性可配置
tcflag_t c_iflag; /* input modes */
tcflag_t c_oflag; /* output modes */
tcflag_t c_cflag; /* control modes RS232控制*/
tcflag_t c_lflag; /* local modes */
cc_t c_cc[NCCS]; /* special characters */
***c_iflag:***
(? 什么是BREAK?)
IGNBRK Ignore BREAK condition on input.
BRKINT If IGNBRK is set, a BREAK is ignored. If it is not set but
BRKINT is set, then a BREAK causes the input and output queues
to be flushed, and if the terminal is the controlling terminal
of a foreground process group, it will cause a SIGINT to be sent
to this foreground process group. When neither IGNBRK nor
BRKINT are set, a BREAK reads as a null byte ('\0'), except when
PARMRK is set, in which case it reads as the sequence \377 \0
\0.
(忽略校验错误)
IGNPAR Ignore framing errors and parity errors.
PARMRK If this bit is set, input bytes with parity or framing errors
are marked when passed to the program. This bit is meaningful
only when INPCK is set and IGNPAR is not set. The way erroneous
bytes are marked is with two preceding bytes, \377 and \0.
Thus, the program actually reads three bytes for one erroneous
byte received from the terminal. If a valid byte has the value
\377, and ISTRIP (see below) is not set, the program might con‐
fuse it with the prefix that marks a parity error. Therefore, a
valid byte \377 is passed to the program as two bytes, \377
\377, in this case.
If neither IGNPAR nor PARMRK is set, read a character with a
parity error or framing error as \0.
(输入校验检查)
INPCK Enable input parity checking.
(剥除输入字符的bit7)
ISTRIP Strip off eighth bit.
INLCR Translate NL to CR on input.
IGNCR Ignore carriage return on input.
ICRNL Translate carriage return to newline on input (unless IGNCR is
set).
IUCLC (not in POSIX) Map uppercase characters to lowercase on input.
(???)
IXON Enable XON/XOFF flow control on output.
IXANY (XSI) Typing any character will restart stopped output. (The
default is to allow just the START character to restart output.)
(???)
IXOFF Enable XON/XOFF flow control on input.
IMAXBEL
(not in POSIX) Ring bell when input queue is full. Linux does
not implement this bit, and acts as if it is always set.
IUTF8 (since Linux 2.6.4)
(not in POSIX) Input is UTF8; this allows character-erase to be
correctly performed in cooked mode.
***c_oflag:***
OPOST Enable implementation-defined output processing.
OLCUC (not in POSIX) Map lowercase characters to uppercase on output.
ONLCR (XSI) Map NL to CR-NL on output.
OCRNL Map CR to NL on output.
ONOCR Don't output CR at column 0.
ONLRET Don't output CR.
OFILL Send fill characters for a delay, rather than using a timed
delay.
OFDEL Fill character is ASCII DEL (0177). If unset, fill character is
ASCII NUL ('\0'). (Not implemented on Linux.)
NLDLY Newline delay mask. Values are NL0 and NL1. [requires
_BSD_SOURCE or _SVID_SOURCE or _XOPEN_SOURCE]
CRDLY Carriage return delay mask. Values are CR0, CR1, CR2, or CR3.
[requires _BSD_SOURCE or _SVID_SOURCE or _XOPEN_SOURCE]
TABDLY Horizontal tab delay mask. Values are TAB0, TAB1, TAB2, TAB3
(or XTABS). A value of TAB3, that is, XTABS, expands tabs to
spaces (with tab stops every eight columns). [requires
_BSD_SOURCE or _SVID_SOURCE or _XOPEN_SOURCE]
BSDLY Backspace delay mask. Values are BS0 or BS1. (Has never been
implemented.) [requires _BSD_SOURCE or _SVID_SOURCE or
_XOPEN_SOURCE]
VTDLY Vertical tab delay mask. Values are VT0 or VT1.
FFDLY Form feed delay mask. Values are FF0 or FF1. [requires
_BSD_SOURCE or _SVID_SOURCE or _XOPEN_SOURCE]
c_cflag:
(字符大小屏蔽)
CSIZE Character size mask. Values are CS5, CS6, CS7, or CS8.
(停止位个数)
CSTOPB Set two stop bits, rather than one.
CREAD Enable receiver.
(奇偶校验使能)
PARENB Enable parity generation on output and parity checking for
input.
(奇偶校验:奇或者偶配置)
PARODD If set, then parity for input and output is odd; otherwise even
parity is used.
HUPCL Lower modem control lines after last process closes the device
(hang up).
CLOCAL Ignore modem control lines.
LOBLK (not in POSIX) Block output from a noncurrent shell layer. For
use by shl (shell layers). (Not implemented on Linux.)
CIBAUD (not in POSIX) Mask for input speeds. The values for the CIBAUD
bits are the same as the values for the CBAUD bits, shifted left
IBSHIFT bits. [requires _BSD_SOURCE or _SVID_SOURCE] (Not
implemented on Linux.)
CMSPAR (not in POSIX) Use "stick" (mark/space) parity (supported on
certain serial devices): if PARODD is set, the parity bit is
always 1; if PARODD is not set, then the parity bit is always 0.
[requires _BSD_SOURCE or _SVID_SOURCE]
CRTSCTS
(not in POSIX) Enable RTS/CTS (hardware) flow control.
[requires _BSD_SOURCE or _SVID_SOURCE]
c_lflag:
(启动终端产生信号)
ISIG When any of the characters INTR, QUIT, SUSP, or DSUSP are
received, generate the corresponding signal.
(启用规范行输入处理)
ICANON Enable canonical mode (described below).
XCASE (not in POSIX; not supported under Linux) If ICANON is also set,
terminal is uppercase only. Input is converted to lowercase,
except for characters preceded by \. On output, uppercase char‐
acters are preceded by \ and lowercase characters are converted
to uppercase. [requires _BSD_SOURCE or _SVID_SOURCE or
_XOPEN_SOURCE]
(输入需要回显)
ECHO Echo input characters.
(规范输入行处理 && 擦除字符功能使能)
ECHOE If ICANON is also set, the ERASE character erases the preceding
input character, and WERASE erases the preceding word.
(规范输入行处理 && KILL字符擦除当前行)
ECHOK If ICANON is also set, the KILL character erases the current
line.
(规范输入行处理 && 设置回显字符为 NL字符)
ECHONL If ICANON is also set, echo the NL character even if ECHO is not
set.
ECHOCTL
(not in POSIX) If ECHO is also set, terminal special characters
other than TAB, NL, START, and STOP are echoed as ^X, where X is
the character with ASCII code 0x40 greater than the special
character. For example, character 0x08 (BS) is echoed as ^H.
[requires _BSD_SOURCE or _SVID_SOURCE]
ECHOPRT
(not in POSIX) If ICANON and ECHO are also set, characters are
printed as they are being erased. [requires _BSD_SOURCE or
_SVID_SOURCE]
ECHOKE (not in POSIX) If ICANON is also set, KILL is echoed by erasing
each character on the line, as specified by ECHOE and ECHOPRT.
[requires _BSD_SOURCE or _SVID_SOURCE]
DEFECHO
(not in POSIX) Echo only when a process is reading. (Not imple‐
mented on Linux.)
FLUSHO (not in POSIX; not supported under Linux) Output is being
flushed. This flag is toggled by typing the DISCARD character.
[requires _BSD_SOURCE or _SVID_SOURCE]
(中断字符禁止刷新缓冲)
NOFLSH Disable flushing the input and output queues when generating
signals for the INT, QUIT, and SUSP characters.
(后台进程尝试写终端设备,发送信号SIGTTOU )
TOSTOP Send the SIGTTOU signal to the process group of a background
process which tries to write to its controlling terminal.
PENDIN (not in POSIX; not supported under Linux) All characters in the
input queue are reprinted when the next character is read.
(bash(1) handles typeahead this way.) [requires _BSD_SOURCE or
_SVID_SOURCE]
(???)
IEXTEN Enable implementation-defined input processing. This flag, as
well as ICANON must be enabled for the special characters EOL2,
LNEXT, REPRINT, WERASE to be interpreted, and for the IUCLC flag
to be effective.
c_cc:
The c_cc array defines the terminal special characters. The symbolic
indices (initial values) and meaning are:
VDISCARD
(not in POSIX; not supported under Linux; 017, SI, Ctrl-O) Tog‐
gle: start/stop discarding pending output. Recognized when IEX‐
TEN is set, and then not passed as input.
VDSUSP (not in POSIX; not supported under Linux; 031, EM, Ctrl-Y)
Delayed suspend character (DSUSP): send SIGTSTP signal when the
character is read by the user program. Recognized when IEXTEN
and ISIG are set, and the system supports job control, and then
not passed as input.
VEOF (004, EOT, Ctrl-D) End-of-file character (EOF). More precisely:
this character causes the pending tty buffer to be sent to the
waiting user program without waiting for end-of-line. If it is
the first character of the line, the read(2) in the user program
returns 0, which signifies end-of-file. Recognized when ICANON
is set, and then not passed as input.
VEOL (0, NUL) Additional end-of-line character (EOL). Recognized
when ICANON is set.
VEOL2 (not in POSIX; 0, NUL) Yet another end-of-line character (EOL2).
Recognized when ICANON is set.
VERASE (0177, DEL, rubout, or 010, BS, Ctrl-H, or also #) Erase charac‐
ter (ERASE). This erases the previous not-yet-erased character,
but does not erase past EOF or beginning-of-line. Recognized
when ICANON is set, and then not passed as input.
VINTR (003, ETX, Ctrl-C, or also 0177, DEL, rubout) Interrupt charac‐
ter (INTR). Send a SIGINT signal. Recognized when ISIG is set,
and then not passed as input.
VKILL (025, NAK, Ctrl-U, or Ctrl-X, or also @) Kill character (KILL).
This erases the input since the last EOF or beginning-of-line.
Recognized when ICANON is set, and then not passed as input.
VLNEXT (not in POSIX; 026, SYN, Ctrl-V) Literal next (LNEXT). Quotes
the next input character, depriving it of a possible special
meaning. Recognized when IEXTEN is set, and then not passed as
input.
VMIN Minimum number of characters for noncanonical read (MIN).
VQUIT (034, FS, Ctrl-\) Quit character (QUIT). Send SIGQUIT signal.
Recognized when ISIG is set, and then not passed as input.
VREPRINT
(not in POSIX; 022, DC2, Ctrl-R) Reprint unread characters (RE‐
PRINT). Recognized when ICANON and IEXTEN are set, and then not
passed as input.
VSTART (021, DC1, Ctrl-Q) Start character (START). Restarts output
stopped by the Stop character. Recognized when IXON is set, and
then not passed as input.
VSTATUS
(not in POSIX; not supported under Linux; status request: 024,
DC4, Ctrl-T). Status character (STATUS). Display status infor‐
mation at terminal, including state of foreground process and
amount of CPU time it has consumed. Also sends a SIGINFO signal
(not supported on Linux) to the foreground process group.
VSTOP (023, DC3, Ctrl-S) Stop character (STOP). Stop output until
Start character typed. Recognized when IXON is set, and then
not passed as input.
VSUSP (032, SUB, Ctrl-Z) Suspend character (SUSP). Send SIGTSTP sig‐
nal. Recognized when ISIG is set, and then not passed as input.
VSWTCH (not in POSIX; not supported under Linux; 0, NUL) Switch charac‐
ter (SWTCH). Used in System V to switch shells in shell layers,
a predecessor to shell job control.
VTIME Timeout in deciseconds for noncanonical read (TIME).
VWERASE
(not in POSIX; 027, ETB, Ctrl-W) Word erase (WERASE). Recog‐
nized when ICANON and IEXTEN are set, and then not passed as
input.
- 终端行规模块
- 终端设备属性接口
2. 终端IO 编程举例
2.1 终端特殊输入字符
表中可被更改的字符 映射位置在
cc_t c_cc[NCCS]; /* special characters */取相应下标
- 禁止中断字符
- 文件结束符 修改为’CTRL + B’
/*
TCSANOW
the change occurs immediately.
TCSADRAIN
the change occurs after all output written to fd has been trans‐
mitted. This option should be used when changing parameters
that affect output.
TCSAFLUSH
the change occurs after all output written to the object
referred by fd has been transmitted, and all input that has been
received but not read will be discarded before the change is
made.
*/
extern "C"
{
#include <termios.h>
#include <unistd.h>
}
#include <iostream>
using namespace std;
int main(void)
{
long vdisable;
struct termios term;
/**/
if(isatty(STDIN_FILENO)==0)
{
cout << "Not a ttydevice" << endl;
return -1;
}
/**/
if((vdisable = fpathconf(STDIN_FILENO,_PC_VDISABLE)) < 0)
{
cout << "can not get vdisable " << endl;
return -1;
}
/**/
if(tcgetattr(STDIN_FILENO,&term) < 0)
{
cout << "failed to get termio" << endl;
return -1;
}
term.c_cc[VINTR]=vdisable;
term.c_cc[VEOF]=2;/*ctrl + B*/
if(tcsetattr(STDIN_FILENO, TCSANOW, &term)<0)
{
cout << "failed to set termio" << endl;
return -1;
}
return 0;
}
2.2 终端波特率设置
/*speed_t
B0
B50
B75
B110
B134
B150
B200
B300
B600
B1200
B1800
B2400
B4800
B9600
B19200
B38400
B57600
B115200
B230400
*/
speed_t cfgetispeed(const struct termios *termios_p);
speed_t cfgetospeed(const struct termios *termios_p);
int cfsetispeed(struct termios *termios_p, speed_t speed);
int cfsetospeed(struct termios *termios_p, speed_t speed);
2.3 行控制函数
01 /*???*/
int tcsendbreak(int fd, int duration);
02 /*
tcdrain() waits until all output written to the object referred to by
fd has been transmitted.
*/
int tcdrain(int fd);
03 /*
tcflush() discards data written to the object referred to by fd but not
transmitted, or data received but not read, depending on the value of
queue_selector:
TCIFLUSH
flushes data received but not read.
TCOFLUSH
flushes data written but not transmitted.
TCIOFLUSH
flushes both data received but not read, and data written but
not transmitted.
*/
int tcflush(int fd, int queue_selector);
04 /* tcflow() suspends transmission or reception of data on the object
referred to by fd, depending on the value of action:
TCOOFF suspends output.
TCOON restarts suspended output.
TCIOFF transmits a STOP character, which stops the terminal device from
transmitting data to the system.
TCION transmits a START character, which starts the terminal device
transmitting data to the system.
The default on open of a terminal file is that neither its input nor
its output is suspended.
*/
int tcflow(int fd, int action);
2.4 终端标识
获取终端设备名:
#include <stdio.h>
char *ctermid(char *s);
判断fd是否为终端设备
#include <unistd.h>
int isatty(int fd);
2.5 获取tty描述符对应的设备
NAME
ttyname, ttyname_r - return name of a terminal
SYNOPSIS
#include <unistd.h>
char *ttyname(int fd);
int ttyname_r(int fd, char *buf, size_t buflen);
DESCRIPTION
The function ttyname() returns a pointer to the null-terminated path‐
name of the terminal device that is open on the file descriptor fd, or
NULL on error (for example, if fd is not connected to a terminal). The
return value may point to static data, possibly overwritten by the next
call. The function ttyname_r() stores this pathname in the buffer buf
of length buflen.
RETURN VALUE
The function ttyname() returns a pointer to a pathname on success. On
error, NULL is returned, and errno is set appropriately. The function
ttyname_r() returns 0 on success, and an error number upon error.
#include <iostream>
using namespace std;
extern "C"
{
#include <unistd.h>
}
int main(void)
{
cout << ttyname(0) << endl;
cout << ttyname(1) << endl;
cout << ttyname(2) << endl;
return 0;
}
终端模拟器下的测试 输出:
/dev/pts/2
/dev/pts/2
/dev/pts/2
CTRL + ALT + F6 切换终端 输出:
/dev/tty6
/dev/tty6
/dev/tty6
2.6 规范行输入与非规范行输入
2.6.1 规范行输入模式
返回条件:
- 要求读取的字符个数条件满足,从终端驱动程序返回
- 读到行定界符返回 [NL EOL EOL2 EOF]
- 捕捉到信号并且读函数不自动重启,函数返回
2.6.2 非规范行输入模式
通过c_cc[VMIN] 以及 c_cc[VTIME]
用户自定义:MIN 和 TIME的值
3. 终端IO 控制命令 stty
stty封装了 以下6个接口函数