socket传送文件

一、文件传送步骤

  我们要利用socket来实现下载一个文件,该如何操作呢?

  服务端:

  1. 读取文件名
  2. 判断文件是否存在
  3. 检测文件大小(用于和客户端对比判断文件是否传送完毕)
  4. 发送文件大小给客户端
  5. 等待客户端确认(防止粘包)
  6. 打开文件
  7. 边读边发送数据
  8. md5验证

  客户端:

  • 发送命令
  • 接收文件大小
  • 返回确认
  • 获取文件名
  • 对比文件大小
  • 写入文件

二、功能实现(ftp下载功能)

  服务端:

# -*- coding: UTF-8 -*-
import os
import socket

# TCP/IP协议, tcp ,如果不填写就是默认这个
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

server.bind(('localhost', 9999))

server.listen()

while True:  # 可以接受多个客户端

    conn, addr = server.accept()
    print('new conn', addr)
    while True:

        cmd_res = conn.recv(1024)
        if not cmd_res:   # 防止当接受的客户端数据为空时,程序卡掉
            print('client has lost...')
            break
        else:
            # 获取命令和文件名
            cmd, filename = cmd_res.decode().split()
            print(cmd, filename)
            if os.path.isfile(filename):  # 判断文件是否存在
                # 文件大小
                file_size = os.stat(filename).st_size
                # 发送文件大小
                conn.send(str(file_size).encode(encoding='utf-8'))
                # 等待客户端确认
                conn.recv(1024)
                # 打开文件
                f = open(filename, 'rb')
                for line in f:
                    conn.send(line)
                    print('sending')
                f.close()
View Code

  客户端:

# -*- coding: UTF-8 -*-
import socket

client = socket.socket()

client.connect(('localhost', 9999))

while True:
    cmd = input('>>:').strip()
    # 判断是否发送空数据,如果是就重新发送
    if len(cmd) == 0:
        continue
    else:
        client.send(cmd.encode('utf-8'))
        # 获取服务端发送的文件大小
        size = client.recv(1024)
        total_file_size = int(size.decode())

        # 返回确认
        client.send(b'file size received')
        filename = cmd.split()[1]
        print(filename)
        received_size = 0
        # 写入文件
        f = open(filename + '.new', 'w', encoding='utf-8')
        while received_size < total_file_size:
            r_data = client.recv(1024)
            received_size += len(r_data)
            f.write(r_data.decode() + '\n')
        else:
            print('file sizes', total_file_size, received_size)
            print('receive finished')
            f.close()
View Code

 有些问题 替换一些内容  

f = open(filename + '.new', 'wb')
f.write(r_data)

   

  这个程序有缺陷,首先目前只能读取本文件夹下的文件,新生成的文件没有中文乱码问题,ok...

三、md5验证文件

  加个md5来验证文件是否一致

  服务端:

# -*- coding: UTF-8 -*-
import os
import socket
import hashlib

# TCP/IP协议, tcp ,如果不填写就是默认这个
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

server.bind(('localhost', 9999))

server.listen()

while True:  # 可以接受多个客户端

    conn, addr = server.accept()
    print('new conn', addr)
    while True:

        cmd_res = conn.recv(1024)
        if not cmd_res:   # 防止当接受的客户端数据为空时,程序卡掉
            print('client has lost...')
            break
        else:
            # md5
            m = hashlib.md5()
            # 获取命令和文件名
            cmd, filename = cmd_res.decode().split()
            print(cmd, filename)
            if os.path.isfile(filename):  # 判断文件是否存在
                # 文件大小
                file_size = os.stat(filename).st_size
                print(file_size)
                # 发送文件大小
                conn.send(str(file_size).encode(encoding='utf-8'))
                # 等待客户端确认
                conn.recv(1024)
                # 打开文件
                f = open(filename, 'rb')
                for line in f:
                    m.update(line)
                    # m.update('abc')  m.update('123')
                    # 其实和m.update('abc123') 结果一下
                    conn.send(line)

                f.close()
                print('send done')
                # 发送md5信息
                conn.send(m.hexdigest().encode('utf-8'))

  客户端:

# -*- coding: UTF-8 -*-
import socket
import hashlib

client = socket.socket()

client.connect(('localhost', 9999))

while True:
    cmd = input('>>:').strip()
    # 判断是否发送空数据,如果是就重新发送
    if len(cmd) == 0:
        continue
    else:
        client.send(cmd.encode('utf-8'))
        # 获取服务端发送的文件大小
        f_size = client.recv(1024)
        total_file_size = int(f_size.decode())

        # 返回确认
        client.send(b'file size received')
        filename = cmd.split()[1]
        print(filename)
        received_size = 0
        # md5
        m = hashlib.md5()

        # 写入文件
        f = open(filename + '.new', 'wb')  # 新生成的文件也正常显示
        while received_size < total_file_size:
            if total_file_size - received_size > 1024:  # 以此来控制只收文件的内容,不会粘包md5的内容
                size = 1024
            else:
                size = total_file_size - received_size
            r_data = client.recv(size)
            received_size += len(r_data)
            m.update(r_data)
            f.write(r_data)
            # print(r_data.decode())
            # print('file sizes', total_file_size, received_size)
        else:
            print('file sizes', total_file_size, received_size)
            server_md5 = client.recv(1024).decode()
            client_md5 = m.hexdigest()
            print(server_md5)
            print(client_md5)
            print('receive finished')
            f.close()

  结果:

  

  结果看上去没有问题了,新文件也能生成,并且有内容

posted @ 2017-10-29 15:38  Bigberg  阅读(2221)  评论(0编辑  收藏  举报