使用 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 作为1234580 与客户端连接(其他一切都超时)。

在客户端 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)。您需要告诉pyngrokngrok 您要设置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))

对于hostport,您需要首先设置一个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 失败的主要内容,如果未能解决你的问题,请参考以下文章

使用 ngrok 使用 tcp 隧道将数据发送到 tcp 端口时出错

ngrok:tcp 转发到 25565(我的世界服务器)

Python网络编程_TCP(简略版)

如何修复 ngrok 转发端口?

如何重用TCP套接字python

如何使用 ngrok 公开 React 开发服务器和 websocket 服务器