2009-04-22 14 views
16

Attualmente sto scrivendo un server telnet in Python. È un server di contenuti. Le persone si collegano al server tramite telnet e si presentano con contenuti di solo testo.Più connessioni di rete simultanee - server Telnet, Python

Il mio problema è che il server dovrebbe ovviamente supportare più di una connessione simultanea. L'attuale implementazione che ora supporta solo uno.

Questa è la, proof-of-concept di base del server ho iniziato con (mentre il programma è molto cambiata nel corso del tempo, il quadro telnet di base non è):

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

Grazie per il vostro aiuto.

risposta

4

È necessaria una qualche forma di IO socket asincrono. Dai un'occhiata allo this explanation, che discute il concetto in termini di socket di basso livello e gli esempi correlati implementati in Python. Questo dovrebbe indirizzarti nella giusta direzione.

3

per una vittoria davvero facile si implementare soluzione utilizzando SocketServer & il SocketServer.ThreadingMixIn

hanno un aspetto un server di questo esempio di eco sembra abbastanza simile a quello che stai facendo in ogni caso: http://www.oreillynet.com/onlamp/blog/2007/12/pymotw_socketserver.html

+1

-1: SocketServer utilizza un thread per connessione che rappresenta un approccio davvero negativo. – nosklo

+0

Sì, sei corretto, ho creato un server xmlrpc che ha parlato con le funzioni vba che hanno chiamato il servizio xmlrpc. Ha funzionato bene fino a quando qualcuno non ha riempito una formula di circa 1000 righe, a quel punto la funzione definita che ha chiamato il mio servizio xmlrpc 1000 volte, creando 1000 thread. Non è divertente. L'approccio contorto è sicuramente la strada da percorrere. – Ravi

16

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

Seriamente, quando si tratta di una rete asincrona, è la strada giusta. Gestisce più connessioni in un approccio a processo singolo a thread singolo.

+1

Questo è perfetto. Potresti dare un esempio di invio e ricezione di dati dal client? Sto leggendo su Twisted ma è piuttosto dettagliato nei suoi tutorial. – SpleenTea

+1

@SpleenTea: basta aggiungere un metodo dataReceived sul protocollo e i dati andranno a esso. Se il tuo protocollo è basato sulla linea, potresti voler eseguire la sottoclasse di twisted.protocols.basic.LineReceiver anziché di Protocollo, quindi puoi semplicemente definire lineReceived e verrà chiamato per ogni riga ricevuta dal client. Per inviare basta usare self.transport.write come ho fatto nell'esempio sopra. http://twistedmatrix.com/projects/core/documentation/howto/ è molto utile, specialmente le esercitazioni. – nosklo

1

Se si desidera eseguirlo in puro python (sans-twisted), è necessario eseguire alcune operazioni di threading. Se si havnt visto prima, check out: http://heather.cs.ucdavis.edu/~matloff/Python/PyThreads.pdf

intorno pagina 5/6 è un esempio che è molto rilevante;)

+0

-1: articolo è un articolo generale sui thread. Gli esempi non hanno nulla a che fare con i socket. Implementare un buon server socket con i thread è complicato, ha molti dettagli ed è difficile da eseguire il debug e non si ottiene alcun beneficio. Non c'è motivo di non andare in asincrono. – nosklo

+1

Il lato inferiore di p.5 (srvr.py) è un server che utilizza l'interfaccia socket per collegarsi a una porta e ascoltare le connessioni. Hai ragione. Non ha nulla a che fare con l'attuale discussione delle prese. Colpa mia. – Alex

1

prima cosa, comprare i libri di Comer su TCP/IP programming.

In questi libri, Comer fornirà diversi algoritmi alternativi per i server. Ci sono due approcci standard.

  • Thread-per-richiesta.

  • Processo per richiesta.

È necessario selezionare uno di questi due e implementarlo.

In thread-per, ogni sessione telnet è un thread separato nell'applicazione complessiva.

In process-per, si esegue il fork di ciascuna sessione telnet in un sottoprocesso separato.

Troverete che process-per-request è molto, molto più facile da gestire in Python e generalmente rende più efficiente l'uso del vostro sistema.

Thread-per-request va bene per le cose che vanno e vengono velocemente (come le richieste HTTP). Telnet ha sessioni di lunga durata in cui il costo di avvio per un sottoprocesso non domina le prestazioni.

+0

-1: Sia Thread-per-request che processo-per-request non possono scalare a un numero di richieste simultanee. – nosklo

+2

@nosklo: "un numero" Nulla può scalare su alcuni numeri perché sono così grandi. Thread per richiesta è spesso considerato abbastanza scalabile. Avete delle specifiche su quali sono le alternative? –

+0

non collegare il modello di concorrenza a ciascuna richiesta. Invece, eseguire un numero di processi/thread indipendente dal numero di richieste. Gestire molte richieste nello stesso processo/thread, preferibilmente usando un IO asincrono. Che scala in modo migliore. – nosklo

4

In ritardo per la risposta, ma con le sole risposte Twisted o threads (ouch), volevo aggiungere una risposta per MiniBoa.

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

torta è grande, ma è piuttosto grande bestia che potrebbe non essere la migliore introduzione alla programmazione singolo thread Telnet asincrono. MiniBoa è un'implementazione Python Telnet asincrona e single-threaded, originariamente progettata per i fanghi, che si adatta perfettamente alla domanda dell'OP.

1

Prova il server MiniBoa? Ha esattamente 0 dipendenze, nessuna roba o altre cose necessarie. MiniBoa è un server telnet asincrono non bloccante, singolo thread, esattamente ciò di cui hai bisogno.

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

1

Usa filettatura e poi aggiungere il gestore in una funzione. Il filo chiamerà ogni volta che una richiesta che ho fatto:

Guardate questa

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