简体   繁体   English

通过LAN通过套接字发送文件时无法正确接收文件

[英]Files not being received correctly when sent through sockets over LAN

I am trying to build an application that will send files over wireless LAN through the Python 3.4 socket module. 我正在尝试构建一个将通过Python 3.4套接字模块通过无线局域网发送文件的应用程序。 It appears to be able to send files within one workstation, but when attempting to send files between two computers on the same network, the computer only appears to receive the first few thousand bytes, the amount dependent on the total size of the file when sent. 它似乎可以在一个工作站内发送文件,但是当尝试在同一网络上的两台计算机之间发送文件时,该计算机似乎仅接收前几千个字节,该数量取决于发送时文件的总大小。

For example, a 127 byte file was sent with no issues, but of a 34,846 byte file, only 1,431 or 4,327 bytes were received (only these two numbers of bytes seemed to be received, seemingly randomly switching between the two) and of a 65,182 byte file, only 5,772 or 4,324 bytes were received (the same situation). 例如,发送了一个127字节的文件,没有问题,但是发送了一个34,846字节的文件,仅接收到1,431或4,327字节(似乎只接收到这两个字节,似乎在两者之间随机切换),而接收到65,182字节文件,只收到5,772或4,324字节(相同的情况)。 From looking at the contents of the received files, it appeared that it was the first few bytes that were received. 从接收到的文件的内容看,似乎是接收到的前几个字节。

Both systems have free, accessible RAM exceeding 2GB and sufficient storage space. 两种系统均具有超过2GB的免费可访问RAM和足够的存储空间。 The server is being run on Windows 8.1, Python 3.4.2, and the client is Ubuntu 14.04 Linux, Python 3.4.0. 服务器正在Windows 8.1,Python 3.4.2上运行,客户端是Ubuntu 14.04 Linux,Python 3.4.0。

My code may be piecemeal and generally poorly written, as I am a beginner without a formal computer science education or any notable experience, especially in network programming. 我的代码可能是零敲碎打的,而且通常写得不好,因为我是初学者,没有接受过正规的计算机科学教育或任何著名的经验,尤其是在网络编程方面。 However, I have rooted through the code and racked my brain with no clear solution presenting itself. 但是,我已经扎根代码,绞尽脑汁,没有提出明确的解决方案。

Server (Host): 服务器(主机):

import os
import socket
import struct
import time
import hashlib

def md5(fname):
    hash_md5 = hashlib.md5()
    with open(fname, "rb") as readFile:
        for chunk in iter(lambda: readFile.read(4096), b""):
            hash_md5.update(chunk)
    return hash_md5.hexdigest()

try:
    s = socket.socket()
    host = socket.gethostname()
    port = 26
    s.bind(("0.0.0.0", port))

    filename = input("File to send? ")

    fileLength = os.stat(filename).st_size
    print("Length:", fileLength, "bytes")
    fileLengthBytes = struct.pack(">L", fileLength)

    filenameBytes = bytes(filename, "ascii")
    filenameLength = struct.pack(">L", len(filenameBytes))

    checksum = md5(filename)
    checksumBytes = bytes(bytearray.fromhex(checksum))

    s.listen(5)
    while True:
        c, addr = s.accept()
        print("Connection from", addr)
        c.send(checksumBytes)
        time.sleep(0.1)
        c.send(filenameLength + fileLengthBytes)
        time.sleep(0.1)
        with open(filename, "rb") as f:
            c.send(filenameBytes + f.read())
        c.close()
finally:
    try:
        c.close()
    except NameError:
        pass
    except Exception as e:
        print(type(e), e.args, e)
    try:
        f.close()
    except NameError:
        pass
    except Exception as e:
        print(type(e), e.args, e)

Client (Recipient): 客户(收件人):

import socket
import struct
import hashlib

def md5(fname):
    hash_md5 = hashlib.md5()
    with open(fname, "rb") as readFile:
        for chunk in iter(lambda: readFile.read(4096), b""):
            hash_md5.update(chunk)
    return hash_md5.hexdigest()


CHECKSUM_LENGTH = 16

try:
    s = socket.socket()
    host = socket.gethostname()
    port = 26

    ip = input("Connect to IP: ")

    s.connect((ip, port))

    initialChecksum = s.recv(CHECKSUM_LENGTH)

    received = s.recv(8)
    # 1st 4 bytes: filename length
    # 2nd 4 bytes: file contents length

    filenameLength = struct.unpack(">L", received[0:4])[0]
    fileLength = struct.unpack(">L", received[4:])[0]
    print("Length:", fileLength)

    bytesToReceive = filenameLength + fileLength
    receivedBytes = s.recv(bytesToReceive)

    filename = str(receivedBytes[0:filenameLength], "ascii")
    f = open(filename, "wb")
    f.write(receivedBytes[filenameLength:]) # Write file contents
    actualChecksum = bytes(bytearray.fromhex(md5(filename)))

    if initialChecksum == actualChecksum:
        print("Fully received", filename)
    else:
        print(filename, "not received correctly")
finally:
    try:
        f.close()
    except NameError:
        pass
    except Exception as e:
        print(type(e), e.args, e)
    try:
        s.close()
    except NameError:
        pass
    except Exception as e:
        print(type(e), e.args, e)

I am aware that the md5 function that I use doesn't appear to work for small files below, I assume, 4 kilobytes. 我知道我使用的md5函数似乎不适用于以下4 KB的小文件。

Where is the problem? 问题出在哪儿? How can it be solved? 如何解决? Am I missing something important? 我缺少重要的东西吗?

You are receiving only the first few packages of the transmission. 您仅收到传输的前几个软件包。 This is because the s.recv() will receive the bytes that have reached the client already, but at most the number given as argument. 这是因为s.recv()将接收已经到达客户端的字节,但最多是作为参数给出的数字。 On a local machine the transmission is fast, you will receive more. 在本地计算机上,传输速度很快,您将收到更多。

To get all parts of the transmission you should collect all bytes until the expected length has been reached. 要获得传输的所有部分,您应该收集所有字节,直到达到预期的长度。

A very simplistic approach would be something like: 一个非常简单的方法是:

buffer = ''
while len(buffer) < bytes_to_receive:
    buffer += s.recv(1500)

1500 is the typical LAN MTU and a good value to get at least a full package. 1500是典型的LAN MTU,对于获得至少一个完整的包装来说是很有价值的。 The code given is only a simple example for Python 2 to explain the concept. 给出的代码只是Python 2解释该概念的简单示例。 It needs to be refined and optimized and, if you are using Python 3, adapted to bytes. 需要完善和优化它,如果您使用的是Python 3,则必须适应字节。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM