如何通过互联网(非本地)使用 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 出现了一些错误。
提前致谢。
编辑:
我遇到的两个主要错误是:
- 超时错误 [WinError 10060]
- 我的朋友在尝试从另一个网络连接时收到此消息
- [WinError 10061]
- 我在同一台计算机上尝试使用我的 public IP 连接时会收到此消息
很抱歉,我无法更详细地说明我的错误并提供完整的打印输出,如果我能够复制它们,我会尝试更新它。
编辑:
我能够重写它并让它工作,我不再需要这方面的帮助。
谢谢。
您正在将 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
更容易做到,因为你要为每个连接指定一个线程。
我正在尝试实现一个简单的聊天程序,该程序使用套接字通过 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 出现了一些错误。
提前致谢。
编辑: 我遇到的两个主要错误是:
- 超时错误 [WinError 10060]
- 我的朋友在尝试从另一个网络连接时收到此消息
- [WinError 10061]
- 我在同一台计算机上尝试使用我的 public IP 连接时会收到此消息
很抱歉,我无法更详细地说明我的错误并提供完整的打印输出,如果我能够复制它们,我会尝试更新它。
编辑: 我能够重写它并让它工作,我不再需要这方面的帮助。 谢谢。
您正在将 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
更容易做到,因为你要为每个连接指定一个线程。