select blocked?

Donn Cave donn at u.washington.edu
Mon Nov 20 13:29:41 EST 2000


Quoth kafa6226 at my-deja.com:

| 	I am a newbie to python and try to write a middle layer
| between the telnet and rxvt to provide some special analyse function. I
| use the select module to listen on the stdin and pty-master-end which
| connected with the telnet. but the select statement seems blocked when
| the string passed from telnet not ended with a NewLine character. I
| have searched the archive but chould not find the answer, can you give
| me a help? thanks!

The UNIX terminal driver is a line oriented device, it holds on to
your input line so that it can process backspaces and things like
that.  If you want your program to see input immediately and directly,
you can turn this feature off, with the POSIX terminal control functions.
Afterwards, put it back the way it was!

Your program is appended, modified to do this.  For more information on
the tty control bits, check your man pages.  On my host that's
"man 4 termios", but the location varies from one platform to another.

	Donn Cave, donn at u.washington.edu
----------------------------------------
#!/usr/bin/env python
import sys
import os
import pty
import select
import termios
import TERMIOS

def main():

	(pid, fd) = pty.fork()
	# Python won't return -1, rather will raise exception.
	if pid == 0:	# child process
		try:
			os.execvp('telnet', ('telnet','localhost',))
		except:
			# must not return to caller.
			os._exit(0)

	# parent process

        iflag, oflag, cflag, lflag, ispeed, ospeed, cc = termios.tcgetattr(0)
	lflag = lflag
        raw_lflag = lflag & ~(TERMIOS.ICANON|TERMIOS.ECHO)
	raw_iflag = iflag & ~(TERMIOS.ICRNL)
	raw_cc = cc[:]
        raw_cc[TERMIOS.VMIN] = 1
        raw_cc[TERMIOS.VTIME] = 0
        termios.tcsetattr(0, TERMIOS.TCSANOW, [raw_iflag, oflag, cflag,
		raw_lflag, ispeed, ospeed, raw_cc])
	try:
 		while 1:
			delay = 1
			from_user = ''
        		(r,w,e) = select.select([0, fd], [], [], delay)
			for File in r:
				if File == 0:
					from_user = os.read(0, 1024)
					# print 'user input:', repr(from_user)
					os.write(fd, from_user)

				if File == fd:
					from_telnet = os.read(fd, 1024)
					os.write(1, from_telnet)
			if from_user == 'q':
				break
	except:
		termios.tcsetattr(0, TERMIOS.TCSANOW, [iflag, oflag, cflag,
				lflag, ispeed, ospeed, cc])
		raise
	termios.tcsetattr(0, TERMIOS.TCSANOW, [iflag, oflag, cflag,
			lflag, ispeed, ospeed, cc])

if __name__ == '__main__':
	main()
---------- Bonus version --------------
#!/usr/bin/env python
import sys
import os
import pty
import select
import termios
import TERMIOS

class TTY:
	def __init__(self):
		self.iflag, self.oflag, self.cflag, self.lflag, \
		self.ispeed, self.ospeed, self.cc = termios.tcgetattr(0)
	def raw(self):
        	raw_lflag = self.lflag & ~(TERMIOS.ICANON|TERMIOS.ECHO)
		raw_iflag = self.iflag & ~(TERMIOS.ICRNL)
		raw_cc = self.cc[:]
        	raw_cc[TERMIOS.VMIN] = 1
        	raw_cc[TERMIOS.VTIME] = 0
        	termios.tcsetattr(0, TERMIOS.TCSANOW, [raw_iflag, self.oflag,
			self.cflag, raw_lflag, self.ispeed, self.ospeed,
			raw_cc])
	def restore(self):
        	termios.tcsetattr(0, TERMIOS.TCSANOW, [self.iflag, self.oflag,
			self.cflag, self.lflag, self.ispeed, self.ospeed,
			self.cc])

def main():
	pid, fd = pty.fork()
	# Python won't return -1, rather will raise exception.
	if pid == 0:	# child process
		try:
			os.execvp('telnet', ('telnet','localhost',))
		except:
			# must not return to caller.
			os._exit(0)

	# parent process

	input = TTY()
	input.raw()

	try:
 		while 1:
			delay = 1
			from_user = ''
        		r, w, e = select.select([0, fd], [], [], delay)
			for File in r:
				if File == 0:
					from_user = os.read(0, 1024)
					# print 'user input:', repr(from_user)
					os.write(fd, from_user)

				if File == fd:
					from_telnet = os.read(fd, 1024)
					os.write(1, from_telnet)
			if from_user == 'q':
				break
	except:
		input.restore()
		raise
	input.restore()

if __name__ == '__main__':
	main()



More information about the Python-list mailing list