服务器/客户端脚本在MacOSX上顺利运行,但在Ubuntu中失败

时间:2012-02-21 18:40:02

标签: python linux macos sockets

我和我的同学正在用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:请注意,在任一计算机上运行此消息时,我们都不会收到任何错误消息。它的行为方式不同。

提前致谢

1 个答案:

答案 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.这需要一些怪癖。