2009-04-22 304 views
16

我目前正在用Python寫一個telnet服務器。這是一個內容服務器。人們將通過telnet連接到服務器,並顯示純文本內容。多個同時網絡連接 - Telnet服務器,Python

我的問題是,服務器顯然需要支持多個同時連接。我現在的實現現在只支持一個。

這是我開始與基本的,證據的概念服務器(而該計劃已隨着時間的推移很大變化,基本的telnet框架還沒有):

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() 

感謝您的幫助。

回答

4

您需要某種形式的異步套接字IO。看看this explanation,它討論低層套接字術語中的概念以及在Python中實現的相關示例。這應該指向正確的方向。

3

對於一個真正輕鬆取勝使用的SocketServer &實現你的解決方案的SocketServer.ThreadingMixIn

有一個看起來它看起來非常類似於你在做什麼,反正這回聲服務器的例子:http://www.oreillynet.com/onlamp/blog/2007/12/pymotw_socketserver.html

+1

-1:SocketServer每個連接使用一個線程,這是一個非常糟糕的方法。 – nosklo 2009-04-22 12:13:59

+0

是的,你是對的,我曾經做過一個xmlrpc服務器,這個服務器通過vba函數與excel對話,這些函數調用了xmlrpc服務。它運行良好,直到有人在1000行左右填充公式,此時定義的函數調用了我的xmlrpc服務1000次,創建1000個線程。不好玩。扭曲的方法當然是要走的路。 – Ravi 2009-04-23 13:22:47

16

在實現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() 

測試:

$ 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. 

嚴重的是,當涉及到異步網絡時,扭曲就是要走的路。它使用單線程單進程方法處理多個連接。

+1

這是完美的。你能給出一個發送和接收客戶端數據的例子嗎?我正在閱讀Twisted,但它在教程中非常詳細。 – SpleenTea 2009-04-23 11:58:33

+1

@SpleenTea:只需在協議上添加一個dataReceived方法,數據就會發送到它。如果你的協議是基於行的,你可能需要繼承twisted.protocols.basic.LineReceiver而不是Protocol,所以你可以定義lineReceived,並且它會從你從客戶端獲得的每一行被調用。按照我在上面的例子中所做的那樣發送使用self.transport.write。 http://twistedmatrix.com/projects/core/documentation/howto/是非常有用的,特別是教程。 – nosklo 2009-04-24 18:30:28

1

首先,買TCP/IP programming Comer的書籍。

在這些書中,Comer將爲服務器提供幾種替代算法。有兩種標準方法。

  • Thread-per-request。

  • Process-per-request。

您必須從這兩個中選擇一個並實現它。

在thread-per中,每個telnet會話都是整個應用程序中的一個單獨線程。

在進程中,您將每個Telnet會話分成一個單獨的子進程。

你會發現process-per-request在Python中更容易處理,並且通常可以更有效地使用你的系統。

Thread-per-request適用於快速前進和後退的事情(如HTTP請求)。 Telnet具有長時間運行的會話,子流程的啓動成本不會影響性能。

4

最遲迴復,但唯一的答案是扭曲或線程(哎),我想爲MiniBoa添加一個答案。

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

Twisted是偉大的,但它是一個相當大的野獸,可能不會是單線程的異步編程的Telnet最好的介紹。 MiniBoa是最初爲泥漿設計的輕量級異步單線程Python Telnet實現,它完美地適合OP的問題。

1

試試MiniBoa服務器?它恰好有0個依賴關係,不需要扭曲或其他東西。 MiniBoa是一個非阻塞的異步遠程登錄服務器,單線程,正是你所需要的。

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

1

使用線程,然後添加到處理程序的功能。該線程將調用請求我做每一次:

看這個

import socket    # Import socket module 
import pygame 
import thread 
import threading,sys 

s = socket.socket()   # Create a socket object 
host = socket.gethostname() # Get local machine name 
port = 12345    # Reserve a port for your service. 
s.bind((host, port)) 
print ((host, port)) 
name = "" 
users = [] 

def connection_handler (c, addr): 
     print "conn handle" 
     a = c.recv (1024) 
     if a == "c": 
     b = c.recv (1024) 
     if a == "o": 
     c.send (str(users)) 
     a = c.recv (1024) 
     if a == "c": 
      b = c.recv (1024) 
     print a,b 






s.listen(6)     # Now wait for client connection. 
while True: 
    c, addr = s.accept() 
    print 'Connect atempt from:', addr[0] 
    username = c.recv(1024) 
    print "2" 
    if username == "END_SERVER_RUBBISH101": 
     if addr[0] == "192.168.1.68": 
     break 
    users.append(username) 
    thread.start_new_thread (connection_handler, (c, addr)) #New thread for connection 

print 
s.close()