Hello All, I'm attempting to write a simple telnet client. Yes, I've been told that I should be using twisted to do this. I want to learn to do it myself first, so that I can fully understand the concepts - then I will scrap it and switch to using twisted.
When I started, I didn't realize there was such a thing as blocking IO. I assumed that if I put the read/write calls for stdio & the socket in different threads all would be good. I've been told that this is not the case and that if I perform a blocking IO call in a thread (such as sys.stdin.read()) it will halt the execution of all threads in the process. I found an example that uses the select module to see if any data is available from stdin before attempting to read ... and that this is the asynchronous/non-blocking way to do it. I've implemented this code, but I can't figure out a similar way to do this with the socket. Here's the code I've put together so far: #!/usr/bin/env python import collections import os import select import socket import sys import termios import tty import threading class InputThread(threading.Thread): """ Read data from the stdin and place in the input buffer. """ def __init__(self, input_buffer): threading.Thread.__init__(self) self.input_buffer = input_buffer def run(self): self.old_settings = termios.tcgetattr(sys.stdin) tty.setcbreak(sys.stdin.fileno()) # prompt loop try: while True: if select.select([sys.stdin], [], [], 0) == ([sys.stdin], [], []): self.input_buffer.append(sys.stdin.read()) print "> " finally: termios.tcsetattr(sys.stdin, termios.TCSADRAIN, self.old_settings) class DisplayThread(threading.Thread): """ Check ouput buffer for data. Print and data and flush buffer. """ def __init__(self, output_buffer): threading.Thread.__init__(self) self.output_buffer = output_buffer def run(self): while True: while len(self.output_buffer) > 0: output_data = self.output_buffer.pop() print output_data, class SocketThread(threading.Thread): """ Check input buffer. If data exists, send it to socket. Read any incoming data from socket and place it in output buffer. """ def __init__(self, input_buffer, output_buffer): threading.Thread.__init__(self) self.input_buffer = input_buffer self.output_buffer = output_buffer def run(self): self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.socket.setblocking(1) self.socket.connect(('nannymud.lysator.liu.se',2000)) while True: while len(self.input_buffer) > 0: input_data = self.input_buffer.pop() self.socket.send(input_data, '\n') self.output_buffer.append(self.socket.recv(1024)) self.sock.close() def main(): """ Interactive, multithreaded network client written in python. """ print "Use 'quit' to exit client." input_buffer = collections.deque() output_buffer = collections.deque(); input_thread = InputThread(input_buffer) input_thread.start() display_thread = DisplayThread(output_buffer) display_thread.start() socket_thread = SocketThread(input_buffer, output_buffer) socket_thread.start() if __name__ == '__main__': main() Help sorting this out so that I can fully understand the concepts and get this working would be greatly appreciated. As I mentioned previously, I am fully planning on scrapping this and rewriting it using twisted once I understand the concepts and have a working prototype. Thank you! - F4RR4R -- Science replaces private prejudice with publicly verifiable evidence. - Richard Dawkins
_______________________________________________ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: http://mail.python.org/mailman/listinfo/tutor