Python 如何使服务器接受来自多个端口的连接?

Python 如何使服务器接受来自多个端口的连接?,python,network-programming,Python,Network Programming,我如何使一个简单的服务器(简单到接受连接并打印到终端,无论接收到什么)接受来自多个端口或端口范围的连接 我是否必须使用多个线程,每个绑定调用一个线程。还是有其他解决办法 简单服务器可以是这样的 def server(): import sys, os, socket port = 11116 host = '' backlog = 5 # Number of clients on wait. buf_size = 1024 try: listening_socket = socket

我如何使一个简单的服务器(简单到接受连接并打印到终端,无论接收到什么)接受来自多个端口或端口范围的连接

我是否必须使用多个线程,每个绑定调用一个线程。还是有其他解决办法

简单服务器可以是这样的

def server():
import sys, os, socket

port = 11116
host = ''
backlog = 5 # Number of clients on wait.
buf_size = 1024

try:
    listening_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    listening_socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) 
    listening_socket.bind((host, port)) 
    listening_socket.listen(backlog)
except socket.error, (value, message):
    if listening_socket:
        listening_socket.close()
    print 'Could not open socket: ' + message
    sys.exit(1)

while True:
    accepted_socket, adress = listening_socket.accept()

    data = accepted_socket.recv(buf_size)
    if data:
        accepted_socket.send('Hello, and goodbye.')
    accepted_socket.close()

server()
编辑: 这是如何做到这一点的一个例子。谢谢大家

import socket, select

def server():
import sys, os, socket

port_wan = 11111
port_mob = 11112
port_sat = 11113

sock_lst = []
host = ''
backlog = 5 # Number of clients on wait.
buf_size = 1024

try:
    for item in port_wan, port_mob, port_sat:
        sock_lst.append(socket.socket(socket.AF_INET, socket.SOCK_STREAM))
        sock_lst[-1].setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) 
        sock_lst[-1].bind((host, item)) 
        sock_lst[-1].listen(backlog)
except socket.error, (value, message):
    if sock_lst[-1]:
        sock_lst[-1].close()
        sock_lst = sock_lst[:-1]
    print 'Could not open socket: ' + message
    sys.exit(1)

while True:
    read, write, error = select.select(sock_lst,[],[])

    for r in read:
        for item in sock_lst:
            if r == item:
                accepted_socket, adress = item.accept()

                print 'We have a connection with ', adress
                data = accepted_socket.recv(buf_size)
                if data:
                    print data
                    accepted_socket.send('Hello, and goodbye.')
                accepted_socket.close()

server()

我不是python爱好者,但您感兴趣的函数是“select”。这将允许您监视多个套接字,并在其中任何一个套接字上发生活动时中断


这里有一个。

如果你真的想偷懒(从程序员的角度来看,而不是从评估的角度来看),你可以在阻塞读取上设置一个超时,然后循环所有套接字;如果发生超时,则没有任何可用数据。在功能上,这类似于
select
所做的工作,但它将控制权从操作系统中移除,并将其放入应用程序中

当然,这意味着随着睡眠时间的缩短,您的程序将接近100%的CPU使用率,因此您不会在生产应用程序上使用它。不过做个玩具也不错

它会是这样的:(未经测试)


由于Python的开销太大,多线程应用程序是一个争论的焦点。还有整个封锁行动的GIL问题。幸运的是,Python的格言“如果它看起来是一个大问题,那么可能已经有人提出了一个(或几个!)”在这里是正确的。我最喜欢的解决方案是微线程模型

Gevent是一个事件驱动的单线程并发库,通过monkey补丁为您即时处理大多数问题
gevent.monkey.patch_socket()
是一个函数,它使用非阻塞变量、轮询和休眠来替换普通套接字调用,以允许根据需要切换到其他Greenlet。如果您想要更多的控制权,或者它没有为您削减控制权,您可以使用select和
gevent
的合作收益率轻松管理切换

这里有一个简单的例子

import gevent
import socket
import gevent.monkey; gevent.monkey.patch_socket()

ALL_PORTS=[i for i in xrange(1024, 2048)]
MY_ADDRESS = "127.0.0.1"    

def init_server_sock(port):
    try: 
        s=socket.socket()
        s.setblocking(0)
        s.bind((MY_ADDRESS, port))
        s.listen(5)
        return s
    except Exception, e:
        print "Exception creating socket at port %i: %s" % (port, str(e))
        return False

def interact(port, sock):
    while 1:
        try:
            csock, addr = sock.accept()
        except:
            continue
        data = ""
        while not data:
            try:
                data=csock.recv(1024)
                print data
            except:
                gevent.sleep(0) #this is the cooperative yield
        csock.send("Port %i got your message!" % port)
        csock.close()
        gevent.sleep(0)


def main():
   socks = {p:init_server_sock(p) for p in ALL_PORTS}
   greenlets = []
   for k,v in socks.items():
       if not v:
           socks.pop(k)
       else:
           greenlets.append(gevent.spawn(interact, k, v))

   #now we've got our sockets, let's start accepting
   gevent.joinall(greenlets)
这将是一个超级简单、完全未经测试的服务器,提供纯文本
,我们收到了您的消息。参与选择有点困难;你必须有一个叫select的manager greenlet,然后启动活动的manager greenlet;但这并不难实现


希望这有帮助!我记得,基于greenlet的理念中很好的一部分是select调用实际上是其hub模块的一部分,这将允许您更轻松地创建一个更具可伸缩性和更复杂的服务器。它也相当有效;有两个基准浮动。

我是Python专家,您需要选择:为什么要实现您自己的选择?内置的select模块不是比这个简单吗?谢谢。我猜,因为select使用的CPU更少。我选择了那个解决方案。我隐约记得它并不简单。但现在我再仔细考虑一下,我很有可能是在C语言中工作,而不是在Python中工作,当时我正在做:(
import gevent
import socket
import gevent.monkey; gevent.monkey.patch_socket()

ALL_PORTS=[i for i in xrange(1024, 2048)]
MY_ADDRESS = "127.0.0.1"    

def init_server_sock(port):
    try: 
        s=socket.socket()
        s.setblocking(0)
        s.bind((MY_ADDRESS, port))
        s.listen(5)
        return s
    except Exception, e:
        print "Exception creating socket at port %i: %s" % (port, str(e))
        return False

def interact(port, sock):
    while 1:
        try:
            csock, addr = sock.accept()
        except:
            continue
        data = ""
        while not data:
            try:
                data=csock.recv(1024)
                print data
            except:
                gevent.sleep(0) #this is the cooperative yield
        csock.send("Port %i got your message!" % port)
        csock.close()
        gevent.sleep(0)


def main():
   socks = {p:init_server_sock(p) for p in ALL_PORTS}
   greenlets = []
   for k,v in socks.items():
       if not v:
           socks.pop(k)
       else:
           greenlets.append(gevent.spawn(interact, k, v))

   #now we've got our sockets, let's start accepting
   gevent.joinall(greenlets)