下面的代码是terminal
IO的非阻塞读取的示例,但是当我在控制台上键入字符时,它不会立即打印出来。 Perpaps你会说我应该私下设置stty -icanon
,所以禁用规范模式,这确实有效,但我想即使我没有禁用stty icanon
,终端的非阻塞读取是character-oriented
,cannonical
模式只是唤醒阻塞过程,但我的进程没有阻塞,如果我们输入一个字符,那么fd是可读的,所以它应该立即打印出来的字符。
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#define MSG_TRY "try again\n"
int main(void)
{
char buf[10];
int fd, n;
fd = open("/dev/tty", O_RDONLY|O_NONBLOCK);
if(fd<0) {
perror("open /dev/tty");
exit(1);
}
tryagain:
n = read(fd, buf, 10);
if (n < 0) {
if (errno == EAGAIN) {
sleep(1);
write(STDOUT_FILENO, MSG_TRY, strlen(MSG_TRY));
goto tryagain;
}
perror("read /dev/tty");
exit(1);
}
write(STDOUT_FILENO, buf, n);
close(fd);
return 0;
}
答案 0 :(得分:1)
O我已经明白了,在打开时使用O_NONBLOCK标志,只是告诉open不要等待调制解调器准备就绪,如果你试图打开一个终端。
发现此来源非常有帮助。 http://en.wikibooks.org/wiki/Serial_Programming/termios#Opening.2FClosing_a_Serial_Device
我今天正在使用tty(RS232端口)设备做一些工作。 http://www.gnu.org/software/libc/manual/html_node/Terminal-Modes.html#Terminal-Modes
您如何知道终端是规范的还是原始的?如果我理解正确,你说你已经设置了终端非规范(原始),但后来又改回来了。它是否正确? 在那种情况下,您的代码中是否设置了非规范设备?
如果你想要原始模式,有一个名为cfmakeraw()的函数。 并且不要忘记使用tcsetattr()设置属性。 例如 const struct termios yourtermios yourtermios.c_cc [VTIME] = 0; yourtermios.c_cc [VMIN] = 1; 或者你认为合适的价值。
以下是有关规范与否的重要信息来源。 http://www.gnu.org/software/libc/manual/html_node/Canonical-or-Not.html#Canonical-or-Not
答案 1 :(得分:0)
如果你想要一个带有一个无缓冲字符的函数,这是我自己编写的函数。它将读取单个字符(大多数时间是一个键击)而无需等待用户按下回车键。
#include <unistd.h>
#include <termios.h>
#include <errno.h>
int ugetc(char *c)
{
if(c == NULL) return EINVAL;
struct termios term;
//Get the current terminal settings so that only
//the settings we want to change are changed
if(tcgetattr(STDIN_FILENO, &term) == -1) return errno;
//Save the original terminal settings
unsigned int c_lflag = term.c_lflag;
unsigned int vmin = term.c_cc[VMIN];
unsigned int vtime = term.c_cc[VTIME];
//If line buffering is turned on then turn if off
if(term.c_lflag & ICANON) term.c_lflag ^= ICANON;
//Make sure that read() will wait for a single character
term.c_cc[VMIN] = 1;
term.c_cc[VTIME] = 0;
//Apply the changed settings
if(tcsetattr(STDIN_FILENO, TCSANOW, &term) == -1) return errno;
//Verify that changes were made properly see "man tcgetattr" for more details
if(tcgetattr(STDIN_FILENO, &term) == -1) return errno;
//Verify that changes were made properly see "man tcgetattr" for more details
if
(
term.c_lflag & ICANON
|| term.c_cc[VMIN] != 1
|| term.c_cc[VTIME] != 0
)
//The value returned can be change to any valid errno macro
return ECANCELED;
//Save the read() return value for later processing
int ret = read(STDIN_FILENO, c, 1);
//Restore the old settings saved from earlier
term.c_lflag = c_lflag;
term.c_cc[VMIN] = vmin;
term.c_cc[VTIME] = vtime;
//Apply the restored settings
if(tcsetattr(STDIN_FILENO, TCSANOW, &term) == -1) return errno;
//Verify the changes were successful see "man tcgetattr" for more details
//NOTE: If tcgetattr() fails to restore the original settings the terminal
//will stay unbuffered
if(tcgetattr(STDIN_FILENO, &term) == -1) return errno;
//Verify the changes were successful see "man tcgetattr" for more details
if
(
term.c_lflag != term.c_lflag
|| term.c_cc[VMIN] != vmin
|| term.c_cc[VTIME] != vtime
)
return ECANCELED;
//If a read error occured return errno
//NOTE: If an error occurs we want to restore the old
//settings anyway so we save the return value and check
//it after the old settings have been restored
if(ret == -1) return errno;
return 0;
}
该功能尚未经过广泛测试,因此您应自行测试。