Nonblocking IO?

Donn Cave donn at u.washington.edu
Tue Jul 11 13:35:36 EDT 2000


Quoth cjc26 at nospam.cornell.edu (Cliff Crawford):
| * Nolan Darilek <nolan_d at bigfoot.com> menulis:
| | 
| | The most obvious solution is to use curses, but this makes my program
| | much more complex than it needs to be. Since cmd does almost exactly
| | what I want it to do, I'd much rather change the Cmd class than add
| | curses. I've seen code written in C which does what I'd like to do
| | (Micq, for example, has the interface which I'm aiming for, yet it
| | doesn't use curses/ncurses.) So, is it somehow possible to either a)
| | make raw_input nonblocking or b) use some other nonblocking IO method?
|
| You could use the select module to wait for input from multiple file
| descriptors (for example, sys.stdin and a socket).  Also, the asyncore
| module is a higher-level interface to select, and may be useful to you
| too.
|
|
| | And, is it then possible to ensure that the output from the socket
| | isn't intermingled with the input? If I do nonblocking IO, I'm
| | assuming that it's simply a matter of printing a newline, my message,
| | and then reprinting the prompt while stuffing the existing input back
| | into the input buffer.
|
| Have you checked out the termios module?  That would be pretty much the
| only other way to do it, besides curses (which is aptly named, don't you
| think? ;)

Right, and that's really the way to get input right away after a key
press too.  I don't have the original post here, but I thought that
might have really been the question.  Since I know a useful answer
to that question, let's pretend so anyway.

When we really want "non-blocking" input, the issue is whether the
system should return from read() whether there is data or not -
normally it "blocks" until data arrives.  Hence the interest in
select(), which is all about this issue of where there's data.

With the terminal we also have the question of _how much_ data should
the system return, should it return a whole LF-terminated line or
return each single byte as it arrives.  This is a function of the
terminal device driver, and you have to use these device specific
termios ioctls to 1) turn off canonical input processing, which is
where it reads whole lines at a time and applies back-spacing edits etc.,
and 2) tell it to read one byte and not to wait for anything more.

The appended code works for me on Digital UNIX.  You may also want
to turn off echo, and print the input yourself.

As for output that happens while the user is typing input, it might
be possible to clean that up a little with some VT100 escapes.
That's difficult in a continuous scrolling model, but if the output
is presented one screen per event it might be pretty easy.

	Donn Cave, University Computing Services, University of Washington
	donn at u.washington.edu
-----------------------------
import termios
import TERMIOS
import posix

iflag, oflag, cflag, lflag, ispeed, ospeed, cc = termios.tcgetattr(0)

lflag2 = lflag & ~TERMIOS.ICANON
cc2 = cc[:]
cc2[TERMIOS.VMIN] = 1
cc2[TERMIOS.VTIME] = 0
termios.tcsetattr(0, TERMIOS.TCSADRAIN,
        [iflag, oflag, cflag, lflag2, ispeed, ospeed, cc2])

posix.write(1, 'Press key: ')
stuff = posix.read(0, 1)
print '\nstuff:', repr(stuff)

termios.tcsetattr(0, TERMIOS.TCSADRAIN,
        [iflag, oflag, cflag, lflag, ispeed, ospeed, cc])



More information about the Python-list mailing list