2011-01-09 21 views
6

Pracuję nad projektem w Pythonie. Mam klienta i serwer. Serwer nasłuchuje połączeń i po otrzymaniu połączenia oczekuje na dane od klienta. Idea polega na tym, że klient może łączyć się z serwerem i wykonywać polecenia systemowe, takie jak ls i cat. To jest mój kod serwera:Pytanie klienta/serwera Pythona

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

I to jest mój kod klienta:

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

Kiedy uruchomić serwer I Get Right wyjście, mówiąc serwer nasłuchuje. Ale kiedy połączyć z moim klientem i wpisz komendę wyjścia serwera z tego błędu:

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 

Po stronie klienta, mam wyjście ls ale serwer dostaje wkręca się.

+1

Czym właściwie jest Twoje pytanie? –

+0

Jak mogę to zrobić, aby klient pozostał otwarty dla kolejnych poleceń do wprowadzenia. Aby klient mógł kontynuować wprowadzanie poleceń i były wykonywane na serwerze. – AustinM

+1

Wygląda na to, że odnawiasz ssh, dlaczego? – nosklo

Odpowiedz

6

Twój kod wywołuje conn.close(), a następnie wraca do numeru conn.recv(), ale conn jest już zamknięty.

+0

Wyjąłem conn.close() z serwera i teraz, gdy Piszę polecenie w kliencie, po prostu się zawiesza. Nic się nie dzieje. – AustinM

+0

W takim przypadku twoje 'plik.readlines()' w kliencie czeka na serwer, aby wysłać coś więcej (ponieważ może). Musisz zdecydować - czy chcesz, aby serwer zaakceptował jedno polecenie, a następnie zamknął połączenie, czy też chcesz, aby serwer wysłał coś, co wskazuje, że dane wyjściowe polecenia zostały zakończone? Jeśli to drugie, co chciałbyś wysłać? –

+0

Chcę, aby serwer wysłał coś, co wskazuje, że dane wyjściowe polecenia zostały zakończone. Pomysł polega na tym, że serwer nadal nasłuchuje połączeń, a klient może wprowadzić polecenie, pobrać jego wynik, a następnie wprowadzić więcej poleceń, jeśli użytkownik tego chce. – AustinM

3

Jeśli chcesz, aby Twój klient powtórzyć to, co robi, po prostu dodaj pętlę tam;)

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

prawdopodobnie powinien być bliżej do tego, co chcesz.

Inne uwagi:

s.listen(1) 

Oświadczenie to powinno chyba być przemieszczane poza pętli while. Wystarczy raz zadzwonić pod numer listen.

pipe = os.popen(rc) 

Os.popen został przestarzały, użyj zamiast niego subprocess module.

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

Otwierasz plik, ale nigdy nie zamykasz pliku. Powinieneś prawdopodobnie dodać numer file.close() po rozmowie sys.stdout.writelines().

EDYCJA:, aby odpowiedzieć poniżej komentarza; zrobione tutaj ze względu na długość i formatowanie

W tej formie czytasz raz z gniazda, a następnie natychmiast go zamykaj. Tak więc, gdy klient idzie wysłać następne polecenie, widzi, że serwer zamknął gniazdo i wskazuje błąd.

Rozwiązaniem jest zmiana kodu serwera, aby mógł obsłużyć odbieranie wielu poleceń. Zauważ, że jest to rozwiązane przez wprowadzenie kolejnej pętli.

Trzeba owinąć

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

w innym while True: pętli tak, że powtarza się aż rozłączy klienta, a następnie owinąć że w próbie z wyjątkiem bloku, który łapie IOError, który jest wyrzucany przez conn.recv (), gdy klient się rozłączy.

try-z wyjątkiem bloku powinna wyglądać

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

Cóż, pętla działa świetnie, gdy raz wprowadzono polecenie, jest ono wykonywane na komputerze serwera, otrzymuję dane wyjściowe na komputerze klienta, a następnie otrzymuję " Monit $ 'ponownie. Chodzi o to, że po wpisaniu innego polecenia nic się nie dzieje. Następnie, jeśli spróbuję innego polecenia, pojawia się błąd socket.error: [Errno 32] Uszkodzona rura – AustinM

+0

Hm interesujące. Teraz klient po prostu zawiesza się i nie otrzymuję danych wyjściowych polecenia, dopóki serwer nie zostanie zamknięty. – AustinM

+0

Zmiana 'fl = conn.makefile ('w', 0)' na 'fl = conn.makefile ('w')' naprawiono dla mnie. Ustawienie drugiego argumentu, który jest rozmiarem bufora, na 0 wydawało się nie działać tak dobrze. –