1

I wrote a script in Python 3.8.6 to send and receive files between different devices. I am sending and receiving files normally, the problem happens when I receive multiple simultaneous connections from different devices.

I configured the script to save the files in folders named with the address of the device that sends the file and what is happening is that when several devices send files at the same time, files from one device go to another folder, randomly. The files are mixed.

I have an idea of why it is happening but not how to solve it.

I thought as an alternative to receive only one connection at a time. But I don't know how to do this.

sendfile.py

def conectividade(host="192.168.0.13", porta=1218, timeout=5):
while True:
    try:
        socket.setdefaulttimeout(timeout)
        socket.socket(socket.AF_INET, socket.SOCK_STREAM).connect((host, porta))
        return True
    except Exception:
        return False


# Function that sends the collected data.
def coleta():
total = []
conectividade()
conect = conectividade()
if conect == False:
    print("\nConnectivity is",conect)
    pass
else:
    data_hoje = datetime.now().strftime('%Y-%b-%d')
    direct = f".\\{data_hoje}\\"
    arquivos = os.listdir(direct)
    for arquivo in arquivos:
        try:
            sock = socket.socket()
            host = "192.168.0.13"
            porta = 1218
            print("Connectivity is", conect)
            sock.connect((host, porta))
            total += arquivo.split(',')
            sock.send(str.encode(arquivo))
            arquivo = str.encode(direct + arquivo)
            with open(arquivo, "rb") as file:
                data = file.read(1024)
                resposta = sock.recv(1024)
                if resposta == b'Waiting file':
                    file_size = os.path.getsize(arquivo)
                    print(b"sending " + arquivo)
                    print(file_size,"kb")
                    sock.send(bytes(str(file_size),'utf-8'))
                    resposta = sock.recv(1024)
                    if resposta == b'Waiting...':
                        while data:
                            sock.send(data)
                            data = file.read(1024)
                            if not data:
                                print(f"**Sending Complete**\n")
                                sock.close()
                        # Delete files after uploads
                        if total == arquivos:
                            print(f"Uploaded files:\n",total)


        except socket.error:
            print("\nSocket Error\n")

receive.py

