Python,同时在两个套接字上进行侦听

时间:2015-07-15 22:32:02

标签: python multithreading sockets

我正在创建一个python服务器,该服务器应该处理来自端口9090上的远程主机的连接以及仅来自端口9091上的localhost(GUI发送数据)的连接。 我认为问题出在socket.listen(backlog)中,因为这会阻止一切。 那么有一种方法可以同时运行socket1.listen(backlog)和socket2.listen(backlog)吗? 另外,创建一个用于从GUI接收数据的套接字(用Java编写)是否是一个好的,最重要的是安全的想法?

2 个答案:

答案 0 :(得分:0)

这可以在C:Listen to multiple ports from one server

中完成

和C ++:Create multiple listening sockets

所以你应该能够用Python做到这一点。

唯一能使这不安全的事情是你的服务器响应GUI而执行危险的活动,但是你可以添加代码来检查并防止攻击。

答案 1 :(得分:0)

我正在使用python2.7.3,并且正如我的评论所述,我无法重现listen阻止问题。 注意:

  • 为了简单起见,我只使用IPv4套接字
  • 我在代码中添加了Python的提示符,表明它没有阻止
  • 关于最终的安全问题:监听9091的套接字(s_local)只接受来自localhost的连接(来自其他主机的连接将失败)

这是 CentOS5 计算机的代码段:

>>> import socket
>>> s_global = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
>>> s_global.bind(("", 9090))
>>> backlog = 0xFF
>>> s_global.listen(backlog)
>>> s_local = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
>>> s_local.bind(("127.0.0.1", 9091))
>>> s_local.listen(backlog)
>>>

并且在同一台机器上有一些输出:

netstat -an | grep 909
tcp        0      0 0.0.0.0:9090                0.0.0.0:*                   LISTEN      
tcp        0      0 127.0.0.1:9091              0.0.0.0:*                   LISTEN      

如图所示,两个服务器套接字都在监听连接。

现在,如果我的环境出现问题(某些阅读显示默认情况下套接字 默认阻止),创建每个套接字后,您可以添加(如在一条评论中指明)以下行:

  • for s_global

    s_global.setblocking(0)
    
  • 用于s_local

    s_local.setblocking(0)
    

现在为了从两个套接字接收传入连接,您应该使用Python' s select module(用于异步IO)需要其他线程;您的服务器应用程序应该经常监听连接,例如:

TIMEOUT = 1 #seconds
terminate = False # variable to be modified externally to end the loop
listening_sockets = [s_global, s_local]
while (not terminate):
    notified_socket_list = select.select(listening_sockets, [], [], TIMEOUT)[0]
    for notified_socket in notified_socket_list:
        incoming_socket, addr = notified_socket.accept()
        handle(incoming_socket, addr)

注意:值得一提的是: epoll select.epoll)在性能方面比选择select.select)更受青睐,但我没有&#39我试过了。

现在,关于连接处理功能(句柄):如果您的服务器仅用于教育目的,您可以保持原样,但如果您的服务器设计为同时接受大量来自/到每个客户的连接和大量数据交换,您应该在单独的线程中处理每个连接(这是一个不适用于Python的一般建议,因为它GIL,有时线程只会降低速度)/ 进程,如同SocketServer.py - part of Python's standard library中所做的那样。

@ Edit1 - 回复第1条评论:

很简单,你所要做的就是修改一下内部 for循环:

    for notified_socket in notified_socket_list:
        incoming_socket, addr = notified_socket.accept()
        if notified_socket == s_global:
            handle_global(incoming_socket, addr)
        else:
            handle_local(incoming_socket, addr)

或者您可以使用我的原始解决方案并区分句柄中的连接:addr参数包含套接字连接到的(本地)端口;您可以测试它,并根据其值(9090或9091)以不同方式处理连接。