我有一个侦听端口的python套接字服务器,并使用以下命令接受所有传入连接:
(conn, address) = socket.accept()
但是,我希望只接受来自某个IP地址的连接。
目前,如果未注册地址,我会关闭连接,以实现此目的。
但有没有更好的方法来做到这一点,直接拒绝来自未注册地址的连接,而不是接受连接然后关闭它们?
答案 0 :(得分:5)
无法从某些IP地址向客户端指示 Connection refused ,并建立与其他IP地址的客户端的连接。这不是Python限制,而是较低级别的BSD套接字层限制。你甚至不能用C做到这一点。
您在Python中可以做的最接近的行为是在接受连接后快速关闭连接:
sock, addr = server_socket.accept()
if addr[0] != '12.34.56.78':
sock.close()
return
...
然后客户端会看到连接被接受,不久之后客户端会在读取时看到EOF,并且无法写入。
但是,可以通过使用以下方法之一在 bind 时间通过接口(即网卡)进行限制:
server_socket.bind(('', 65432)) # Bind on any interface.
server_socket.bind(('127.0.0.1', 65432)) # Bind on loopback (localhost clients only).
server_socket.bind(('34.56.78.91', 65432))
因此,在 127.0.0.1 版本中,telnet 127.0.0.1 65432
(作为客户端)可以正常工作,但telnet myhostname 65432
会产生拒绝连接(和server_socket.accept()
调用无法获得此连接。)
答案 1 :(得分:0)
如果您阅读docs,可以找到告诉您的BaseServer.verify_request(request, client_address)
:
必须返回一个布尔值;如果值为True,则处理请求,如果为False,则拒绝请求。可以重写此函数以实现服务器的访问控制。默认实现始终返回True。
答案 2 :(得分:0)
Microsoft似乎通过SO_CONDITIONAL_ACCEPT socket option
支持此功能这似乎需要使用WSAAccept to accept connections
这个常量不出现在我的Windows 8机器上的pythons套接字模块中。我不认为可以通过python的内置套接字模块使用WSAAccept。
如果我理解正确,这将允许您的服务器在配置为使用RST数据包时立即响应SYN数据包,而不是完成握手和交换FIN数据包。请注意,使用此标志会删除处理来自操作系统的连接并将其放在应用程序上的责任,因此存在大量错误和性能命中的空间。如果提升性能是目标,那么可能不值得追求
可以在Windows上的C级别进行。 Pythons ctypes模块允许与C代码接口,因此技术上可以通过python接口完成。但它可能需要一些非常小的努力。如果您确定需要此功能,那么找到支持此功能的C套接字库可能会花费更少的精力,然后您可以为此创建一个ctypes包装。