data_hoje = datetime.now().strftime('%Y-%b-%d')
sock = socket.socket()
host ='192.168.0.13'
porta = 1218
sock.bind((host, porta))
sock.listen(10)
total = []
while True:
    conn, addr = sock.accept()
    pasta = ".\\" + addr[0].replace('.','_')
    subpasta = pasta + "\\" +  data_hoje
    if os.path.exists(pasta) == False:
        os.makedirs(f'{pasta}')
    if os.path.exists(subpasta) == False:
        os.makedirs(f'{subpasta}')
    data = conn.recv(1024)
    while data == b'':
        conn.close()
        conn, addr = sock.accept()
        data = conn.recv(1024)
    if data == b'Finalizando socket':
        print("Finalizando conexão com " + addr[0])
        conn.close()
        sock.close()
    total += data.decode().split(',')
    name_file = total[-1]
    with open(f"{subpasta}\\{name_file}", "wb") as file:
        conn.send(b"Waiting file")
        data = conn.recv(1024)
        tamanho = data.decode('utf-8')
        file_size = int(tamanho)
        if file_size != 0:
            conn.send(b"Waiting...")
            print("HOST <--> " + addr[0] + f"  Download de {name_file} - {tamanho} kb")
            while data:
                data = conn.recv(1024)
                file.write(data)
        
            conn.close()
Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
GConelhero
  • 126
  • 8
  • Your `receive.py` mostly throws away data it receives, so it's hard to figure out how it's meant to work. You should read and understand [this](https://stackoverflow.com/a/43420503/238704) answer before trying to fix your code. – President James K. Polk Dec 18 '20 at 00:02

2 Answers2

1

In receive.py you have:

conn, addr = sock.accept()
# [...]
while data == b'':
    conn.close()
    conn, addr = sock.accept()
    data = conn.recv(1024)

The client that connects on the first accept() may be different from the client that connects on the accept() inside the cycle, which could lead to the files mixing up as you described. You should re-write it with a single accept(), to guarantee the whole processing is done for the same client. This approach is described in TCP/IP Client and Server - PyMOTW-3.

Modified receive.py:

data_hoje = datetime.now().strftime("%Y-%b-%d")
sock = socket.socket()
host = "192.168.0.13"
porta = 1218
sock.bind((host, porta))
sock.listen(10)
total = []
try:
    while True:
        conn, addr = sock.accept()
        try:
            pasta = ".\\" + addr[0].replace(".", "_")
            subpasta = pasta + "\\" + data_hoje
            if os.path.exists(pasta) is False:
                os.makedirs(f"{pasta}")
            if os.path.exists(subpasta) is False:
                os.makedirs(f"{subpasta}")
            data = b""
            while data == b'':
                data = conn.recv(1024)
            if data == b"Finalizando socket":
                print("Finalizando conexão com " + addr[0])
                continue
            total += data.decode().split(",")
            name_file = total[-1]
            with open(f"{subpasta}\\{name_file}", "wb") as file:
                conn.send(b"Waiting file")
                data = conn.recv(1024)
                tamanho = data.decode("utf-8")
                file_size = int(tamanho)
                if file_size != 0:
                    conn.send(b"Waiting...")
                    print(
                        "HOST <--> " + addr[0] + f"  Download de {name_file} - {tamanho} kb"
                    )
                    while data:
                        data = conn.recv(1024)
                        file.write(data)

        finally:
            conn.close()
finally:
    sock.close()
fzbd
  • 477
  • 2
  • 8
  • 1
    This code preserves most of the bugs of the original. – President James K. Polk Dec 18 '20 at 00:01
  • fzdb, Thanks to your idea, I reviewed the code. When I put the function conectividade() in sendfile.py the socket errors broke the script, after putting except socket.error, it doesn't happen anymore, making me no longer need to conectividade... – GConelhero Dec 18 '20 at 00:12
  • @PresidentJamesK.Polk Feel free to elaborate, but note that OP didn't report data loss, reading only 1k at some points is fine for him. – fzbd Dec 18 '20 at 00:43
0

Basically, what was causing the error was the conectividade() function recursively in the original script.

so I needed...

while True:
    conn.close()
    conn, addr = socket.accept()
    data = conn.recv

What caused the files to mix, as said by fzdb ...

How was the new script ...

sendfile.py

import socket
import os
from datetime import datetime

def coleta():
    total = []
    data_hoje = datetime.now().strftime('%Y-%b-%d')
    direct = f".\\{data_hoje}\\"
    arquivos = os.listdir(direct)
    for arquivo in arquivos:
        try:
            sock = socket.socket()
            host = "192.168.0.13"
            porta = 1218
            print("Connectivity is",)# conect)
            sock.connect((host, porta))
            total += arquivo.split(',')
            sock.send(str.encode(arquivo))
            arquivo = str.encode(direct + arquivo)
            with open(arquivo, "rb") as file:
                data = file.read(1024)
                resposta = sock.recv(1024)
                if resposta == b'Waiting file':
                    file_size = os.path.getsize(arquivo)
                    print(b"sending " + arquivo)
                    print(file_size,"kb")
                    sock.send(bytes(str(file_size),'utf-8'))
                    resposta = sock.recv(1024)
                    if resposta == b'Waiting...':
                        while data:
                            sock.send(data)
                            data = file.read(1024)
                            if not data:
                                sock.close()
                                print(f"**Sending Complete**\n")
                        if total == arquivos:
                            print(f"Uploaded files:\n",total)


    except socket.error:
        print("\nSocket Error\n")

receive.py

import socket
import os
from datetime import datetime

data_hoje = datetime.now().strftime('%Y-%b-%d')
host ='192.168.0.13'
porta = 1218
sock.bind((host, porta))
sock.listen(10)
total = []
while True:
    conn, addr = sock.accept()
    pasta = ".\\" + addr[0].replace('.','_')
    subpasta = pasta + "\\" +  data_hoje
    if os.path.exists(pasta) == False:
        os.makedirs(f'{pasta}')
    if os.path.exists(subpasta) == False:
        os.makedirs(f'{subpasta}')
   data = conn.recv(1024)
    if data == b'':
        conn.close()
    total += data.decode().split(',')
    name_file = total[-1]
    try:
        with open(f"{subpasta}\\{name_file}", "wb") as file:
            conn.send(b"Waiting file")
            data = conn.recv(1024)
            tamanho = data.decode('utf-8')
            file_size = int(tamanho)
            if file_size != 0:
                conn.send(b"Waiting...")
                print("HOST <--> " + addr[0] + f"  Download de {name_file} - {tamanho} bytes")
                while data:
                    data = conn.recv(1024)
                    file.write(data)
    except:
        pass

Thank you!

For those who want to help with the original code ...

I have problems with NumPad on pynput

https://github.com/gconelhero/Keylogger

GConelhero
  • 126
  • 8