900字范文,内容丰富有趣,生活中的好帮手!
900字范文 > python实现利用Socket进行图片 文件的传输

python实现利用Socket进行图片 文件的传输

时间:2020-01-05 00:42:15

相关推荐

python实现利用Socket进行图片 文件的传输

近期测试方面有需求,利用一台主机进行图像数据获取,然后传输至另一台主机上,我的方法是利用socket实现,开发语言是python,能够在客户端实现图像的获取,然后发送至服务器,服务器端可以选择保存图片至指定文件夹,也可以不保存,实时查看。

一、视频转化为图片的传输:

客户端打开笔记本摄像头,将图片格式进行转换后,发送至服务器,服务器格式转换后显示保存。

服务器程序:

# -*- coding: utf-8 -*-#功能:# 1.一台电脑/两台电脑间,客户端自动截屏后传输图像至服务器# 2.一台电脑/两台电脑间,客户端自动打开摄像头传输图像至服务器#服务器程序import socketserver, struct, gzip, timeimport PIL.ImageShowfrom PIL import ImageFile, Imagefrom io import BytesIOimport matplotlib.pyplot as pltimport cv2import numpydef Save(imgBytes):imgIO = BytesIO(imgBytes)img = Image.open(imgIO)img = img.convert('YCbCr') # 转换成YCbCr格式# img.save('.\screenshot\{:.2f}.jpeg'.format(time.time()))#保存图片,注意图片会一直存储,要及时清理class DATA(socketserver.BaseRequestHandler):def handle(self):ImageFile.LOAD_TRUNCATED_IMAGES = Trues = self.requestwhile True:t1 = time.time()headSize = struct.calcsize('l') # 计算文件头长度head = s.recv(headSize) # 接收文件头if head:imgSize = struct.unpack('l', head)[0] # 获取图像长度,类型:intrecvSize = 0 # 接收到的数据长度imgBytesZ = b'' # 接收到的数据print("imgSize,recvSize,imgBytesZ",imgSize,recvSize,imgBytesZ)while True:if imgSize - recvSize > 0: # 不断接收数据直至没有数据imgBuf = s.recv(SERVER().bufSize)recvSize += len(imgBuf)else:breakimgBytesZ += imgBufimgBytes = gzip.decompress(imgBytesZ) # 解压数据t2 = time.time()T = str(str((t2 - t1) * 1000) + "ms")print("接受图片所需时间",T)Save(imgBytes)#保存图像#图像显示bytes_stream = BytesIO(imgBytes)#图像由Byte格式转换回PCI.Image格式image = Image.open(bytes_stream)PIL.ImageShow.show(image)# img = cv2.cvtColor(numpy.asarray(image), cv2.COLOR_RGB2BGR)#显示图片,每次都会重新打开一个界面显示传输的图片class SERVER():def __init__(self):self.bufSize = 8388608 # 每一次接受的字节流长度def Server(self):server = socketserver.ThreadingTCPServer(('192.168.1.12', 8000), DATA) # 自定义端口,不同主机的话,服务器写自己的主机端口,客户机写服务器主机端口#server = socketserver.ThreadingTCPServer(('127.0.0.1', 8000), DATA) #同一主机server.serve_forever()if __name__ == "__main__":SERVER().Server()

客户端程序:

