下面是另外一个概念——伪终端(pseudo-terminal),根据pty(7)的介绍,伪终端一对虚拟设备,提供端到端双向通信的通路,一端称为master,另一端称为slave。在slave那端看到的和在真实终端看到的效果一样。所以伪终端一般被ssh等网络登录程序使用。历史上,有两套伪终端接口,一个是Unix 98伪终端,另一个是BSD伪终端。
BSD提供的接口很简单:/dev/pty[p-za-e][0-9a-f] 是master; /dev/tty[p-za-e][0-9a-f] 是slave,它们都是配好对的。这样看起来很简单,但对程序员来说不容易,要找到一个合适的终端需要一个个从头尝试。所以这种方式已经被遗弃。 而Unix 98伪终端则完全不同,它始终使用/dev/ptmx作为master复制设备,然后在每次打开它的时候才得到一个master设备的fd,同时在/dev/pts/目录下得到一个slave设备。这样编程就相对容易了,根据pts(4)介绍,需要三个新的API: ptsname(3),grantpt(3)和unlockpt(3)。我们可以通过一个实例看一下如何使用:
[cpp] view plain copy
- #include <stdio.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- #include <sys/ioctl.h>
- #include <termios.h>
- #include <unistd.h>
- #include <pthread.h>
- #include <sched.h>
- #include <stropts.h>
- char *mptname = "/dev/ptmx"; /* master pseudo-tty device */
- //...
- int master,slave;
- struct termios sbuf;
- struct winsize size;
- void getmaster()
- {
- struct stat stb;
- if ((master = open(mptname, O_RDWR))>= 0) { /* a pseudo-tty is free */
- (void) ioctl(0, TCGETS, (char *)&sbuf);
- (void) ioctl(0, TIOCGWINSZ, (char *)&size); /// TIOCGWINSZ 获得终端设备的窗口大小 get
- return;
- } else { /* out of pseudo-tty's */
- perror(mptname);
- fprintf(stderr, gettext("Out of pseudo-tty's\n"));
- exit(1);
- }
- }
- void getslave()
- {
- char *slavename; /* name of slave pseudo-tty */
- grantpt(master); /* change permissions of slave */
- unlockpt(master); /* unlock slave */
- slavename = ptsname(master); /* get name of slave */
- slave = open(slavename, O_RDWR); /* open slave */
- if (slave <0) { /* error on opening slave */
- perror(slavename);
- exit(1);
- }
- ioctl(slave, I_PUSH, "ptem"); /* push pt hw emulation module */
- ioctl(slave, I_PUSH, "ldterm"); /* push line discipline */
- (void) ioctl(slave, TCSETSF, (char *)&sbuf);
- (void) ioctl(slave, TIOCSWINSZ, (char *)&size);
- }
|