views:

3316

answers:

9

I'm currently writing a telnet server in Python. It's a content server. People would connect to the server via telnet, and be presented with text-only content.

My problem is that the server would obviously need to support more than one simultaneous connection. The current implementation I have now supports only one.

This is the basic, proof-of-concept server I began with (while the program has changed greatly over time, the basic telnet framework hasn't):

import socket, os

class Server:
    def __init__(self):
     self.host, self.port = 'localhost', 50000
     self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
     self.socket.bind((self.host, self.port))

    def send(self, msg):
     if type(msg) == str: self.conn.send(msg + end)
     elif type(msg) == list or tuple: self.conn.send('\n'.join(msg) + end)

    def recv(self):
     self.conn.recv(4096).strip()

    def exit(self):
     self.send('Disconnecting you...'); self.conn.close(); self.run()
     # closing a connection, opening a new one

    # main runtime
    def run(self):
     self.socket.listen(1)
     self.conn, self.addr = self.socket.accept()
     # there would be more activity here
     # i.e.: sending things to the connection we just made


S = Server()
S.run()

Thanks for your help.

+2  A: 

If you're up for a bit of a conceptual challenge, I'd look into using twisted.

Your case should be trivial to implement as a part of twisted. http://twistedmatrix.com/projects/core/documentation/howto/servers.html

Trey Stout
+1: twisted is the way to go. Implementing a simple telnet server should be really easy.
nosklo
+3  A: 

You need some form of asynchronous socket IO. Have a look at this explanation, which discusses the concept in low-level socket terms, and the related examples which are implemented in Python. That should point you in the right direction.

Brian Agnew
Interesting article - Thanks! +1
Jon Cage
+1: asynchronous networking is what you need. Thanks for the article.
nosklo
+2  A: 

For a really easy win implement you solution using SocketServer & the SocketServer.ThreadingMixIn

have a look a this echo server example it looks quite similar to what you're doing anyway: http://www.oreillynet.com/onlamp/blog/2007/12/pymotw_socketserver.html

Ravi
-1: SocketServer uses a thread per connection which is a really bad approach.
nosklo
Yes you are correct, I once made an xmlrpc server which excel talked to via vba functions that called the xmlrpc service. It worked well until somebody filled a formula down around 1000 rows at which point the defined function that called my xmlrpc service 1000 times, creating 1000 threads. Not fun. The twisted approach is certainly the way to go.
Ravi
+5  A: 

Implemented in twisted:

from twisted.internet.protocol import Factory, Protocol
from twisted.internet import reactor

class SendContent(Protocol):
    def connectionMade(self):
        self.transport.write(self.factory.text)
        self.transport.loseConnection()

class SendContentFactory(Factory):
    protocol = SendContent
    def __init__(self, text=None):
        if text is None:
            text = """Hello, how are you my friend? Feeling fine? Good!"""
        self.text = text

reactor.listenTCP(50000, SendContentFactory())
reactor.run()

Testing:

$ telnet localhost 50000
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Hello, how are you my friend? Feeling fine? Good!
Connection closed by foreign host.

Seriously, when it comes to asynchronous network, twisted is the way to go. It handles multiple connections in a single-thread single-process approach.

nosklo
This is perfect. Could you give an example of sending and recieving data from the client? I'm reading up on Twisted but it's quite verbose in it's tutorials.
SpleenTea
@SpleenTea: Just add an dataReceived method on the protocol and data will go to it. If your protocol is line-based you may want to subclass twisted.protocols.basic.LineReceiver instead of Protocol, so you can just define lineReceived and it'll be called for each line you get from the client. To send just use self.transport.write as I did in the example above. http://twistedmatrix.com/projects/core/documentation/howto/ is very useful, specially the tutorials.
nosklo
A: 

If you want to do it in pure python (sans-twisted), you need to do some threading. If you havnt seen it before, check out: http://heather.cs.ucdavis.edu/~matloff/Python/PyThreads.pdf

around page 5/6 is an example that is very relevant ;)

Alex
-1: article is a general article about threads. Examples have nothing to do with sockets. Implementing a good socket server with threads is tricky, has lots of details and is hard to debug, and you get no benefit. There's no reason to not go asynchronous.
nosklo
Bottom of p.5 (srvr.py) is a server that uses the socket interface to bind to a port and listen for connections. You're right. It has nothing to do with the current discussion of sockets. My bad.
Alex
A: 

First, buy Comer's books on TCP/IP programming.

In those books, Comer will provide several alternative algorithms for servers. There are two standard approaches.

  • Thread-per-request.

  • Process-per-request.

You must pick one of these two and implement that.

In thread-per, each telnet session is a separate thread in your overall application.

In process-per, you fork each telnet session into a separate subprocess.

You'll find that process-per-request is much, much easier to handle in Python, and it generally makes more efficient use of your system.

Thread-per-request is fine for things that come and go quickly (like HTTP requests). Telnet has long-running sessions where the startup cost for a subprocess does not dominate performance.

S.Lott
A: 

Thank you all very much. I've decided to implement it in SocketServer, and it's working seamlessly.

SpleenTea
A: 

How to resolve this problem?

I have this error in my consol

Traceback (most recent call last): File "G:/Programmes File/Python/honeypot/serviceTelnet.py", line 1, in from twisted.internet.protocol import Factory, Protocol ImportError: No module named twisted.internet.protocol

love2010
A: 

Late for the reply, but with the only answers being Twisted or threads (ouch), I wanted to add an answer for MiniBoa.

http://code.google.com/p/miniboa/

Twisted is great, but it's a rather large beast that may not be the best introduction to single-threaded asynchronous Telnet programming. MiniBoa is a lightweight, asynchronous single-threaded Python Telnet implementation originally designed for muds, which suits the OP's question perfectly.

georgek