多端口网络应用

时间:2012-10-29 21:44:11

标签: python sockets networking process

我想创建一个可以在多个端口上运行的python网络应用程序(例如:TCP:1234,TCP:5678等)。

所以我可以说n个套接字,每个套接字都监听客户端连接。我编写了一个简单的网络应用程序来监听一系列端口,但是当我运行应用程序时,它会在第一个套接字进程的监听阶段停滞不前!

如何在运行时生成单个python程序以侦听N个端口,每个端口等待客户端连接到它。所有套接字都在同时运行和监听。

Socket/Process #1: Listening on TCP Port 5000
Socket/Process #2: Listening on TCP Port 5001
Socket/Process #3: Listening on TCP Port 5002
...
Socket/Process #N: Listening on TCP Port 6000

欣赏任何想法。

#!/usr/bin/env  python

import socket

def getPortList():
    ports=[]
    nPort=int(raw_input("# how many ports you want? "))
    j = 0
    for i in range(0,nPort):
        ports.append(int(raw_input("Enter port number: ")))
        j+=1
    return ports

def myTCPSocket(port=5000):
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR,1)
    s.bind(("", int(port)))
    print ("\nWaiting for connections!\n")
    s.listen(5)
    (clientsock, clientaddr) = s.accept()
    print(clientaddr)

    data = "start"

    while len(data):
                clientsock.send("\nWelcome to Echo Server\n")
                data = clientsock.recv(1024)
                print ("Data sent is: ", data)
                clientsock.send(data)
                if data == "exit\r\n":
                        clientsock.close()

plst = getPortList()

for item in plst:
    myTCPSocket(item)

1 个答案:

答案 0 :(得分:2)

在多个套接字上进行侦听与在单个套接字上进行侦听没有什么不同。

您已经需要以某种方式处理侦听器套接字和所有客户端连接套接字。您可以通过以下方式执行此操作:

  • 围绕select.select(或pollkqueueepoll等创建循环。)
  • 使用标准库反应器asyncore
  • 使用第三方反应堆或类似Twisted的反应器。
  • 使用特定于操作系统的功能(例如,通过PyObjC使用Cocoa runloop和服务器)。
  • 为每个新连接创建一个线程。
  • 为每个新连接创建子进程。

几乎所有这些方案都可以用于处理多个侦听器。最简单的方法是将两者合并为一个(例如,一个select循环,它处理所有的侦听器及其所有客户端套接字,或者为每个侦听器和客户端套接字分别使用一个线程。) p>

出于性能或调试原因,您可能希望改为使用双层混合方法(例如,每个侦听器的一个线程,每个侦听器的所有客户端套接字都有一个select循环,或者一个进程每个侦听器,每个都有一个用于每个客户端套接字的线程)。但如果你没有任何理由这样做,就不要增加复杂性。

http://pastebin.com/QebZMKz3显示了一个简单的单select实现。这是输出:

$ ./multiserve.py 22222 22223 &
(('127.0.0.1', 22222), ' listening')
(('127.0.0.1', 22223), ' listening')
$ echo 'abc' | nc localhost 22222
(('127.0.0.1', 22222), ' <- ', ('127.0.0.1', 64633))
(('127.0.0.1', 64633), ' <- ', 'abc\n')
(('127.0.0.1', 64633), ' EOF')

如果您认为自己永远不需要同时处理两个客户......那么,您可能错了,但是......您可以使用上述大部分技术,而且可能会稍微简单一些。例如,您可以选择侦听器,然后在返回循环之前同步执行accept和client-socket通信。或者,您可以为每个侦听器创建进程或线程,但在每个侦听器中同步处理accept和client-socket通信。等等。

http://pastebin.com/wLVLT49i显示了一个简单的示例,似乎是您尝试做的事情。由于它为每个套接字使用一个进程(通过os.fork),它允许在不同端口上同时连接;因为它不会在每个进程内异步执行任何操作,所以它不允许同时连接到同一个端口。 (当然它是特定于POSIX的,因为它使用fork。)

如果您想首先学习如何编写异步网络服务器,我建议您执行两种不同的实现:select和线程。它们在概念上是基础的,而且相对容易编码。

首先,对于select,您必须了解事件循环的想法 - 事件是每个新的传入连接,现有连接上的每个传入网络数据包,即使每次都是管道写作取消畅通。这里的棘手问题是,与任何事件循环一样,您需要处理每个事件并在不阻塞的情况下返回,并且不需要花费太多CPU时间。例如,对于echo服务器,您不能只对其他套接字执行写操作,因为其中一些可能很忙。所以相反,你必须将输出粘贴在每个套接字的写缓冲区中,并且当它们准备就绪时,它们将在以后的某个事件循环中运行它。

同时,对于线程,每个连接的一个单独的线程似乎使一切变得微不足道,但是当你需要将消息从一个线程回显到另一个线程时会发生什么?您需要某种形式的线程间通信,或者需要具有线程间同步的共享数据。因此,您可能在每个套接字上都有Queue的写入,因此任何其他套接字的线程都可以将消息推送到队列中。

这些都不如转化良好的反应堆或反应器能做的那么好,但它值得学习基础知识 - 特别是因为你将面临阻塞问题(来自select )和任何解决方案的通信问题(来自线程),当你在更高层次上工作时,它们会变得更加神秘和难以调试。