# -*- coding: utf-8 -*-#功能:# 1.一台电脑/两台电脑间,客户端自动截屏后传输图像至服务器# 2.一台电脑/两台电脑间,客户端自动打开摄像头传输图像至服务器#客户端程序import socket, struct, pyscreenshot, gzipfrom PIL import Imagefrom io import BytesIOimport cv2import timeimport numpyclass CLIENT():def __init__(self):self.bufSize = 8388608 # 每一次传输的字节流长度#自动截屏功能,需要可以开启,使用的话注意注释掉下面的调用摄像头代码'''# def Data(self, s):#while True:# img = pyscreenshot.grab() # 截取屏幕图像,类型:PIL.PngImagePlugin.PngImageFile## imgW = img.size[0] # 图像宽度# imgH = img.size[1] # 图像长度# if imgW > 1920: # 图像宽度不超过1920# zoom = 1920 / imgW# else:# zoom = 1# imgResize = img.resize((int(imgW * zoom), int(imgH * zoom)), Image.Resampling.LANCZOS) # 调整后的图像# print(type(imgResize))# imgIO = BytesIO() # 创建文件对象,类型:io.BytesIO# imgResize.save(imgIO, 'JPEG') # 以JPEG格式存储,减少数据大小# print(type(imgIO))# imgIOZ = BytesIO() # 创建文件对象,类型:io.BytesIO# imgIOZ.write(press(imgIO.getvalue())) # 压缩原图并存入文件对象# print(type(imgIOZ))# imgBytes = imgIOZ.getvalue() # 图像的字节流,类型:bytes# print(len(imgBytes)) # 显示字节流长度## imgSize = len(imgBytes) # 图像大小(字节流长度),类型:int# head = struct.pack('l', imgSize) # 构造文件头信息,内容是图像大小(字节流长度),类型:bytes# s.send(head) # 发送文件头# imgIOZ.seek(0, 0) # 从开头读取图片# while True:#imgBuf = imgIOZ.read(self.bufSize) # self.bufSize大小的图片,类型:bytes#if not imgBuf: # 传输完成退出循环# break#s.send(imgBuf) # 发送self.bufSize大小的图片'''#调用笔记本摄像头程序,使用时注意注释掉上方截屏部分的代码def Data(self, s):# screen = cv2.VideoCapture(0)while True:# img即为t1 = time.time()sucess, img = screen.read()# 转为灰度图片,转不转都可以gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)img_encode = cv2.imencode('.jpg', img)[1]data_encode = numpy.array(img_encode)# str_encode = data_encode.tostring()str_encode = data_encode.tobytes()encode_len = str(len(str_encode))print(encode_len) # 输出看一下encode码的大小,可有可无# 显示摄像头cv2.imshow("321img", gray)# 保持画面的持续。k = cv2.waitKey(3) #这里如果为0的话,就是将你目前所在的画面定定格,为其他数字比如1的时候,表示1秒后程序结束。但是由于是死循环,所以结束后马上开启,就为连续图像,if k == 27:# 通过esc键退出摄像cv2.destroyAllWindows()breakelif k == ord("s"): # 关闭摄像头# 通过s键保存图片,并退出。cv2.imwrite("image2.jpg", img)cv2.destroyAllWindows()breakimgResize = Image.fromarray(cv2.cvtColor(img,cv2.COLOR_BGR2RGB))#将opencv格式图像,转化为PIC.Image格式print(type(imgResize))imgIO = BytesIO() # 创建文件对象,类型:io.BytesIOimgResize.save(imgIO, 'JPEG') # 以JPEG格式存储,减少数据大小print(type(imgIO))imgIOZ = BytesIO() # 创建文件对象,类型:io.BytesIOimgIOZ.write(press(imgIO.getvalue())) # 压缩原图并存入文件对象print(type(imgIOZ))imgBytes = imgIOZ.getvalue() # 图像的字节流,类型:bytesprint(len(imgBytes)) # 显示字节流长度imgSize = len(imgBytes) # 图像大小(字节流长度),类型:inthead = struct.pack('l', imgSize) # 构造文件头信息,内容是图像大小(字节流长度),类型:bytess.send(head) # 发送文件头imgIOZ.seek(0, 0) # 从开头读取图片while True:imgBuf = imgIOZ.read(self.bufSize) # self.bufSize大小的图片,类型:bytesif not imgBuf: # 传输完成退出循环breaks.send(imgBuf) # 发送self.bufSize大小的图片print("send successed")t2 = time.time()T = str(str((t2 - t1)*1000) + "ms")print("发送图片所需时间:", T)def Client(self):while True: # 死循环加上try语句可以不用考虑先运行服务器端try: # 连接不上重试s = socket.socket()s.connect(('192.168.1.12', 8000)) # 自定义服务器IP和端口#s.connect(('127.0.0.1', 8000))# 同一台主机下服务器IP和端口except Exception as e:print('Connection error')print(e)s.close()continuetry: # 传输数据发生错误重试self.Data(s) # 处理数据并传输except Exception as e:print('Data error')print(e)finally:s.close()if __name__ == '__main__':screen = cv2.VideoCapture(0)CLIENT().Client()

二、图片、文件的传输,都是一样利用的socket,代码如下:

客户端代码:

# 服务器端server.py# 能实现主机自身或不同主机间传图片或者文件,不过目前只能是客户端发,服务器收,# 互相发送的功能还未实现,如果是单纯不想利用U盘传图片,笨方法是互相调换身份,# 那就用客户端运行服务器程序,注意更换ipimport socketimport osimport sysimport structdef socket_service_image():try:s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)s.bind(('127.0.0.1', 8000))s.listen(10)except socket.error as msg:print(msg)sys.exit(1)print("Wait for Connection.....................")while True:sock, addr = s.accept() # addr是一个元组(ip,port)deal_image(sock, addr)def deal_image(sock, addr):print("Accept connection from {0}".format(addr)) # 查看发送端的ip和端口while True:fileinfo_size = struct.calcsize('128sq')buf = sock.recv(fileinfo_size) # 接收图片名print(buf)if buf:filename, filesize = struct.unpack('128sq', buf)fn = filename.decode().strip('\x00')print(type(fn))new_filename = os.path.join(r'E:\\reseive_images\\' + fn) recvd_size = 0fp = 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 = filesizefp.write(data) # 写入图片数据fp.close()sock.close()breakif __name__ == '__main__':socket_service_image()

