使用 Ngrok 时 Python TCP 套接字返回 getaddrinfo 失败
Posted
技术标签:
【中文标题】使用 Ngrok 时 Python TCP 套接字返回 getaddrinfo 失败【英文标题】:Python TCP socket returns getaddrinfo failed when using Ngrok 【发布时间】:2020-09-02 05:14:38 【问题描述】:我正在尝试使用 Ngrok 使用 socket
模块连接两个 python 脚本。我试过用 ngrok.exe 和 pyngrok 来做这件事。尝试使用port
作为12345
或80
与客户端连接(其他一切都超时)。
在客户端 s.connect((ip, port))
上没有错误,但 Python server.py 和 ngrok 终端没有注册任何东西。当我将 URL 放入网络浏览器时,该 URL 确实有效,因为 Ngrok 注册了 502 bad gateway
。
我认为这是因为套接字没有使用 HTTP,而是使用 TCP,但是当我使用 TCP 标志 (ngrok.exe TCP 12345
) 启动 Ngrok 时,转发地址看起来像 tcp://0.tcp.ngrok.io:xxxxx
,当我将它放入客户端时 @ 987654330@ 它返回socket.gaierror: [Errno 11001] getaddrinfo failed
所以我想我的问题是,如何让 Python 客户端套接字接受这个地址,还是我应该做一些不同的事情?
谢谢
server.py
from pyngrok import ngrok
import socket
port = 12345
s = socket.socket()
s.bind(('', port))
public_url = ngrok.connect(port)
print("ngrok tunnel \"\" -> \"http://127.0.0.1:/\"".format(public_url, port))
s.listen(5)
print("socket is listening" )
c, addr = s.accept()
print('Got connection from', addr )
c.send(str.encode(str("Yes")))
while True:
c.recv(1024).decode("utf-8")
client.py
import socket
s = socket.socket()
url = "copied from server or ngrok"
ip = socket.gethostbyname(url)
port = 12345
s.connect((ip, 12345))
【问题讨论】:
gethostbyname 需要一个 hostname 而不是某个 URL。这是well documented。您需要使用的名称是 URL 中的域部分,然后您需要使用 URL 中的端口进行连接。 只是一个友好的提醒,请点击对帮助您的福利社区成员的答案的复选标记。 【参考方案1】:我是pyngrok
的开发者,我看到你正在使用它。文档中其实有一个TCP socket/client集成的例子,可以在here找到。
但你在正确的轨道上。简而言之,您没有指定协议,这意味着正在使用默认协议 (http
)。您需要告诉pyngrok
和ngrok
您要设置tcp
隧道。所以改为这样做:
ngrok_tunnel = ngrok.connect(port, "tcp", remote_addr=":".format(host, port))
print("ngrok tunnel \"\" -> \"tcp://127.0.0.1:/\"".format(ngrok_tunnel.public_url, port))
对于host
和port
,您需要首先设置一个ngrok
子域(您可以这样做here),类似于host="1.tcp.ngrok.io"
。然后你也将相同的主机/帖子传递给你的client.py
(你做错的地方包括协议tcp://
,不要管它)。
【讨论】:
【参考方案2】:另一个使用 ngrok 的安全 Python 套接字示例。 您可以在设计代码时忽略 ngrok,然后在测试后注入 pyngrok 依赖项(几行)。
ssl_client.py
# -*- coding: latin-1 -*-
from OpenSSL import SSL
import sys, os, select, socket
def verify_cb(conn, cert, errnum, depth, ok):
# This obviously has to be updated
print ('Got certificate: %s' % cert.get_subject())
return ok
if len(sys.argv) < 3:
print ('Usage: python[2] client.py HOST PORT')
sys.exit(1)
dir = os.path.dirname(sys.argv[0])
if dir == '':
dir = os.curdir
# Initialize context
ctx = SSL.Context(SSL.SSLv23_METHOD)
ctx.set_verify(SSL.VERIFY_PEER, verify_cb) # Demand a certificate
ctx.use_privatekey_file (os.path.join(dir, 'simple','client.pkey'))
ctx.use_certificate_file(os.path.join(dir, 'simple','client.cert'))
ctx.load_verify_locations(os.path.join(dir, 'simple','CA.cert'))
# Set up client
sock = SSL.Connection(ctx, socket.socket(socket.AF_INET, socket.SOCK_STREAM))
sock.connect((sys.argv[1], int(sys.argv[2])))
while 1:
line = sys.stdin.readline()
if line == '':
break
try:
sock.send(line.encode())
except SSL.Error:
raise
print ('Connection died unexpectedly')
break
sock.shutdown()
sock.close()
ssl_server.py
from OpenSSL import SSL
import sys, os, select, socket
def verify_cb(conn, cert, errnum, depth, ok):
# This obviously has to be updated
print ('Got certificate: %s' % cert.get_subject())
return ok
if len(sys.argv) < 2:
print ('Usage: python[2] server.py PORT')
sys.exit(1)
dir = os.path.dirname(sys.argv[0])
if dir == '':
dir = os.curdir
# Initialize context
ctx = SSL.Context(SSL.SSLv23_METHOD)
ctx.set_options(SSL.OP_NO_SSLv2)
ctx.set_verify(SSL.VERIFY_PEER|SSL.VERIFY_FAIL_IF_NO_PEER_CERT, verify_cb) # Demand a certificate
ctx.use_privatekey_file (os.path.join(dir, 'simple', 'server.pkey'))
ctx.use_certificate_file(os.path.join(dir, 'simple', 'server.cert'))
ctx.load_verify_locations(os.path.join(dir, 'simple', 'CA.cert'))
# Set up server
server = SSL.Connection(ctx, socket.socket(socket.AF_INET, socket.SOCK_STREAM))
server.bind(('', int(sys.argv[1])))
server.listen(3)
server.setblocking(0)
clients =
writers =
def dropClient(cli, errors=None):
if errors:
print ('Client %s left unexpectedly:' % (clients[cli],))
print (' ', errors)
else:
print ('Client %s left politely' % (clients[cli],))
del clients[cli]
if cli in writers:
del writers[cli]
if not errors:
cli.shutdown()
cli.close()
from pyngrok import ngrok
port=6063 #make a param
public_url = ngrok.connect(port, "tcp").public_url
print(f"ngrok tunnel 'public_url' -> 'tcp://127.0.0.1:port'")
while 1:
try:
r,w,_ = select.select([server]+list(clients.keys()), writers.keys(), [])
except:
raise
for cli in r:
if cli == server:
cli,addr = server.accept()
print ('Connection from %s' % (addr,))
clients[cli] = addr
else:
try:
ret = cli.recv(1024)
print(555, ret)
except (SSL.WantReadError, SSL.WantWriteError, SSL.WantX509LookupError):
pass
except SSL.ZeroReturnError:
raise
dropClient(cli)
except SSL.Error as errors:
raise
dropClient(cli, errors)
else:
if not cli in writers:
writers[cli] = b''
writers[cli] = writers[cli] + ret
if 0:
for cli in w:
try:
ret = cli.send(writers[cli])
except (SSL.WantReadError, SSL.WantWriteError, SSL.WantX509LookupError):
pass
except SSL.ZeroReturnError:
print(111)
raise
dropClient(cli)
except SSL.Error as errors:
raise
dropClient(cli, errors)
else:
writers[cli] = writers[cli][ret:]
if writers[cli] == '':
del writers[cli]
for cli in clients.keys():
cli.close()
server.close()
第 59 行的 URL 更改
详情在这里:secure-python-socket-using-ngrok
【讨论】:
以上是关于使用 Ngrok 时 Python TCP 套接字返回 getaddrinfo 失败的主要内容,如果未能解决你的问题,请参考以下文章