2011-01-09 4 views
6

Je travaille sur un peu d'un projet en python. J'ai un client et un serveur. Le serveur écoute les connexions et une fois la connexion reçue, il attend l'entrée du client. L'idée est que le client peut se connecter au serveur et exécuter des commandes système telles que ls et cat. Ceci est mon code serveur:Question client/serveur Python

import sys, os, socket 


host = ''     
port = 50105 

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
s.bind((host, port)) 
print("Server started on port: ", port) 

s.listen(5) 
print("Server listening\n") 
conn, addr = s.accept() 
print 'New connection from ', addr 
while (1): 
    rc = conn.recv(5) 
    pipe = os.popen(rc) 
    rl = pipe.readlines() 
    file = conn.makefile('w', 0) 
    file.writelines(rl[:-1]) 
    file.close() 
    conn.close() 

Et voici mon code client:

import sys, socket 
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
host = 'localhost' 
port = input('Port: ') 
s.connect((host, port)) 
cmd = raw_input('$ ') 
s.send(cmd) 
file = s.makefile('r', 0) 
sys.stdout.writelines(file.readlines()) 

Quand je démarre le serveur je reçois la sortie à droite, estimant que le serveur est à l'écoute. Mais quand je me connecte avec mon client et tapez une commande des sorties de serveur avec cette erreur:

Traceback (most recent call last): 
File "server.py", line 21, in <module> 
    rc = conn.recv(2) 
File "/usr/lib/python2.6/socket.py", line 165, in _dummy 
    raise error(EBADF, 'Bad file descriptor') 
socket.error: [Errno 9] Bad file descriptor 

Du côté client, je reçois la sortie de ls, mais le serveur obtient foiré.

+1

Alors, quelle est exactement votre question? –

+0

Comment puis-je faire en sorte que le client reste ouvert pour plus de commandes à entrer. Alors que le client peut continuer à entrer des commandes et qu'elles sont exécutées sur le serveur. – AustinM

+1

Vous semblez réinventer ssh, pourquoi? – nosklo

Répondre

6

Votre code appelle conn.close(), puis revient à conn.recv(), mais conn est déjà fermé.

+0

J'ai pris conn.close() du serveur et maintenant quand Je tape une commande dans le client il bloque juste. Rien ne se passe. – AustinM

+0

Dans ce cas, votre 'file.readlines()' dans le client attend le serveur pour envoyer quelque chose de plus (car il pourrait). Vous devrez décider - voulez-vous que votre serveur accepte une commande, puis fermez la connexion, ou voulez-vous que le serveur envoie quelque chose qui indique que la sortie de la commande est terminée? Si ce dernier, que voudriez-vous envoyer? –

+0

Eh bien, je veux que le serveur envoie quelque chose qui indique que la sortie de la commande est terminée. L'idée est que le serveur reste à l'écoute des connexions et que le client peut entrer une commande, en obtenir la sortie, puis entrer plus de commandes si l'utilisateur le souhaite. – AustinM

3

Si vous voulez que votre client de répéter ce qu'il fait, il suffit d'ajouter une boucle là-dedans;)

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
host = 'localhost' 
port = input('Port: ') 
s.connect((host, port)) 
while True: 
    cmd = raw_input('$ ') 
    s.send(cmd) 
    file = s.makefile('r', 0) 
    sys.stdout.writelines(file.readlines()) 

devrait probablement être plus proche de ce que vous voulez.

Autres commentaires:

s.listen(1) 

Cette déclaration devrait probablement être déplacée hors de la boucle while. Vous avez seulement besoin d'appeler listen une fois.

pipe = os.popen(rc) 

os.popen a été dépréciée, utilisez le subprocess module à la place.

file = s.makefile('r', 0) 

Vous ouvrez un fichier, mais vous ne fermez le fichier. Vous devriez probablement ajouter un file.close() après votre appel sys.stdout.writelines().

EDIT: pour répondre ci-dessous commentaire; fait ici en raison de la longueur et du formatage

En l'état, vous lisez une fois le socket, puis vous le fermez immédiatement. Ainsi, lorsque le client envoie la commande suivante, il voit que le serveur a fermé le socket et signale une erreur.

La solution est de changer votre code serveur afin qu'il puisse gérer la réception de plusieurs commandes. Notez que ceci est résolu en introduisant une autre boucle.

Vous devez envelopper

rc = conn.recv(2) 
pipe = os.popen(rc) 
rl = pipe.readlines() 
fl = conn.makefile('w', 0) 
fl.writelines(rl[:-1]) 

dans une autre boucle while True: afin qu'il répète jusqu'à ce que le client se déconnecte, puis enveloppez que dans un essai, sauf le bloc qui attire l'IOError qui est jeté par conn.recv () lorsque le client se déconnecte.

l'essai, sauf le bloc devrait ressembler à

try: 
    # the described above loop goes here 
except IOError: 
    conn.close() 
# execution continues on... 
+0

Eh bien, la boucle fonctionne très bien qu'une fois qu'une commande est entrée, elle est exécutée sur la machine du serveur, je reçois la sortie sur mon ordinateur client et ensuite je reçois le $ 'invite à nouveau. La chose est, après cela quand je tape une autre commande rien ne se passe. Ensuite, si j'essaie une autre commande, j'obtiens une erreur socket.error: [Errno 32] Broken pipe – AustinM

+0

Hm intéressant. Maintenant, le client se bloque et je ne reçois pas la sortie de la commande tant que le serveur n'est pas fermé. – AustinM

+0

Changer 'fl = conn.makefile ('w', 0)' en 'fl = conn.makefile ('w')' l'a corrigé pour moi. Définir le deuxième argument, qui est une taille de tampon, à 0 semble ne pas fonctionner aussi bien. –