Python如何使用套接字传输文件?编写服务器和客户端 Python 脚本,使用 Python 中的套接字模块在网络中接收和发送文件。
文件传输是通过网络或 Internet 连接将文件从一台计算机复制或移动到另一台计算机的过程。在本教程中,我们将逐步介绍如何编写处理该问题的客户端/服务器 Python 脚本。
基本思想是创建一个监听特定端口的服务器,这个服务器将负责接收文件(你可以让服务器也发送文件)。另一方面,客户端将尝试连接到服务器并发送任何类型的文件。
Python如何在网络中传输文件?我们将使用Python 内置的socket模块,它为我们提供了在 Internet 上广泛使用的 socket 操作,因为它们支持与任何网络的任何连接。
相关: 如何在 Python 中发送电子邮件。
首先,我们需要安装tqdm库,这将使我们能够打印精美的进度条:
pip3 install tqdm
客户端代码
Python如何使用套接字传输文件?让我们从客户端开始,发送者:
import socket
import tqdm
import os
SEPARATOR = "<SEPARATOR>"
BUFFER_SIZE = 4096 # send 4096 bytes each time step
Python套接字传输文件示例 - 我们需要指定要连接的服务器的 IP 地址和端口,以及要发送的文件的名称。
# the ip address or hostname of the server, the receiver
host = "192.168.1.101"
# the port, let's use 5001
port = 5001
# the name of file we want to send, make sure it exists
filename = "data.csv"
# get the file size
filesize = os.path.getsize(filename)
该文件名必须在当前目录中存在,或者你也可以使用绝对路径到你的计算机上文件的某处。这是你要发送的文件。
os.path.getsize(filename)以字节为单位获取该文件的大小,这很好,因为我们需要它来在客户端和服务器中打印进度条。
Python如何在网络中传输文件?让我们创建 TCP 套接字:
# create the client socket
s = socket.socket()
连接到服务器:
print(f"[+] Connecting to {host}:{port}")
s.connect((host, port))
print("[+] Connected.")
connect()方法需要一对(主机、端口)的地址来将套接字连接到该远程地址。建立连接后,我们需要发送文件的名称和大小:
# send the filename and filesize
s.send(f"{filename}{SEPARATOR}{filesize}".encode())
我在这里使用SEPARATOR只是为了分隔数据字段,它只是一个垃圾消息,我们可以使用send()两次,但我们可能不想这样做。encode()函数对我们传递给'utf-8'编码的字符串进行编码(这是必要的)。
现在我们需要发送文件,在发送文件时,我们将使用tqdm库打印漂亮的进度条:
# start sending the file
progress = tqdm.tqdm(range(filesize), f"Sending {filename}", unit="B", unit_scale=True, unit_divisor=1024)
with open(filename, "rb") as f:
while True:
# read the bytes from the file
bytes_read = f.read(BUFFER_SIZE)
if not bytes_read:
# file transmitting is done
break
# we use sendall to assure transimission in
# busy networks
s.sendall(bytes_read)
# update the progress bar
progress.update(len(bytes_read))
# close the socket
s.close()
基本上我们在这里做的是打开以二进制读取的文件,从文件中读取块(在本例中为4096字节或4KB)并使用sendall()函数将它们发送到套接字,然后我们更新进度条每次,一旦完成,我们关闭该套接字。
相关: 如何在 Python 中制作聊天应用程序。
Python套接字传输文件示例:服务器代码
好的,我们已经完成了与客户的沟通。让我们深入研究服务器,打开一个新的空 Python 文件,然后:
import socket
import tqdm
import os
# device's IP address
SERVER_HOST = "0.0.0.0"
SERVER_PORT = 5001
# receive 4096 bytes each time
BUFFER_SIZE = 4096
SEPARATOR = "<SEPARATOR>"
我已经初始化了一些我们要使用的参数,注意我已经使用“0.0.0.0”作为服务器 IP 地址,这意味着本地机器上的所有 IPv4 地址。你可能想知道,为什么我们不只使用我们的本地 IP 地址或“localhost”或“127.0.0.1”?好吧,如果服务器有两个 IP 地址,让我们说一个网络上的“192.168.1.101”,另一个网络上的“10.0.1.1”,并且服务器侦听“0.0.0.0”,那么这两个 IP 都可以访问.
或者,你可以使用公共或私有 IP 地址,具体取决于你的客户端。如果连接的客户端在你的本地网络中,你应该使用你的私有 IP(你可以使用ipconfig
Windows 中的ifconfig
命令或Mac OS/Linux 中的命令来检查它),但如果你期望来自 Internet 的客户端,你绝对应该使用你的公共地址。
另外,请确保你在服务器中使用与客户端相同的端口。
Python如何使用套接字传输文件?让我们创建我们的 TCP 套接字:
# create the server socket
# TCP socket
s = socket.socket()
现在这与客户端不同,我们需要将刚刚创建的套接字绑定到我们的SERVER_HOST和SERVER_PORT:
# bind the socket to our local address
s.bind((SERVER_HOST, SERVER_PORT))
之后,我们将监听连接:
# enabling our server to accept connections
# 5 here is the number of unaccepted connections that
# the system will allow before refusing new connections
s.listen(5)
print(f"[*] Listening as {SERVER_HOST}:{SERVER_PORT}")
一旦客户端连接到我们的服务器,我们需要接受该连接:
# accept connection if there is any
client_socket, address = s.accept()
# if below code is executed, that means the sender is connected
print(f"[+] {address} is connected.")
请记住,当客户端连接时,它会发送文件的名称和大小,让我们接收它们:
# receive the file infos
# receive using client socket, not server socket
received = client_socket.recv(BUFFER_SIZE).decode()
filename, filesize = received.split(SEPARATOR)
# remove absolute path if there is
filename = os.path.basename(filename)
# convert to integer
filesize = int(filesize)
如前所述,接收到的数据与文件名和文件大小相结合,我们可以通过SEPARATOR字符串拆分它们来轻松提取它们。
之后,我们需要删除文件的绝对路径,这是因为发送者发送的文件是他自己的文件路径,可能与我们的不同,os.path.basename()函数返回路径名的最后一部分.
Python套接字传输文件示例 - 现在我们需要接收文件:
# start receiving the file from the socket
# and writing to the file stream
progress = tqdm.tqdm(range(filesize), f"Receiving {filename}", unit="B", unit_scale=True, unit_divisor=1024)
with open(filename, "wb") as f:
while True:
# read 1024 bytes from the socket (receive)
bytes_read = client_socket.recv(BUFFER_SIZE)
if not bytes_read:
# nothing is received
# file transmitting is done
break
# write to the file the bytes we just received
f.write(bytes_read)
# update the progress bar
progress.update(len(bytes_read))
# close the client socket
client_socket.close()
# close the server socket
s.close()
Python如何使用套接字传输文件?与客户端代码没有太大区别。但是,我们在此处以二进制写入方式打开文件,并使用recv(BUFFER_SIZE)方法从客户端套接字接收BUFFER_SIZE字节并将其写入文件。完成后,我们关闭客户端和服务器套接字。
还学习: 如何使用 Python 列出 FTP 服务器中的所有文件和目录
好吧,让我在我自己的私人网络上试一试:
C:\> python receiver.py
[*] Listening as 0.0.0.0:5001
我需要转到我的 Linux 机器并发送一个示例文件:
root@rockikz:~/tools# python3 sender.py
[+] Connecting to 192.168.1.101:5001
[+] Connected.
Sending data.npy: 9%|███████▊ | 45.5M/487M [00:14<02:01, 3.80MB/s]
现在让我们看看服务器:
[+] ('192.168.1.101', 47618) is connected.
Receiving data.npy: 33%|███████████████████▍ | 160M/487M [01:04<04:15, 1.34MB/s]
太好了,我们完成了!
Python如何在网络中传输文件?你现在可以根据自己的需要扩展此代码,以下是你可以实现的一些示例:
- 使服务器能够使用线程同时从多个客户端接收多个文件。
- 在发送之前压缩文件,这可能有助于增加传输持续时间。
- 在发送文件之前对其进行加密,以确保没有人能够拦截和读取该文件,本教程将有所帮助。
- 通过检查两个文件(发送方的原始文件和接收方的发送文件)的校验和,确保文件正确发送。在这种情况下,你需要安全的散列算法来做到这一点。
- 添加聊天室,以便你可以聊天和传输文件。