文件上传 + socketserver(并发)

 

文件上传

示例 1 : 将文件或图片等数据 从客户端传送到服务端

  涉及到解决黏包, 将 命令 / 文件路径(文件) / 文件大小  +   文件内容  都发过去 前面的东西和后面的数据在传输的过程中,可能会出现黏包现象, 为了解决这个问题,将 文件信息 部分的长度进行压缩struct.pack()进行压缩,一起发送到服务端,则发送的内容为 文件信息长度 / 文件信息 / 文件内容 三部分,通过解压文件长度,获取接收文件信息的字节长度,最终通过循环接收文件内容.

  涉及知识点 :  黏包 / 序列化 / hashlib对比文件数据是否一致

# 服务端  
import
struct import socket import json import hashlib sock=socket.socket() sock.bind(('127.0.0.1',8800)) sock.listen(5) while 1: print("server is working....") conn,addr= sock.accept() while 1: # 接收json的打包长度 file_info_length_pack=conn.recv(4) file_info_length=struct.unpack("i",file_info_length_pack)[0] # 接收json字符串 file_info_json=conn.recv(file_info_length).decode("utf8") file_info=json.loads(file_info_json) action=file_info.get("action") filename=file_info.get("filename") filesize=file_info.get("filesize") # 循环接收文件 md5=hashlib.md5() with open("put/"+filename,"wb") as f: recv_data_length=0 while recv_data_length<filesize: data=conn.recv(1024) recv_data_length+=len(data) f.write(data) # MD5摘要 md5.update(data) print("文件总大小:%s,已成功接收%s"%(filesize,recv_data_length)) print("接收成功!") conn.send(b"OK") print(md5.hexdigest()) md5_val=md5.hexdigest() client_md5=conn.recv(1024).decode("utf8") if md5_val==client_md5: conn.send(b"203") else: conn.send(b"204")

 

# 客户端  
import socket
import os
import json
import struct
import hashlib

sock=socket.socket()
sock.connect(("127.0.0.1",8800))


while 1 :
    cmd=input("请输入命令:") # put 111.jpg

    action,filename=cmd.strip().split(" ")
    filesize=os.path.getsize(filename)

    file_info={
        "action": action,
        "filename": filename,
        "filesize": filesize,
    }
    file_info_json=json.dumps(file_info).encode("utf8")

    ret=struct.pack("i",len(file_info_json))
    sock.send(ret)     # 发送 file_info_json的打包长度
    sock.send(file_info_json)   # 发送 file_info_json字节串

    # 发送 文件数据
    md5=hashlib.md5()
    with open(filename,"rb") as f:
        for line in f:
            sock.send(line)
            md5.update(line)

    data=sock.recv(1024)
    print(md5.hexdigest())
    md5_val=md5.hexdigest()
    sock.send(md5_val.encode("utf8"))  # 发送密文
    is_valid=sock.recv(1024).decode('utf8')
    if is_valid=="203":
        print("文件完整!")
    else:
        print("文件上传失败!")

socketserver (并发)

♥♥♥♥♥

  使用socketserver 的 ThreadingTCPServer 可以是服务端同时接收多个客户端的请求. 逻辑部分封装在 handle 方法中

import socketserver

class My_Server(socketserver.BaseRequestHandler):  # 定义自己的服务类,必须继承 socketserver.BaseRequestHandle 类
    def handle(self):  # 方法名是固定的
        '''
        handle中有 套接对象request  等价于之前的conn  
                    用法为  self.request.recv(1024)     self.request.send() 
        :return: 
        '''
        
        pass   # handle方法中是服务端的请求后的命令  逻辑部分
    

server = socketserver.ThreadingTCPServer(('127.0.0.1',8899),My_Server)      # 参数为 ip端口,  自定的类      # 用于  bingd绑定  listen等候数
server.serve_forever()      # 用于   accept() 等待连接

socketserver 源码解析

 

 

posted @ 2018-09-05 15:23  葡萄想柠檬  Views(480)  Comments(0)    收藏  举报
目录代码