题目

   在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.截图

socket两个python程序非阻塞通信 两个python 通信_socket

5.使用方法

a. 先运行服务端 server,再运行客户端client。
b. 在客户端下输入get pics_names,获得服务端中pics文件夹中的所有图片名称。
c. 接着从返回的所有图片名称中,选择一个,在客户端输入,如1.jpg。则会从服务端传回这张图片。
d. 退出通信,在客户端输入break即可。