客户端程序:

# 客户端client.py# 图片或者文件都可以import socketimport osimport sysimport structdef sock_client_image():while True:try:s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)# s.connect(('改成服务器ip地址', 8001)) # 服务器和客户端在不同的系统或不同的主机下时使用的ip和端口,首先要查看服务器所在的系统网卡的ip# s.connect(('127.0.0.1', 8000)) #服务器和客户端都在一个系统下时使用的ip和端口s.connect(('192.168.1.13', 8000)) # 服务器和客户端是两个主机时,服务器的ip和端口except socket.error as msg:print(msg)print(sys.exit(1))# 输入当前目录下的图片名 xxx.jpgfilepath = r'F:\pythonProject\Pyserial-Demo-master\Pyserial-Demo-master\test1.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))breaks.send(data) # 以二进制格式发送图片数据s.close()break #循环发送if __name__ == '__main__':sock_client_image()

三、大文件的传输,其实原理和上面是一样的,结构也差不多,代码如下:

服务器端:

#快速读取快速存储,大文件也可以import timeimport cv2import osimport jsonimport socketimport threading#读取文件的最大数max_len=8388608 #也可以提前写一个大数字,这样传输的会快一些,或者用于,如4294967296#端口号和IP地址remote_PORT=5555remote_IP='127.0.0.1'remote_addr=(remote_IP,remote_PORT)#绑定IP地址和端口号PORTsocket_Server=socket.socket(socket.AF_INET,socket.SOCK_STREAM)socket_Server.bind(remote_addr)#监听socket_Server.listen()print('正在监听来自客户端的消息......')def Server_Recv_File(socket):""":param socket: 服务端套接字:param root: 主窗口:return:"""t1 = time.time()#获取客户端发送的消息头msg_header=socket.recv(max_len)header=json.loads(msg_header.decode('utf-8'))#输出客户端发送的消息头信息print(header)#保存接收文件的地方# curr_path=os.getcwd()curr_path = os.path.join(r'E:\reseive_images_1')# time = datetime.now()# time = datetime.strftime(datetime.now(), '%Y%m%d-%H%M%S')filename = curr_path + '\\recv_' + header['filename'] + header['msg_type']get_file_Size=header['msg_len']file_size=0#输出文件名和文件大小print('文件名: {}'.format(filename))print(type(filename))print('file_size: {}'.format(get_file_Size))recv_count = 0#如果文件不存在则创建if os.path.exists(filename)==False:with open(filename,'wb') as fp:while file_size!=get_file_Size:message=socket.recv(max_len)fp.write(message)file_size+=len(message)print(file_size)recv_count+=1else:with open(filename, 'wb') as fp:while file_size != get_file_Size:message = socket.recv(max_len)fp.write(message)file_size += len(message)print(file_size)recv_count += 1print('接收次数: {}'.format(recv_count))socket.close()print('接收完成...')t2 = time.time()t = t2-t1print(t)if __name__=='__main__':print('Pycharm')new_socket,addr=socket_Server.accept()Server_Recv_File(new_socket)

客户端:

#快速读取快速存储,大文件也可以import osimport jsonimport socketimport threadingimport time#读取文件的最大数,可以修改,提前写一个大数字,这样传输的会快一些,或者用于,如4294967296max_len=8388608#端口号和IP地址remote_PORT=5555remote_IP='127.0.0.1'remote_addr=(remote_IP,remote_PORT)#绑定端口号和IP地址socket_Client=socket.socket(socket.AF_INET,socket.SOCK_STREAM)socket_Client.connect(remote_addr)def Client_Send_File(socket_Client,filename):""":param socket: 客户端套接字:param filename: 要传输的文件:param root:主窗口:return:"""t1 = time.time()#首先将消息头发送至服务端file,class_file=os.path.splitext(filename)#获取文件大小# file_size=os.path.getsize(filename)file_Size=os.stat(filename).st_sizemsg_header={'filename':file,'msg_type':class_file,'msg_len':file_Size}msg_header_bytes=bytes(json.dumps(msg_header),encoding='utf-8')#当消息头的长度不满1024时,使用空格填充msg_header_bytes+=b''*(max_len-len(msg_header_bytes))socket_Client.send(msg_header_bytes)file_len=0recv_count=0#发送的文件头大小print('msg_header_bytes: {}'.format(len(msg_header_bytes)))#发送的文件大小print('file_size: {}'.format(file_Size))with open(filename,'rb') as fp:while file_len!=file_Size:message=fp.read(max_len)socket_Client.send(message)file_len+=len(message)print(file_len)recv_count+=1print('发送次数: {}'.format(recv_count))# socket_Client.close()print('发送完成...')t2 =time.time()t=t2-t1print(t)if __name__=='__main__':print('Pycharm')#第二个参数为图片或者其他文件的路径Client_Send_File(socket_Client,'yolov3.weights')

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。