Python中的客户端服务器编程?

10

这是一个Python多线程服务器和客户端的源代码。

在代码中,客户端和服务器会在任务完成后关闭连接。我希望保持连接并通过同一连接发送更多数据以避免每次关闭和打开套接字的开销

以下代码来自:http://www.devshed.com/c/a/Python/Basic-Threading-in-Python/1/

import pickle
import socket
import threading

# We'll pickle a list of numbers:
someList = [ 1, 2, 7, 9, 0 ]
pickledList = pickle.dumps ( someList )

# Our thread class:
class ClientThread ( threading.Thread ):

   # Override Thread's __init__ method to accept the parameters needed:
   def __init__ ( self, channel, details ):

      self.channel = channel
      self.details = details
      threading.Thread.__init__ ( self )

   def run ( self ):

      print 'Received connection:', self.details [ 0 ]
      self.channel.send ( pickledList )
      for x in xrange ( 10 ):
         print self.channel.recv ( 1024 )
      self.channel.close()
      print 'Closed connection:', self.details [ 0 ]

# Set up the server:
server = socket.socket ( socket.AF_INET, socket.SOCK_STREAM )
server.bind ( ( '', 2727 ) )
server.listen ( 5 )

# Have the server serve "forever":
while True:
   channel, details = server.accept()
   ClientThread ( channel, details ).start()

import pickle
import socket
import threading

# Here's our thread:
class ConnectionThread ( threading.Thread ):

   def run ( self ):

      # Connect to the server:
      client = socket.socket ( socket.AF_INET, socket.SOCK_STREAM )
      client.connect ( ( 'localhost', 2727 ) )

      # Retrieve and unpickle the list object:
      print pickle.loads ( client.recv ( 1024 ) )

      # Send some messages:
      for x in xrange ( 10 ):
         client.send ( 'Hey. ' + str ( x ) + '\n' )

      # Close the connection
      client.close()

# Let's spawn a few threads:
for x in xrange ( 5 ):
   ConnectionThread().start()
3个回答

20

为每个连接生成一个新线程是一个非常糟糕的设计选择。

事实上,使用线程等待网络 IO 是不值得的。你的程序会变得非常复杂,而且你根本没有任何好处,因为在线程中等待网络不会让你更快地等待。在这种情况下使用线程只会让你失去。

以下文字摘自 Python 文档:

有两种方法可以让单处理器上的程序同时运行“多个任务”。多线程编程是最简单和最流行的方法,但还有一种非常不同的技术,可以让您几乎获得多线程的所有优势,而不必实际使用多个线程。如果您的程序主要受 I/O 限制,那么这真的很实用。如果您的程序受处理器限制,则预先安排调度的线程可能是您真正需要的。然而,网络服务器很少受到处理器限制。

如果是处理器受限的服务器情况,您可以始终留下另一个进程/线程来执行处理器部分。接着说:

如果您的操作系统支持其 I/O 库中的 select 系统调用(几乎所有操作系统都支持),则可以使用它来同时处理多个通信通道;在后台进行 I/O 时执行其他工作。虽然这种策略可能看起来奇怪和复杂,尤其是在开始时,但在许多方面,它比多线程编程更容易理解和控制。

因此,不要使用线程,而要使用非阻塞的输入/输出:将套接字收集到一个列表中,并使用 select.select 的事件循环来知道哪个套接字有数据可读。在单个线程中完成此操作。

您可以选择像twisted这样的Python异步网络框架来为您完成此操作。这将为您节省大量麻烦。Twisted的代码已经改进了多年,并覆盖了一些您需要花费时间才能掌握的边角情况。

编辑:任何现有的异步IO库(如Twisted)都是Python代码。您本可以自己编写,但已经有人为您编写了。我不明白为什么你会使用自己编写的糟糕的代码,而不是使用其中一个库。因为对于初学者来说,网络IO很难做到完美无缺。


如何在不使用Twisted或任何其他库的情况下进行异步网络编程?请提供建议。 - Pratik Deoghare
2
@david:我在我的问题的第三段已经这样做了。 - nosklo
@david:如果不使用库,你什么也做不了。一切都是库。从某种角度来看,Python 本身就是一个库。你可以随时将 Twisted 代码的部分或全部复制到你的应用程序中,并假装你自己编写了它。Twisted 是纯 Python 的。 - nosklo
@david:换句话说,Twisted是你本可以自己编写的代码。只不过它已经为你编写好了。我不明白为什么你不使用它(或任何其他异步IO库),而要编写自己的最糟糕的代码。 - nosklo
1
@nosklo:感谢您的建议,但是没有任何非常简单的例子来了解Python中异步网络是如何工作的吗? - Pratik Deoghare
龙卷风是什么? - wrivas

3

我不确定我理解这个问题,但如果您不想关闭连接,请不要调用close()...


(注:该段内容为关于it技术的建议)

0

如果想要了解一个保持TCP连接并使用熟悉协议的客户端的示例,请查看源代码中的telnetlib模块。(抱歉,其他人将不得不回答您的线程问题。)

保持TCP连接的服务器示例可以在SocketServer模块的源代码中找到(任何标准的Python安装都包括源代码)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接