步骤
启动服务端程序等待连接。
启动客户端程序与服务端建立连接。
客户端输入要发送的图片文件路径(文件名)。
客户端将图片文件名和文件大小打包压缩成指定格式的数据,并发送给服务端。
服务端接收到图片文件名和文件大小后,创建新的文件名,开始接收并写入图片数据。
客户端循环读取图片文件数据,发送给服务端。
服务端不断接收并写入图片数据,直到接收完整个文件。
客户端发送完文件后,关闭Socket连接。
服务端接收完文件后,关闭Socket连接。
服务端
import os.path # 导入os.path模块,用于处理文件路径
import socket # 导入socket模块,用于创建Socket连接
import struct # 导入struct模块,用于处理二进制数据
import sys # 导入sys模块,用于退出程序
def socket_service_image():
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 创建TCP/IP Socket对象
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # 设置Socket的地址重用选项
s.bind(('192.168.9.100', 6666)) # 绑定Socket到指定的IP地址和端口
s.listen(10) # 开始监听连接请求
except socket.error as msg:
print(msg)
sys.exit(1)
print("Wait for Connection..........................") # 打印等待连接的提示信息
while True:
sock, addr = s.accept() # 接受客户端的连接请求
deal_image(sock, addr) # 处理接收到的图片
def deal_image(sock, addr):
print("Accept connection from {0}".format(addr)) # 打印客户端的IP地址和端口
while True:
fileinfo_size = struct.calcsize("128sq") # 计算文件名和文件大小的struct格式
buf = sock.recv(fileinfo_size) # 接收图片名和文件大小
if buf:
filename, filesize = struct.unpack("128sq", buf) # 解包得到图片名和文件大小
fn = filename.decode().strip("\x00") # 解码图片名
new_filename = os.path.join("./", "new_" + fn) # 在服务器端创建新的图片名
recvd_size = 0
fp = open(new_filename, 'wb') # 打开新的文件,准备写入图片数据
while not recvd_size == filesize:
if filesize - recvd_size > 1024:
data = sock.recv(1024) # 接收图片数据
recvd_size += len(data)
else:
data = sock.recv(1024) # 接收图片数据
recvd_size = filesize
fp.write(data) # 写入图片数据
fp.close() # 关闭文件
sock.close() # 关闭Socket连接
break
if __name__ == '__main__':
socket_service_image()
客户端
import socket # 导入socket模块,用于创建Socket连接
import os # 导入os模块,用于操作系统相关的功能
import sys # 导入sys模块,用于退出程序
import struct # 导入struct模块,用于处理二进制数据
def sock_client_image():
while True:
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 创建TCP/IP Socket对象
# s.connect(('服务器的ip',6666))# 服务器和客户端在不同的系统或不同的主机下时使用的ip和端口,首先要查看服务器所在的系统网卡的ip
s.connect(('192.168.23.161', 6666)) # 服务器和客户端都在一个系统下时使用的ip和端口
except socket.error as msg:
print(msg)
print(sys.exit(1))
filepath = input('input the file:') # 输入当前目录下的图片名 xxx.jpg
fhead = struct.pack(b'128sq', bytes(os.path.basename(filepath), encoding='utf-8'),
os.stat(filepath).st_size) # 将xxx.jpg以128sq的格式打包
s.send(fhead) # 发送文件名和文件大小
fp = open(filepath, 'rb') # 打开要传输的图片
while True:
data = fp.read(1024) # 读入图片数据
if not data:
print('{0} send over...'.format(filepath))
break
s.send(data) # 以二进制格式发送图片数据
s.close()
if __name__ == '__main__':
sock_client_image()
struct的作用
struct是Python内置的一个模块,它提供了一些函数,用于在Python中处理二进制数据和C语言中的结构体。在图片上传的过程中。struct模块的作用如下:
1.将图片名和文件名大小打包:在客户端程序中,使用struct.pack函数将图片名和文件大小以特定的格式进行打包。在服务端程序中,使用struct.unpack函数进行解包。这样可以将图片和文件大小作为2进制数据进行传输。
2.确定文件名的长度:通过使用struct.calcsize函数,可以计算出指定格式的结构体在内存中所占的字节数。在这个场景中,结构体格式为"128sq",表示图片名为128字节的字符串,后面跟着一个长整形表示文件大小。这样可以保证在接收端正确地解析出图片名和文件大小。
3.传输图片数据:在客户端程序中,使用Socket发送图片的二进制数据,需要读取图片的内容,将其分片并发送。在服务端程序中,也使用Socket进行接收,并将接收到的数据写入到新的文件中。
通过结合Socket和struct模块的使用,可以实现在客户端和服务端之间传输图片数据的功能,确保数据的完整性格正确性。