Python 客户端/服务器问题

6 投票
2 回答
14722 浏览
提问于 2025-04-16 09:40

我正在用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的输出,但服务器却出现了问题。

2 个回答

3

如果你想让你的客户端重复执行某个操作,只需要在里面加一个循环就行了;)

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已经不推荐使用了,建议用subprocess模块来代替。

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

你打开了一个文件,但从来没有关闭它。你应该在sys.stdout.writelines()调用之后加上file.close()

编辑:为了回答下面的评论;由于长度和格式原因在这里处理。

目前的情况是,你只从套接字读取了一次,然后立刻关闭了它。因此,当客户端尝试发送下一个命令时,它会发现服务器关闭了套接字,从而出现错误。

解决办法是修改你的服务器代码,使其能够处理多个命令。注意,这个问题可以通过引入另一个循环来解决。

你需要把

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

放在另一个while True:循环里面,这样它就会一直重复,直到客户端断开连接,然后再把这个循环放在一个try-except块里,以捕获当客户端断开连接时conn.recv()抛出的IOError。

这个try-except块应该看起来像这样:

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

你的代码先调用了 conn.close(),然后又回到 conn.recv() 这一步,但这时候 conn 已经关闭了。

撰写回答