6

我正在使用我的 python 服务器,但我已经使用 localhost 并且我想通过互联网。到目前为止,我的代码是:

import socket
import threading
import socketserver

class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler):

    def handle(self):
        data = self.request.recv(1024)
        cur_thread = threading.current_thread()
        response = "{}: {}".format(cur_thread.name, data)
        self.request.sendall(b'worked') 

class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
    pass

def client(ip, port, message):
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.connect((ip, port))
    try:
        sock.sendall(message)
        response = sock.recv(1024)
        print("Received: {}".format(response))
    finally:
        sock.close()

if __name__ == "__main__":
    # Port 0 means to select an arbitrary unused port
    HOST, PORT = "0.0.0.0", 9001

    server = ThreadedTCPServer((HOST, PORT), ThreadedTCPRequestHandler)
    ip, port = server.server_address

    # Start a thread with the server -- that thread will then start one
    # more thread for each request
    server_thread = threading.Thread(target=server.serve_forever)
    # Exit the server thread when the main thread terminates
    server_thread.daemon = True
    server_thread.start()
    print("Server loop running in thread:", server_thread.name)
    ip = '12.34.56.789' #Not my real ip address This is just to hide my ip
    print(ip, PORT)

    client(ip, PORT, b'Hello World 1')
    #client(ip, port, b'Hello World 2')
    #client(ip, port, b'Hello World 3')

    server.shutdown()

当我运行这个我得到错误:

Server loop running in thread: Thread-1
12.34.56.789 9001
Traceback (most recent call last):
  File "C:/Python32/serverTesty.py", line 43, in <module>
    client(ip, PORT, b'Hello World 1')
  File "C:/Python32/serverTesty.py", line 18, in client
    sock.connect((ip, port))
socket.error: [Errno 10061] No connection could be made because the target machine actively refused it

我知道该端口有效,因为当我在程序运行时在端口 9001 上使用 canyouseeme.org 时,它说它处于活动状态并且正在工作。所以我想我只是在某个地方连接错误。

4

1 回答 1

27

ip = '12.34.56.789' #不是我的真实IP地址,它是我从whatismyip.org获得的

第一个问题是“12.34.56.789”根本不是有效的 IP 地址。每个组件必须适合 8 位 (0-255);789是不可能的。但我认为这不是您正在运行的实际代码,因为输出显示 12.45.29.122。

第二个问题是您使用的地址不是您的真实地址。

您的机器可能有一个内部 IP 地址,只能从您的 LAN 访问。然后,您的路由器有一个外部 IP 地址。路由器使用一种称为网络地址转换的技术,让 LAN 上的每台机器在充当客户端时假装外部地址属于它们(这就是 whatismyip.org 向您显示该地址的原因)。但是当他们充当服务器时,这不起作用。

如果你仔细想想,它真的没有办法奏效。如果您进行出站连接并且有人回复,则路由器知道回复应该发送到您的计算机。但是,如果有人突然出现并与路由器通话,它怎么会知道将连接发送到哪台机器呢?

如果您尝试从同一个 LAN 内部进行连接,有一个非常简单的解决方案:使用服务器的真实内部地址,而不是路由器的外部地址。

如果您需要从外部进行连接,则无需额外的工作就无法连接。有四种方法可以解决这个问题:

  1. 为您的机器提供一个真正的可公开寻址的 IP 地址(例如,将其放在路由器的 DMZ 上)。对于家庭用户来说,这通常不是一个选择,对于不知道自己在做什么的人来说,这是一个糟糕的选择(除非您希望您的机器在午餐时间成为某人的僵尸网络的一部分)。

  2. 在路由器的配置中设置静态端口转发。这对于每个路由器都是不同的,但想法是你告诉它“如果有人来寻找端口 9001,总是将他们发送到机器 192.168.1.64”。

  3. 使用 UPnP 动态设置端口转发。

  4. 设置 NAT 打孔。

选项 3 和 4 比较复杂,我认为选项 2 是您想要的,所以我不会解释它们。

最重要的是:

HOST, PORT = "192.168.1.64", 9001

server = ThreadedTCPServer((HOST, PORT), ThreadedTCPRequestHandler)

您已经明确告诉服务器“监听 192.168.1.64”。即使你把你的服务器机器放在 DMZ 上,所以它的地址是 192.168.1.64 和 12.45.29.122,你的程序只监听第一个上的连接,所以没有人能够使用第二个访问它。如果要监听所有地址,请使用 0.0.0.0。

在编辑后的版本中,您现在正在监听 0.0.0.0,并连接到路由器的公共 IP,并且您声称已在路由器上设置了端口转发,但您仍然遇到完全相同的错误。

如果这一切都是正确的,那么可能会出现三个明显的问题:

  1. 您实际上不是端口转发;设置有问题。
  2. 您实际上并没有在 0.0.0.0:9001 上收听。
  3. 您有防火墙阻止连接。

您可以进行一些测试来缩小范围。

  1. 打开两个终端。在一个中,键入nc -kl 9001。在另一个中,键入nc 12.34.56.78 9001。它们应该连接起来,因此您在一个窗口中输入的任何内容都会出现在另一个窗口中(可能只有在您点击 Return 后)。如果可行,则端口转发正常,并且没有防火墙问题,因此这是您的代码中的问题。

  2. 如果这不起作用,请准确发布您在每个窗口中看到的内容。然后 Ctrl-C 第二个nc,然后键入nc 192.168.1.64 9001。如果现在可行,则端口转发设置不正确,除非您有一个聪明的防火墙,允许相同主机(或相同接口)连接但不允许远程连接。

  3. 如果两者都不起作用,则可能是防火墙问题。(除非您的 IP 地址或其他信息有误。)您可能会在某处找到日志,但如果不知道您在哪个平台上以及您正在使用什么防火墙,就很难提供太多帮助。(此外,对于与 SO 不同的站点,这可能是一个问题。)

如果您使用的是 Windows 或某些 linux 发行版,则需要nc从某个地方获取 (netcat) 的副本;在大多数 linux 发行版和 Mac 上,它应该是内置的。此外,GNU、BSD 和 Hobbitnc略有不同,所以如果nc -kl 6000给你一个错误,你可能需要阅读手册页或--help. (如果我没记错的话,Hobbitnc需要-l -p6000,BSD 需要-l 6000,GNU 都允许。)

或者你可能想要ncat,一个我知道可以处理我上面使用的语法的 netcat 的重新实现,并且有一个适用于 Windows 的单文件静态可执行文件。

如果您无法开始使用nc,至少尝试更改您的代码以连接到 192.168.1.64 而不是 12.34.56.78。如果这样可以解决问题,至少您会知道它是端口转发还是允许相同主机/接口连接但不允许远程连接的防火墙。

于 2012-09-28T00:23:24.337 回答