Python Socket实现两台电脑之间的文件传输
项目说明
现有系统是两台Windows 10的电脑,其中一台作为服务器,另一台作为客户端。服务器中有一个文件夹pics,里面有10张图片,如下图:
本文旨在利用Python中的Socket库将服务器中的图片传输到客户端。
实现步骤
服务器:
-
1.套接字对象类型声明和连接协议生成;
-
2.在服务器中绑定要监听的端口,开始监听;
-
3.客户端上传请求后,建立服务器到客户端的连接实例;
-
4.接收数据,获取图片名称命令,指定要传输的图片;
-
5.将图片数据按照字节数分批下载到客户端,直到传输完成。
客户:
-
1.声明协议类型,同时生成socket连接对象;
-
2.连接服务器的相关端口;
-
3.向服务器发送有关图像名称的命令;
-
4.根据字节数批量获取从服务器下载到客户端的数据,并在一个文件中共存,直到传输完成。
代码实现
这里的代码实现只是为了说明一些重要功能的作用,并不完整。完整的代码贴在文末。
服务器
1.导入所需的库
进口插座
导入我们
2.声明协议类型,同时生成socket连接对象
服务器 u003d socket.socket()
3.在服务器中绑定需要监听的端口并开始监听
server.bind(('192.168.43.164', 1200)) # 绑定监听端口 u003d (服务器ip地址+任意端口)
server.listen(5) # 监听
这里的服务器ip地址可以在终端输入ipconfig找到。端口是任意指定的。如果它被占用了,最好换一个。
4.获取服务器中的图片信息
BASE_DIR u003d os.path.dirname(os.path.abspath(__file__)) # 获取当前目录
PIC\DIR u003d os.path.join(BASE_DIR, 'pics') # 图片文件夹路径
pic_names u003d sorted(os.listdir(PIC_DIR)) # 获取所有排序好的图片的名字,并放入一个列表中 ['1.jpg','2.jpg',...,'9 .jpg']
将图片名称放入一个大字符串中
pic_names u003d " ".join(i for i in pic_names) # '0.jpg 1.jpg 2.jpg 3.jpg 4.jpg 5.jpg 6.jpg 7.jpg 8.jpg 9.jpg '
5.客户端上传请求后,建立服务器到客户端的连接实例
conn, addr u003d server.accept()
print("接收自{}请求".format(addr))
这里生成的conn是客户端连接的,服务端为其生成的连接实例。
6.接收数据并指定图片名称
接收数据时,可以指定每次接收的字节数,防止阻塞。这里设置每次最多可以接收1024字节。
data u003d conn.recv(1024) # 接收数据,获取图片名称命令,指定要传输的图片
打印(“接收:”,数据)
7.上传相关图片信息给客户端
客户端和服务端的通信是基于bytes类型的信息进行的,所以每次传输后,都需要将bytes类型的信息解码成string类型的信息。
另外,需要将要下载的图片大小传输给客户端,以便客户端指定每次上传的字节数。
img_name u003d data.decode('utf-8') # 将客户端传来的图片名称(字节)解码成字符串
img_path u003d os.path.join(PIC_DIR, img_name) # 获取对应图片的绝对路径
file\size u003d os.stat(img\path).st_size # 获取图像文件的大小,以字节为单位。调用stat时,用于返回相关文件的系统状态信息
file_info u003d '%s|%s' % (img_name, file_size) # 发送图片信息给客户端(用于区分文档中的两个任务)
conn.sendall(字节(文件_info,'utf-8'))
8.打开相关图片文件,批量读取字节并下载到客户端
f u003d open(img_path, 'rb') # 以二进制格式打开文件为只读
has_sent u003d 0 #记录已发送的字节数
while has_sent !u003d file_size: # 如果发送的字节数不等于图片的大小,则发送
file u003d f.read(1024) # 一次读取 1024 个字节
conn.sendall(file) # 发送给客户端
has_sent +u003d len(file) # 更新发送的字节数
f.close() #发送后关闭文件
客户端
1.导入所需的库
进口插座
导入我们
2.声明协议类型,同时生成socket连接对象
服务器 u003d socket.socket()
3.连接到服务器的相关端口
client.connect(('192.168.43.28', 1200))
这里的ip地址就是服务器的ip地址。也就是说,这里的ip地址和端口号和服务器代码中设置的一样。
4.上传图片名称信息到服务器
msg u003d input(">>:").strip() # 获取要发送到服务器的字符串格式的信息
client.send(msg.encode("utf-8")) # 将字符串格式编码成字节发送
5.接收服务器返回的图片信息
data u003d client.recv(1024) # 接收服务器返回的内容
6.以二进制格式打开文件以存储服务器下载的字节
f u003d open(path, 'ab') # 打开二进制格式的文件进行追加。如果文件不存在,则创建一个新文件进行写入。
has_receive u003d 0 # 统计接收到的字节数
而有_receive !u003d 文件大小:
data1 u003d client.recv(1024) # 一次从服务器接收1024字节的数据
f.write(data1) # 写入
has_receive +u003d len(data1) # 更新接收到的字节
f.close() # 关闭文件
此处设置的一次接收的字节数不需要与服务器中的相同。
完整代码
服务器
进口插座
导入我们
server u003d socket.socket() # 1.声明协议类型,同时生成socket链接对象
server.bind(('192.168.43.28', 1200)) # 绑定监听端口 u003d (服务器ip地址+任意端口)
server.listen(5) # 监听
BASE_DIR u003d os.path.dirname(os.path.abspath(__file__)) # 获取当前目录
PIC\DIR u003d os.path.join(BASE_DIR, 'pics') # 图片文件夹路径
pic_names u003d sorted(os.listdir(PIC_DIR)) # 获取所有排序好的图片的名字,并放入一个列表中 ['1.jpg','2.jpg',...,'9 .jpg']
将图片名称放入一个大字符串中
pic_names u003d " ".join(i for i in pic_names) # '0.jpg 1.jpg 2.jpg 3.jpg 4.jpg 5.jpg 6.jpg 7.jpg 8.jpg 9.jpg '
print("我要开始等电话了")
当真:
conn, addr u003d server.accept() # 等待调用
conn 是客户端连接的连接实例,并在服务器上为其生成
print("接收自{}请求".format(addr))
当真:
data u003d conn.recv(1024) # 接收数据,获取图片名称命令,指定要传输的图片
打印(“接收:”,数据)
如果没有数据:
print("客户端丢失了...")
休息
if data.decode('utf-8') u003du003d 'get pics_names': # 获取图片名称的命令定义为get pics_names
conn.send(pic_names.encode('utf-8'))
elif data.decode('utf-8') u003du003d 'break':
休息
其他:
img_name u003d data.decode('utf-8') # 将客户端传来的图片名称(字节)解码成字符串
img_path u003d os.path.join(PIC_DIR, img_name) # 获取对应图片的绝对路径
file\size u003d os.stat(img\path).st_size # 获取图像文件的大小,以字节为单位。调用stat时,用于返回相关文件的系统状态信息
file_info u003d '%s|%s' % (img_name, file_size) # 发送图片信息给客户端(用于区分文档中的两个任务)
conn.sendall(字节(文件_info,'utf-8'))
f u003d open(img_path, 'rb') # 以二进制格式打开文件为只读
has_sent u003d 0 #记录已发送的字节数
while has_sent !u003d file_size: # 如果发送的字节数不等于图片的大小,则发送
file u003d f.read(1024) # 一次读取 1024 个字节
conn.sendall(file) # 发送给客户端
has_sent +u003d len(file) # 更新发送的字节数
f.close() #发送后关闭文件
print('上传成功')
休息
server.close()
客户端
进口插座
导入我们
client u003d socket.socket() # 声明socket类型,同时生成socket连接对象
client.connect(('192.168.43.28', 1200)) # ip + 链接服务器端口
BASE_DIR u003d os.path.dirname(os.path.abspath(__file__)) # 获取当前目录
当真:
msg u003d input(">>:").strip() # 获取要发送到服务器的字符串格式的信息
如果 len(msg) u003du003d 0:
继续
client.send(msg.encode("utf-8")) # 将字符串格式编码成字节发送
如果味精 u003du003d 'break':
休息
data u003d client.recv(1024) # 接收服务器返回的内容
if len(str(data, 'utf-8').split('|')) u003du003d 2: # 如果返回的字符串长度为2,表示从服务器返回一张图片用于任务2
filename, filesize u003d str(data, 'utf8').split('|') # 获取指定图片的名称和大小
path u003d os.path.join(BASE_DIR, filename) # 指定保存图片的路径
filesize u003d int(filesize) # 将图像大小转换为塑料
f u003d open(path, 'ab') # 打开二进制格式的文件进行追加。如果文件不存在,则创建一个新文件进行写入。
has_receive u003d 0 # 统计接收到的字节数
而有_receive !u003d 文件大小:
data1 u003d client.recv(1024) # 一次从服务器接收1024字节的数据
f.write(data1) # 写入
has_receive +u003d len(data1) # 更新接收到的字节
f.close() # 关闭文件
print("recv:", data.decode())
客户端.close()
报错
可能会出现以下错误消息:
连接尝试失败,因为连接方在一段时间后没有正确回复或连接主机没有响应!
这时候我们可以去两台电脑的终端输入:
ping 192.168.43.X
这个 X 指的是另一台计算机的 IP 地址。
应出现以下提示
是否 Ping 10.16.1.89 32 字节数据:
From 192.168.2.135 回复来自:无法访问目标主机。
From 192.168.2.135 回复来自:无法访问目标主机。
From 192.168.2.135 回复来自:无法访问目标主机。
From 192.168.2.135 回复来自:无法访问目标主机。
但是正常的提示应该是:
这个时候,很可能是网络问题。可以尝试使用手机热点,同时为这两台电脑开启wifi。个人测试很有用!
更多推荐
所有评论(0)