我和我的同学正在用Python编写服务器/客户端模型用于学校项目。所有服务器脚本都接受从客户端(在本地主机上运行)建立的连接,并接收将它们打印到终端窗口的消息。该脚本是在运行OSX10.7.3 64位的Macbook Air上编写的,并且可以在这台计算机上运行,但是当我在同学的Linux计算机(Ubuntu 11.04 64位)或我们的计算机实验室Linux计算机(Ubuntu 10.04 32位)上运行时,它的运行方式有些不同。在脚本中,服务器和客户端都被设置为非阻塞,并且这在我的Mac上正常工作,但是在Linux机器上它们起阻止作用,不允许从客户端nr2发送任何数据,在从客户nr1收到任何之前。
Python不应该是多平台语言吗?如果没有,那么调整代码的最佳方法是什么,使其在MacOS和Ubuntu上都能正常工作?
如果这有点模糊,我很抱歉,但我从下面的服务器和客户端脚本发布我的代码。
Btw,我的Mac运行Python 2.7.1,Ubuntu 11.04运行Python 2.7.1+,Ubuntu 10.04运行Python 2.6.5。由于我们都是套接字编程的新手并且是Python的初学者(因此学校项目和简单的代码=)),如果有人能够以简单的方式详细说明,我们将非常感激。
首先是server.py文件:
import select
import socket
import sys
import threading
import client
class Server:
def __init__(self):
self.host = 'localhost'
self.port = 50000
self.backlog = 5
self.size = 1024
self.server = None
self.threads = []
def openSocket(self):
try:
self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.server.bind((self.host, self.port))
self.server.listen(5)
print "Listening to port " + str(self.port) + "..."
except socket.error, (value,message):
if self.server:
self.server.close()
print "Could not open socket: " + message
sys.exit(1)
def run(self):
self.openSocket()
self.server.setblocking(0)
input = [self.server,sys.stdin]
running = True
while running:
inputready, outputready, exceptready = select.select(input,[],[], 0.01)
for s in inputready:
c = client.Client(self.server.accept())
self.threads.append(c)
print "Client " + str(c.address) + " connected"
inputready.pop()
for c in self.threads:
try:
data = c.client.recv(self.size)
print data
except socket.error, (value,message):
continue
#close threads
self.server.close()
for c in self.threads:
c.join()
if __name__ == "__main__":
s = Server()
s.run()
然后是client.py文件:
import select
import socket
import sys
import server
import threading
class Client(threading.Thread):
def __init__(self,(client,address)):
threading.Thread.__init__(self)
self.client = client
self.address = address
self.size = 1024
def run(self):
self.client.connect(('localhost',50000))
c.client.setblocking(0)
running = True
while running:
line = sys.stdin.readline()
if line == "exit":
self.client.close()
else:
self.client.sendall(line)
self.client.close()
if __name__ == "__main__":
c = Client((socket.socket(socket.AF_INET, socket.SOCK_STREAM),'localhost'))
c.run()
PS:没关系某些循环上的缩进。当我复制粘贴我的代码时发生了一些事情。 PPS:请注意,在任一计算机上运行此消息时,我们都不会收到任何错误消息。它的行为方式不同。
提前致谢
答案 0 :(得分:1)
不可否认,我对非阻塞套接字没有经验,所以我无法真正帮助它。但是,您描述的行为似乎正是您的代码所做的 - 服务器接受连接请求,创建新的Client对象,将其附加到列表 - 然后逐个侦听同一列表中的所有客户端。这意味着第一个客户端能够连接和发送消息,但下一个客户端无法连接,因为服务器正在从第一个客户端接收数据。
此外,永远不会达到此代码:
self.server.close()
for c in self.threads:
c.join()
因为服务器永远不会停止接受请求。更重要的是,你似乎没有启动线程,你只是创建它们。
无论如何,如果您像这样修改服务器的运行功能,它应该可以工作:
from threading import Thread #this line is at the top of the file, of course
def run(self):
self.openSocket()
self.running = True #make sure to implement some code that'll actually set this variable to False!
while self.running:
c= client.Client(self.server.accept())
t= Thread(target=self.listenToClient,args=[c])
t.daemon= True #this makes sure to kill the thread when the main thread exits
self.threads.append(t)
t.start()
#close threads
self.server.close()
for c in self.threads:
c.join()
def listenToClient(self, c):
print "Client " + str(c.address) + " connected"
while self.running:
try:
data = c.client.recv(self.size)
if data=='': #if the client disconnected
return
print data
except socket.error, (value,message):
continue
要么我完全错了,要么我不知道为什么你的代码在Mac OSX上工作。
P.S:确保不要使用Python 3.这需要一些怪癖。