如何通过互联网而不是局域网发送文件



所以,我和我的朋友只是想尝试在python中创建我们自己的个人聊天应用程序。我首先尝试制作一个CLI应用程序,我在谷歌上搜索了一些东西,但我无法找到如何通过Internet发送文件。有很多方法可以通过局域网发送,但我和我的朋友在不同的网络上,所以这是行不通的。我似乎找不到在互联网上做这件事的方法。我是网络新手,所以如果我犯了任何错误,请原谅。这是我必须通过局域网传输文件的代码:

客户端.py

import socket
from threading import Thread
from datetime import datetime
# server's IP address
# if the server is not on this machine, 
# put the private (network) IP address (e.g 192.168.1.2)
SERVER_HOST = input("Server IP : ")
SERVER_PORT = 5002 # server's port
separator_token = "<SEP>" # we will use this to separate the client name & message
# initialize TCP socket
s = socket.socket()
print(f"[*] Connecting to {SERVER_HOST}:{SERVER_PORT}...")
# connect to the server
s.connect((SERVER_HOST, SERVER_PORT))
print("[+] Connected.")
# prompt the client for a name
name = input("Enter your name: ")
def listen_for_messages():
while True:
message = s.recv(1024).decode()
print("n" + message)
# make a thread that listens for messages to this client & print them
t = Thread(target=listen_for_messages)
# make the thread daemon so it ends whenever the main thread ends
t.daemon = True
# start the thread
t.start()
while True:
# input message we want to send to the server
to_send =  input()
# a way to exit the program
if to_send.lower() == 'q':
break
# add the datetime, name & the color of the sender
date_now = datetime.now().strftime('%Y-%m-%d %H:%M:%S') 
to_send = f"[{date_now}] {name}{separator_token}{to_send}"
# finally, send the message
s.send(to_send.encode())
# close the socket
s.close()

服务器.py

import socket
from threading import Thread
# server's IP address
SERVER_HOST = "0.0.0.0"
SERVER_PORT = 5002 # port we want to use
separator_token = "<SEP>" # we will use this to separate the client name & message
# initialize list/set of all connected client's sockets
client_sockets = set()
# create a TCP socket
s = socket.socket()
# make the port as reusable port
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# bind the socket to the address we specified
s.bind((SERVER_HOST, SERVER_PORT))
# listen for upcoming connections
s.listen(5)
print(f"[*] Listening as {SERVER_HOST}:{SERVER_PORT}")
def listen_for_client(cs):
"""
This function keep listening for a message from `cs` socket
Whenever a message is received, broadcast it to all other connected clients
"""
while True:
try:
# keep listening for a message from `cs` socket
msg = cs.recv(1024).decode()
except Exception as e:
# client no longer connected
# remove it from the set
print(f"[!] Error: {e}")
client_sockets.remove(cs)
else:
# if we received a message, replace the <SEP> 
# token with ": " for nice printing
msg = msg.replace(separator_token, ": ")
# iterate over all connected sockets
for client_socket in client_sockets:
# and send the message
client_socket.send(msg.encode())
while True:
# we keep listening for new connections all the time
client_socket, client_address = s.accept()
print(f"[+] {client_address} connected.")
# add the new connected client to connected sockets
client_sockets.add(client_socket)
# start a new thread that listens for each client's messages
t = Thread(target=listen_for_client, args=(client_socket,))
# make the thread daemon so it ends whenever the main thread ends
t.daemon = True
# start the thread
t.start()

您的代码很好。问题在于网络设置。

我想你们都有典型的设置,所以你们都支持NAT(网络地址转换(。其他聊天应用程序使用双方都可以连接的服务器。如果你输入朋友的IP地址,你会尝试打开与路由器的连接,但路由器可能不会应答。

一个破解是在你的一个路由器上设置端口转发。根据您的示例,假设5002,并将所有传入流量转发到正确的本地机器。这应该会让你跑起来,但我同意这不是一件容易的事情。一个更简单的设置是使用upnp,它会自动设置端口转发规则,但我不知道哪个包会这样做(肯定有一个(。

如果您的提供商支持,另一种方法是切换到ipv6。由于地址空间的增加,通常会向客户提供ipv6范围,这样本地机器就可以拥有公共ipv6地址,您可以使用这些地址进行连接。在这里,包应该正确路由,但防火墙可能会干扰。

另一种破解方法是完全绕过路由器,将机器直接插入上行链路连接。这取决于您的提供商和网络设置。如果你有一个路由器,它也可以作为调制解调器通过电视电缆或电话线连接,这就不起作用了。

Diclaimer:这可能不是一个真实的答案(至少不是预期的答案(,但它不适合发表评论。

幸运的是,你给出了一些关于你真正问题的背景!因为这既不是Python问题,也不是文件传输问题。它是关于如何在两个专用网络之间交换数据,每个网络都由ISP路由器进行网络地址转换保护。没有简单直接的答案,只有可能的变通办法。

事实上,正确的解决方案是,您或您的朋友在云中使用(虚拟(机并在那里安装服务器。这样,服务器就会有一个真实的地址,并且可以很容易地从任何客户端访问。它有一些缺点和陷阱,因为您现在有一个可公开访问的应用程序,并且始终处于运行状态,所以必须考虑安全性。。。

可能的解决方案取决于您的ISP路由器。有些允许将本地地址配置为DMZ,DMZ是一个可以从互联网和局域网其他部分访问的地址,但只能在某些端口上访问。背后的理由是尽可能减少攻击面:DMZ中的机器很容易受到攻击,但它不应该包含敏感数据,并且如果受到攻击,应该很容易从头开始重建。但只有当你(或你的一个朋友(可以奉献一台物理机器时,这才有意义(树莓或同等产品并不那么贵(。其他允许配置一个特殊端口,以便自动路由到内部地址。你失去了DMZ的安全优势,但不再需要奉献任何东西。

不幸的是,正如我最初所说,我没有代码修复建议,因为问题不存在,也没有任何直接的解决方案,因为解决方案确实取决于您的ISP路由器。

最新更新