python 绑定 socket.error: [Errno 13] 权限被拒绝
我有一个Python脚本,它可以从远程机器获取数据包,并把这些数据包写入一个叫做gr3的tun接口,具体操作是这样的:
(os.write(self.tun_fd.fileno(), ''.join(packet)))
Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
inet addr:10.0.0.6 P-t-P:10.0.0.8 Mask:255.255.255.255
UP POINTOPOINT RUNNING NOARP MULTICAST MTU:1500 Metric:1
RX packets:61 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:500
RX bytes:5124 (5.0 KiB) TX bytes:0 (0.0 b)
我想通过一个单独的pong脚本来接收这些数据包,具体想法是这样的:
import threading, os, sys, fcntl, struct, socket
from fcntl import ioctl
from packet import Packet
HOST = '10.0.0.6'
PORT = 111
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((HOST, PORT))
s.listen(1)
conn, addr = s.accept()
print 'Connected by', addr
while 1:
data = conn.recv(1024)
if not data: break
else: print data
conn.sendall(data)
conn.close()
但是我遇到了这个错误:
s.bind((HOST, PORT))
File "<string>", line 1, in bind
socket.error: [Errno 13] Permission denied
4 个回答
你可能正在使用一个被其他服务占用的端口,或者这个端口是被保留的。你可以换一个空闲的端口号,或者换一个你知道没有被使用的端口。
给遇到同样错误的朋友们:
你的服务器可能没有以管理员权限运行。所有1024以下的端口都是系统保留的。你需要一个有管理员权限的服务器来帮忙。
在我的具体情况下,我通过设置一个反向代理,用Nginx将请求转发到我应用的高端口来解决问题。
我部署的生产服务器Waitress没有以管理员身份运行,所以无法打开系统保留的端口。于是我启动了Nginx来处理SSL加密,并通过http将所有https请求转发到应用的端口,这样就成功了。
我建议你先确认一下你想用的端口没有被其他程序占用,如果没有被占用,再确保你的服务器设置能够处理这个端口。
这是我找到的文档,经过很多次的挠头后,它清楚地解释了这个情况:
外部绑定
Waitress不应该以管理员身份运行,因为这样会让你的应用代码也以管理员身份运行,这样不安全。不过,这也意味着你无法绑定到80或443端口。相反,应该在Waitress前面使用像Nginx或Apache httpd这样的反向代理。
如果不指定--host选项,你可以绑定到所有外部IP的非特权端口。但在使用反向代理的情况下,不要这样做,否则可能会绕过代理。
0.0.0.0不是一个有效的地址,你需要在浏览器中使用一个具体的IP地址。
来源: https://flask.palletsprojects.com/en/2.2.x/deploying/waitress/
虽然这个问题里没有提到,但我想扩展一下关于本地进程间通信的 unix sockets 的内容,也就是 AF_UNIX
。在 man unix 7
中可以看到:
在Linux的实现中,路径名套接字会遵循它所在目录的权限。如果进程没有在创建套接字的目录中写入和搜索(执行)权限,那么创建新的套接字就会失败。
在Linux上,连接到一个流套接字对象需要对该套接字有写入权限;向数据报套接字发送数据报同样需要对该套接字有写入权限。POSIX并没有说明套接字文件的权限会有什么影响,在某些系统(例如旧版的BSD)中,套接字的权限会被忽略。可移植的程序不应该依赖这个特性来保证安全。
所以,如果在使用 bind()
创建unix套接字时遇到 PermissionError: [Errno 13] Permission denied
的错误,请检查一下套接字所在目录的权限。
作为普通用户,你不能绑定低于1024的端口号。
所以你可以选择:
- 使用一个大于1024的端口号(推荐)
- 或者以有特权的用户身份运行脚本
如果真的需要接受111端口的请求,虽然更复杂,但更安全的解决方案是:
- 在一个更高的端口上以普通用户身份运行,然后将111端口的请求转发到这个高端口上。