linux中有好多终端,如下简单介绍下各类终端或并口的概念。
1.1tty:终端设备的总称
tty是Teletype或TeletypeWriter的简写,英文翻译为电传打字机。电传打字机一般有鼠标、收发报器和印字机等组成,是传真机使用原先的通讯设备,原理近似电报。后被显示器和按键所代替,所以如今叫终端比较合适。
终端是一种字符型设备,他有多种类型,一般使用tty来简称各种类型的终端设备。
目前,tty通常指控制终端(man4tty),设备文件是/dev/ttyx,常用的就是linux默认提供的6个命令行终端,可通过Ctrl+Alt+Fn切换图形界面或终端窗口。在Ubuntu命令行输入tty显示终端:
$ tty
/dev/tty2
1.2pty:虚拟终端
Apseudoterminal简写为pty,是虚拟终端或伪终端,可以在终端模拟器(terminalemulator)中运行,manpty查看。pty是成对的逻辑终端设备(即master和slave设备,对master的操作会反映到slave上,对slave的操作也会反映到master上),与实际化学设备无关。Aptyisapairofvirtualcharacterdevicesthatprovideabidirectionalcommunicationchannel.oneendiscalledmaster;theotherendiscalledtheslave.
linux提供了两套虚拟终端插口,BSD-style和SystemV-style,SystemV-style终端也被称为UNIX98pseudoterminals,是目前使用的伪终端式样。
AnunusedUNIX98pseudoterminalmasterisopenedbycallingposix_openpt(3).(Thisfunctionopensthemasterclonedevice,/dev/ptmx;seepts(4).)Afterperforminganyprogram-specificinitializations,changingtheownershipandpermissionsoftheslavedeviceusinggrantpt(3),andunlockingtheslaveusingunlockpt(3)),thecorrespondingslavedevicecanbeopenedbypassingthenamereturnedbyptsname(3)inacalltoopen(2).
PTM指pseudoterminalmaster,PTS指pseudoterminalslave。
/dev/ptmx(UNIX98masterclonedevice),所有主设备对应的设备文件都指向/dev/ptmx
/dev/pts/*(UNIX98slavedevices)
ssh或Telnet登陆远程主机时的终端就是pty,运行tty查看:
$ tty /dev/pts/11
伪终端是一对虚拟的字符设备,linux内核使用一种符合tty线规程(linediscipline)的单向管线联接伪终端的主从设备。主设备上的任何写入操作就会反映到从设备上,反之亦然。从设备上的应用进程可以像使用传统终端一样读取来自主设备上应用程序的输入,以及向主设备应用输出信息。伪终端从设备应用一般是主设备应用的子进程,主应用打开一对伪终端并fork一个子进程,之后子进程打开并使用从设备。
1.3串行端口终端
与计算机串行端口(RS-232)联接的终端设备,对应的设备文件名称为/dev/tty+类型+设备编号linux 虚拟串口软件,如/dev/ttyS0,S表示设备类型,0为指定类型下的设备编号。这儿的串行端口可以是通过硬件或软件模拟的,如USB转并口,虚拟并口。
2.多个虚拟终端
Unix98伪终端使用流程如下:
上述函数都来自glibc库。伪终端编程更常用的API是openpty,直接实现了上述流程的所有步骤。login_tty函数用于实现在指定的终端上启动登入会话。forkpty函数整合了openpty、fork和login_tty,在网路服务程序可用于为柴桥录用户打开一对伪终端,并创建相应的会话子进程。
注意:使用opentty,login_pty和forkpty须要链接util库。
#include #include #include #include #include #include #define SLAVE_DEV_NAME_MAX_LEN 128 #define PTY_BUFF_MAX_LEN 1024 int main(int argc, char *argv[]) { int mpty = 0, spty = 0; int rv = 0, n = 0; char spty_name[SLAVE_DEV_NAME_MAX_LEN]={0}; char buf[PTY_BUFF_MAX_LEN] = {0}; fd_set rfds; rv = openpty(&mpty, &spty, spty_name, NULL, NULL); if(-1 == rv){ perror("Failed to get a pty"); return -1; } printf("Get a pty pair, FD -- master[%d], slave[%d]n", mpty, spty); printf("Slave name is %sn", spty_name); FD_ZERO(&rfds); FD_SET(mpty, &rfds); while(1){ rv = select(mpty+1, &rfds, NULL, NULL, NULL); if(rv < 0){ perror("Failed to select"); return -1; } if(FD_ISSET(mpty, &rfds)){ n = read(mpty, buf, PTY_BUFF_MAX_LEN); if(n > 0){ // memset(buf+n, 0, PTY_BUFF_MAX_LEN-n); printf("recv [%d] bytes:[%s]n", n, buf); } else if (n == 0){ printf("Slave closedn"); break; } else { if(errno == EINTR){ continue; } perror("Failed to read the mastern"); return -1; } } } close(mpty); close(spty); return 0; }
编译及运行:
gcc pty_test.c -o pty_test -lutil -Wall $ ./pty_test Get a pty pair, FD -- master[3], slave[4] Slave name is /dev/pts/6 recv [1] bytes:[1] recv [11] bytes:[hello world]
另一终端:
$ echo -n "1" > /dev/pts/6 $ echo -n "hello world" > /dev/pts/6
每次运行上述程序,生成一个虚拟终端口(slave),由此同一主机可运行多个虚拟终端口(slave)。可通过文件/proc/sys/kernel/pty/max查询或更改伪终端数目。
$ cat /proc/sys/kernel/pty/max 4096
3.远程访问并口
通过网路远程访问并口,首先须要把并口虚拟化网路端口,然后在网路中的另外一个主机上通过Telnet等工具直接访问该网路端口linux 虚拟串口软件,或则把网路端口逆向为一个虚拟并口,从而通过minicom等工具进行访问。
socat工具可以实现上述功能。如本地(虚拟并口)/dev/pts6,主机IP:192.168.134.144,主机端口54321,对端主机虚拟并口文件tty.virt001,可通过如下步骤测试。
主机1并口转TCP端口:
sudosocattcp-l:54321,reuseaddr,forkfile:/dev/pts/6,waitlock=/var/run/ttypts.lock,clocal=1,cs8,nonblock=1,ixoff=0,ixon=0,ispeed=9600,ospeed=9600,raw,echo=0,crtscts=0
主机2将TCP端口转虚拟并口:
sudosocatpty,link=/dev/tty.virt001tcp:192.168.134.144:54321
主机2远程访问并口:
sudominicom-D/dev/tty.virt001
或
telnet192.168.134.14454321
4.虚拟终端单向收发
上述程序测试示例中因为ptm与pts在一个程序中,没有控制ptm的发送,不易于测试观察,网上有程序实现用两组虚拟终端中两个slave配对,因而基于并口的单向数据收发。
#!/usr/bin/env python3 #--coding = utf-8 -- import pty import os import select def mkpty(): master1, slave = pty.openpty() slaveName1 = os.ttyname(slave) master2, slave = pty.openpty() slaveName2 = os.ttyname(slave) print ('nslave device names: ', slaveName1, slaveName2) return master1, master2 if __name__ == "__main__": master1, master2 = mkpty() while True: rl, wl, el = select.select([master1, master2], [], [], 1) for master in rl: data = os.read(master, 128) print ("read %d data:" %len(data)) if master == master1: os.write(master2, data) else : os.write(master1, data)
上述程序用python实现了两个虚拟终端slave单向收发。
两个主机都可通过minicom单向收发数据。
测试中惟一不足是接收端对换行不能正确处理,可以回车但不能换行,可能与minicom设置有关,编程处理应当无问题。
据悉注意到python程序是一个一个字符处理的,并没有依照换行符整行发送,不能正确换行可能也与python程序有关。
5.常见的虚拟并口问题
1.linux下怎样生成虚拟并口?
linux中有虚拟终端的概念即ptylinux修改文件名,pty是成对的逻辑终端设备(有两个终端组成,支持单向收发)linux驱动下载,linux系统调用原生支持生成虚拟终端。
无论是实体并口,还是虚拟并口,表现方式都是并口,在linux下都是通过termios访问设置的。Ubuntu下cutecom图形界面并口调试工具可以生成并测试虚拟并口。
windows下vspd软件(VirtualSerialPortDriver)可以生成并测试虚拟并口。
2.并口的远程访问?
实体并口或虚拟并口(虚拟终端)要想实现远程访问,须要将并口数据转换到网路端口,远程通过网路实现远程访问并口。常用的工具ncat、socat都可以实现此功能。
3.3G或4G无线模块如何实现的多并口访问?
测试3G或4G模块时见到模块虚拟出多个并口,这是怎样实现的呢?这种并口本身就是在模块内部的虚拟并口,通过USB载体表现下来。
此和上述的网路访问虚拟并口不同,这儿的虚拟并口的访问利用USB合同,要求模块实现USB合同来表征模块本身实现的插口(多个虚拟并口)。
当主机访问3G或4G模块时,通过USB总线枚举来找到模块实现的并口功能;而3G或4G模块内部,多并口可能是虚拟并口,也可能是实体并口(芯片),但须要实现USB合同。
参考:
Linux终端简介与pty编程并口虚拟化:通过网路访问并口Linux下的虚拟终端(可用于在本机上模拟并口进行调试)Ubuntu下使用虚拟并口进行开发测试linux下并口转TCP/IP的终端服务器实现通过nc实现