slave fd被另一个应用程序(比如"A")用作串行端口设备.
A将设置其波特率/停止位等.我的应用程序需要此信息.
顺便说一下,有没有办法让只有主fd打开的进程被通知所有ioctl()发给奴隶fd的电话?
是的,这是可能的(在Linux和2004年之前的FreeBSD中),在数据包模式下使用pty并在其上设置EXTPROC标志.
在主端上启用数据包模式ioctl(master, TIOCPKT, &nonzero).现在read主端的每一个都会产生一个数据包:无论在另一端写入什么,加上一个状态字节,说明从端的情况("终端的写队列(即从端)被刷新" )
但是,这并不意味着主设备立即意识到从设备端的变化,例如,只要有东西要读select(),主设备就不会在这些变化发生时立即返回
但是,在pty的本地标志字中设置EXTPROC之后 - 使用tcsetattr()- select() 将在从属状态改变后立即返回,然后可以直接通过我们在父进程中保持打开的从属fd检查从属终端,或者,至少在Linux上,只需tcgetattr()在主方面.
请注意,EXTPROC禁用pty驱动程序的某些部分,例如关闭本地回显.
EXTPROC没有被大量使用(这是一个可能的用例),不是非常便携,根本没有记录(至少在Linux termios或tty_ioctl联机帮助页面中已经存在).看看linux内核源码drivers/tty/n_tty.c我得出结论,奴隶termios结构的任何变化都会使得select()主端返回 - 但是tcsetattr()不会改变任何东西.
编辑:为了回应JF Sebastians的请求,我给出了一个示例程序,该程序应该明确如何EXTRPOC在linux机器上使用数据包模式:
/* Demo program for managing a pty in packet mode with the slave's
** EXTPROC bit set, where the master gets notified of changes in the
** slaves terminal attributes
**
** save as extproc.c, compile with gcc -o extproc extproc.c -lutil
*/
#include <stdio.h>
#include <pty.h>
#include <termios.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/select.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#define BUFSIZE 512
void main() {
int master; // fd of master side
pid_t pid;
if((pid = forkpty(&master, NULL, NULL, NULL))) { // we're parent
fd_set rfds, xfds;
int retval, nread, status = 0, nonzero = 1;
char buf[BUFSIZE];
ioctl(master, TIOCPKT, &nonzero); // initiate packet mode - necessary to get notified of
// ioctl() on the slave side
while(1) {
// set stdout unbuffered (we want to see stuff as it happens)
setbuf(stdout, NULL);
// prepare the file descriptor sets
FD_ZERO(&rfds);
FD_SET(master, &rfds);
FD_ZERO(&xfds);
FD_SET(master, &xfds);
// now wait until status of master changes
printf("---- waiting for something to happen -----\n");
select(1 + master, &rfds, NULL, &xfds, NULL);
char *r_text = (FD_ISSET(master, &rfds) ? "master ready for reading" : "- ");
char *x_text = (FD_ISSET(master, &xfds) ? "exception on master" : "- ");
printf("rfds: %s, xfds: %s\n", r_text, x_text);
if ((nread = read(master, buf, BUFSIZE-1)) < 0)
perror("read error");
else {
buf[nread] = '\0';
// In packet mode *buf will be the status byte , and buf + 1 the "payload"
char *pkt_txt = (*buf & TIOCPKT_IOCTL ? " (TIOCPKT_IOCTL)" : "");
printf("read %d bytes: status byte %x%s, payload <%s>\n", nread, *buf, pkt_txt, buf + 1);
}
if (waitpid(pid, &status, WNOHANG) && WIFEXITED(status)) {
printf("child exited with status %x\n", status);
exit(EXIT_SUCCESS);
}
}
} else { // child
struct termios tio;
// First set the EXTPROC bit in the slave end termios structure
tcgetattr(STDIN_FILENO, &tio);
tio.c_lflag |= EXTPROC;
tcsetattr(STDIN_FILENO, TCSANOW, &tio);
// Wait a bit and do an ordinary write()
sleep(1);
write(STDOUT_FILENO,"blah", 4);
// Wait a bit and change the pty terminal attributes. This will be picked up by the master end
sleep(1);
tio.c_cc[VINTR] = 0x07;
tcsetattr(STDIN_FILENO, TCSANOW, &tio);
// Wait a bit and exit
sleep(1);
}
}
Run Code Online (Sandbox Code Playgroud)
输出将是这样的:
---- waiting for something to happen -----
rfds: master ready for reading, xfds: exception on master
read 1 bytes: status byte 40 (TIOCPKT_IOCTL), payload <>
---- waiting for something to happen -----
rfds: master ready for reading, xfds: -
read 5 bytes: status byte 0, payload <blah>
---- waiting for something to happen -----
rfds: master ready for reading, xfds: exception on master
read 1 bytes: status byte 40 (TIOCPKT_IOCTL), payload <>
---- waiting for something to happen -----
rfds: master ready for reading, xfds: -
read error: Input/output error
child exited with status 0
Run Code Online (Sandbox Code Playgroud)
一般来说,pty的主端不一定是tty(并且具有相关的termios结构),但在Linux下,它是(共享termios:一端的更改将同时改变两个termios结构).
这意味着我们可以修改上面的示例程序并EXTPROC在主方面设置,它不会有任何区别.
所有这些都没有记录在我看来,当然也不那么便携.