如何通过互联网(非本地)使用 Python 3 套接字 client/server 设置?

How to use a Python 3 socket client/server setup over the internet (not locally)?

我正在尝试实现一个简单的聊天程序,该程序使用套接字通过 UDP 连接传输数据。但是,我不知道如何正确设置它,以便在我将它托管在我的笔记本电脑上时,来自本地网络之外的人可以访问它。我正在使用端口 5000,并在我的笔记本电脑的路由器上转发了该端口。端口转发似乎不是问题;至少 portforward.com 中的 "Port Forward Network Utilities" 似乎检测到它已正确转发。也许我混淆了我需要托管和连接的 IP 地址?有问题的代码如下:

import socket
import threading
import sys


class Server:
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    connections = []

    def __init__(self):
        self.sock.bind(('192.168.1.5', 5000))
        self.sock.listen(1)

    def handler(self, c, a):
        while True:
            data = c.recv(1024)
            for connection in self.connections:
                print(data.decode())
                connection.send(data)
            if not data:
                break

    def run(self):
        while True:
            c, a = self.sock.accept()
            cThread = threading.Thread(target=self.handler, args=(c, a))
            cThread.daemon = True
            cThread.start()
            self.connections.append(c)
            print(self.connections)


class Client:
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    usr_name = ""

    def sendMsg(self):
        while True:
            self.sock.send(bytes(self.usr_name + ": " + input("-> "), 'utf-8'))

    def __init__(self, address):
        self.sock.connect((address, 5000))
        self.usr_name = input("Enter a username: ")
        iThread = threading.Thread(target=self.sendMsg)
        iThread.daemon = True
        iThread.start()

        while True:
            data = self.sock.recv(1024)
            if not data:
                break
            print(data.decode())


if len(sys.argv) > 1:
    client = Client(sys.argv[1])
else:
    server = Server()
    server.run()

如您所见,我输入了我当前的本地 IP 地址用于托管服务器,而客户端要求一个 IP 来连接。我不确定现在该怎么做才能通过 Internet 托管它,但我已经尝试了我能想到的所有 IP 组合,但 returns 出现了一些错误。

提前致谢。

编辑: 我遇到的两个主要错误是:

很抱歉,我无法更详细地说明我的错误并提供完整的打印输出,如果我能够复制它们,我会尝试更新它。

编辑: 我能够重写它并让它工作,我不再需要这方面的帮助。 谢谢。

您正在将 UDP 端口 5000 端口转发到 5000。

但是您打开的是 TCP 流,而不是 UDP。这就是 SOCK_STREAM 的意思。如果你想要UDP,你需要使用SOCK_DGRAM.

所以,你需要让这两个保持一致。唯一的问题是,我不确定你在这里真正想要哪一个。

一方面,您的代码是面向连接的recv,并且似乎假定可靠传输,这意味着您可能需要 TCP。

另一方面,您的代码似乎假设每个 recv(1024) 都将从另一端恰好得到一个 send,这仅适用于 UDP; TCP sockets are byte streams, not message streams。当您执行 recv(1024) 时,您可以轻松地获取 80 字节行的前 12 个字节,这意味着它可以在 UTF-8 字符的中间结束,这意味着 decode 将抛出一个例外。

我想你想要 TCP,但在它之上有一个成帧协议。在这里可能有意义的最简单的协议是文本行。这对你自己来说很容易做到,但使用 socket.makefile 更容易做到,因为你要为每个连接指定一个线程。