pastie.org/1447201

отаю над небольшим проектом на Python. У меня есть клиент и сервер. Сервер прослушивает соединения, и как только соединение получено, он ожидает ввода от клиента. Идея состоит в том, что клиент может подключиться к серверу и выполнить системные команды, такие как ls и cat. Это мой код сервера:

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

И это мой код клиента:

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

Когда я запускаю сервер, я получаю правильный вывод, говоря, что сервер слушает. Но когда я соединяюсь со своим клиентом и набираю команду, сервер выходит с этой ошибкой:

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

На стороне клиента я получаю вывод ls, но сервер облажается.

 AustinM10 янв. 2011 г., 01:39
Как я могу сделать так, чтобы клиент оставался открытым для ввода новых команд. Чтобы клиент мог продолжать вводить команды, и они выполняются на сервере.
 gahooa10 янв. 2011 г., 02:07
Если вы действительно хотите узнать об этом, возьмите книгу «Расширенное программирование в среде Unix», второе издание ... Она объяснитвсе вам нужно перейти на программирование клиент / сервер.
 nosklo10 янв. 2011 г., 01:41
Вы, кажется, заново изобретаете SSH, почему?
 Sven Marnach10 янв. 2011 г., 01:34
Так в чем именно твой вопрос?
 AustinM10 янв. 2011 г., 01:42
На самом деле это не переизобретение SSH, это просто базовая серверная клиентская программа, где клиент может удаленно выполнять команды. Не на уровне безопасности, который обеспечивает SSH. Просто. Вроде как телнет.

Ответы на вопрос(2)

Решение Вопроса

conn.close() а затем возвращается кconn.recv(), ноconn уже закрыт.

 Greg Hewgill10 янв. 2011 г., 00:06
В качестве третьего варианта вы могли бы иметьсервер сгенерировать подсказку, когда закончите выполнение команды. Тогда клиент становится очень простым и просто передает символы назад и вперед. На самом деле, в этот момент вы на пути к переизобретениютелнет.
 AustinM10 янв. 2011 г., 00:02
Я хочу, чтобы сервер отправил что-то, что указывает на завершение вывода команды. Идея состоит в том, что сервер продолжает прислушиваться к соединениям, и клиент может ввести команду, получить ее вывод, а затем ввести больше команд, если пользователь пожелает.
 Greg Hewgill09 янв. 2011 г., 23:59
В этом случае вашfile.readlines() в клиенте ждет, когда сервер отправит что-то большее (потому что это может). Вам нужно решить - хотите ли вы, чтобы ваш сервер принял одну команду и затем закрыл соединение, или вы хотите, чтобы сервер отправил что-то, что указывает на завершение вывода команды? Если последнее, что бы вы хотели отправить?
 Greg Hewgill10 янв. 2011 г., 00:05
Есть две альтернативы - серверМожно продолжайте прослушивать новые соединения, даже если каждое отдельное соединение закрывается после выполнения команды (это похоже на то, как работает простой HTTP). Преимущество в том, что код гораздо проще. В качестве альтернативы можно установить связь между клиентом и сервером для нескольких команд, но вам нужно будет выбрать способ пометить окончание вывода команды сервера, чтобы клиент знал, когда показывать следующее приглашение. Хитрость заключается в выборе того, что не будет отображаться в самом выводе команды.
 AustinM09 янв. 2011 г., 23:55
Я взял conn.close () с сервера, и теперь, когда я набираю команду на клиенте, она просто зависает. Ничего не произошло.

чтобы ваш клиент повторил то, что он делает, просто добавьте туда цикл;)

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

Наверное, должно быть ближе к тому, что вы хотите.

Другие комментарии:

s.listen(1)

Это утверждение, вероятно, следует переместить за пределы цикла while. Вам нужно только позвонитьlisten один раз.

pipe = os.popen(rc)

os.popen устарел, используйтемодуль подпроцесса вместо.

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

Вы открываете файл, но никогда не закрываете файл. Вы, вероятно, должны добавитьfile.close() после вашегоsys.stdout.writelines() вызов.

РЕДАКТИРОВАТЬ: ответить ниже комментарием; сделано здесь из-за длины и форматирования

Когда он стоит, вы читаете из сокета один раз, а затем сразу же закрываете его. Таким образом, когда клиент отправляет следующую команду, он видит, что сервер закрыл сокет, и указывает на ошибку.

Решение состоит в том, чтобы изменить код вашего сервера, чтобы он мог обрабатывать несколько команд. Обратите внимание, что это решается введением еще одного цикла.

Вам нужно завернуть

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

в другойwhile True: Цикл, повторяющийся до тех пор, пока клиент не отключится, а затем оберните его в блок try-Кроме, который перехватывает IOError, который выдается conn.recv (), когда клиент отключается.

блок try-кроме должен выглядеть

try:
    # the described above loop goes here
except IOError:
    conn.close()
# execution continues on...
 Alex Miller11 янв. 2011 г., 00:49
измененияfl = conn.makefile('w', 0) вfl = conn.makefile('w') исправил это для меня. Установка второго аргумента, который является размером буфера, в 0, похоже, не сработает.
 Alex Miller11 янв. 2011 г., 01:06
Я также должен был добавитьif len(rc) == 0: raise IOError послеrc = conn.recv(2) потому что для меня, когда recv вызывался на сокете, который был закрыт на другом конце, он просто ничего не возвращал. яподумал что это должно вызвать IOError, но я думаю, что нет? (Если бы кто-то еще мог прыгнуть сюда и объяснить, почему, это будет оценено.)
 AustinM10 янв. 2011 г., 20:30
Хм интересно. Теперь клиент просто зависает, и я не получаю вывод команды, пока сервер не будет закрыт.
 AustinM10 янв. 2011 г., 03:21
Ну, цикл работает отлично, как только команда введена, она выполняется на сервере, я получаю вывод на своем клиентском компьютере, а затем снова получаю приглашение «$». Дело в том, что после ввода другой команды ничего не происходит. Затем, если я попробую другую команду, я получу ошибку socket.error: [Errno 32] Broken pipe
 AustinM11 янв. 2011 г., 03:56
Хорошо, я сделал все предложенное, и у меня все та же проблема -_- Он все еще зависает, пока сервер не будет закрыт. Просто чтобы убедиться, что здесь мой сервер / клиент:pastie.org/1447201

Ваш ответ на вопрос