题目
在linux环境下用python语言编程。使用socket实现两台主机之间的通信:其中一台为服务器,服务器上建立本地图像库文件夹(不少于10张图像),图像为不低于720P的彩色图像;另一台为客户端。通过python调用socket编写服务器端和客户端程序完成以下功能:1)服务器将本地图像库的所有图像文件名告知给客户端;2)客户端通知服务器需要获取的图像文件名称,服务器将对应的图像文件通过网络传送给客户端,客户端将其保存存盘。
2.服务端
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
# Date: 19-5-22 下午8:48
import socket
import os
server = socket.socket() # 1.声明协议类型,同时生成socket链接对象
server.bind(('localhost', 6666)) # 绑定要监听端口=(服务器的ip地址+任意一个端口)
server.listen(5) # 监听
BASE_DIR = os.path.dirname(os.path.abspath(__file__)) # 获得当前目录
PIC_DIR = os.path.join(BASE_DIR, 'pics') # 图片文件夹的路径
pic_names = sorted(os.listdir(PIC_DIR)) # 获得排序后的所有图片名称,放在一个列表中【'1.jpg','2.jpg',...,'9.jpg'】
# 将图片名称放进一个大字符串中
pic_names = " ".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("我要开始等电话了")
while True:
conn, addr = server.accept() # 等电话打进来
# conn就是客户端连过来而在服务器端为其生成的一个连接实例
print("收到来自{}请求".format(addr))
while True:
data = conn.recv(1024) # 接收数据,获取图像名称的命令,指定需要传输的图片
print("recv:", data)
if not data:
print("client has lost...")
break
if data.decode('utf-8') == 'get pics_names': # 获取图像名称的命令 定义为get pics_names
conn.send(pic_names.encode('utf-8'))
elif data.decode('utf-8') == 'break':
break
else:
img_name = data.decode('utf-8') # 将客户端传输过来的图片名称(bytes)解码成字符串
img_path = os.path.join(PIC_DIR, img_name) # 获得对应图片的绝对路径
file_size = os.stat(img_path).st_size # 获得图像文件的大小,字节单位
file_info = '%s|%s' % (img_name, file_size) # 将图像信息发给客户端(用于区分文档中的两个任务)
conn.sendall(bytes(file_info, 'utf-8'))
f = open(img_path, 'rb') # 以二进制格式打开一个文件用于只读
has_sent = 0 # 记录下已经发送的字节数
while has_sent != file_size: # 发送的字节数 不等于 图像的大小,则接着发送
file = f.read(1024) # 一次读1024个字节
conn.sendall(file) # 发送给客户端
has_sent += len(file) # 更新已发送的字节数
f.close() # 发送结束,关闭文件
print('上传成功')
break
server.close()
3.客户端
import socket
import os
client = socket.socket() # 声明socket类型,同时生成socket连接对象
client.connect(('localhost', 6666)) # 链接服务器的ip + 端口
BASE_DIR = os.path.dirname(os.path.abspath(__file__)) # 获得当前目录
while True:
msg = input(">>:").strip() # 获得要向服务端发送的信息,字符串格式
if len(msg) == 0:
continue
client.send(msg.encode("utf-8")) # 将字符串格式编码成bytes,发送
if msg == 'break':
break
data = client.recv(1024) # 接收服务端返回的内容
if len(str(data, 'utf-8').split('|')) == 2: # 如果返回的字符串长度为2,说明针对的任务2,从服务端传回一张图片
filename, filesize = str(data, 'utf8').split('|') # 获得指定图像的名称,图像大小
path = os.path.join(BASE_DIR, filename) # 指定图像的保存路径
filesize = int(filesize) # 图像大小转换成整形
f = open(path, 'ab') # 以二进制格式打开一个文件用于追加。如果该文件不存在,创建新文件进行写入。
has_receive = 0 # 统计接收到的字节数
while has_receive != filesize:
data1 = client.recv(1024) # 一次从服务端接收1024字节的数据
f.write(data1) # 写入
has_receive += len(data1) # 更新接收到的字节数
f.close() # 关闭文件
print("recv:", data.decode())
client.close()
4.截图
5.使用方法
a. 先运行服务端 server,再运行客户端client。
b. 在客户端下输入get pics_names,获得服务端中pics文件夹中的所有图片名称。
c. 接着从返回的所有图片名称中,选择一个,在客户端输入,如1.jpg。则会从服务端传回这张图片。
d. 退出通信,在客户端输入break即可。