socket传文件

粘包的两种处理方式

  • 一次完整的交互(ack响应)
  • 使用if判断,保证recv的最后一次,剩多少收多少(后面的数据就可再收了)

get文件

ftp server

  1. recv得到文件名
  2. 检测文件是否存在
  3. send文件大小给客户端(如果存在)
  4. 等待客户端确认
  5. 打开文件
  6. 边读边send,同时做MD5
  7. 最后send文件MD5
  8. 验证文件夹
  9. 关闭文件

ftp client

  1. send 命令给server
  2. recv文件大小
  3. send something #一次交互解决粘包
  4. wb模式打开新文件
  5. 边recv边写,同时做md5
  6. 关闭文件
  7. recv服务端发过来的源文件的md5值

在收完文件后又直接接收了md5的值,所以在收文件的过程中(f.close()之前),通过if判断,保证文件准确的接收了那么多

get file 交互图


import hashlib
import socket,os
server = socket.socket()
server.bind(('localhost', 9999))
server.listen()

while True:
    conn,addr = server.accept()
    print('new conn:',addr)
    while True:
        print("等待新指令")
        data = conn.recv(1024)
        if not data:
            print("客户端已断开")
            break

        cmd,filename = data.decode().split()
        print(filename)
        if os.path.isfile(filename):
            f = open(filename, 'rb')
            m = hashlib.md5()
            file_size = os.stat(filename).st_size
            conn.send( str(file_size).encode() )  #send file size
            conn.recv(1024)   #等待确认
            for line in f:
                m.update(line)
                conn.send(line)
            print("file md5", m.hexdigest())
            f.close()
            conn.send(m.hexdigest().encode())
        print("send done")
server.close()

import socket
import hashlib
client = socket.socket()
client.connect(('localhost', 9999))

while True:
    cmd = input('>>:').strip()
    if not cmd:continue
    if cmd.startswith("get"):
        client.send(cmd.encode())
        server_response = client.recv(1024)
        print("server response:", server_response)
        client.send(b'ready to recv file')
        file_total_size = int(server_response.decode())
        received_size = 0
        filename = cmd.split()[1]
        f = open(filename+".new",'wb')
        m = hashlib.md5()
        while received_size < file_total_size:
            #如果没有此处if判断,可能会发生粘包(最后一次接受1024可能将md5一起收过来)
            if file_total_size - received_size > 1024:  #要收不止一次
                size = 1024
            else:  #最后一次,剩多少收多少
                size = file_total_size - received_size
            data = client.recv(size)    #用size替换1024
            received_size += len(data)
            m.update(data)
            f.write(data)
            print(file_total_size,received_size)
        else:
            new_file_md5 = m.hexdigest()
            print("file recv done")
            f.close()
        server_file_md5 = client.recv(1024)   #此处接收md5值(发生粘包客户端会在此处阻塞)
        print("server file md5:",server_file_md5)
        print("client file md5",new_file_md5)

client.close()

简单的ftp:https://github.com/jinboxu/ftp

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 135,323评论 19 139
  • win7 cmd管理员权限设置 net localgroup administrators 用户名 /add 把“...
    f675b1a02698阅读 10,738评论 0 11
  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 14,195评论 4 61
  • 最近在学习Python看了一篇文章写得不错,是在脚本之家里的,原文如下,很有帮助: 一、网络知识的一些介绍 soc...
    qtruip阅读 7,675评论 0 6
  • 我发现对于我来说,坚持做一件事情正在渐渐变得很困难,很难坚持读完一本书,很难坚持早起,很难坚持锻炼等等。道理知道...
    让我睡阅读 1,599评论 0 0