Python file transfer, client-server

1

I have a problem with my code, I need to develop an application that is able to send a file to a server and also can recover files from the server I am using a tuple to send the data to the server

nome = input('Digite o nome do arquivo a ser enviado: ')
arquivo = open(nome, 'r')
message = arquivo.read()
tupla = (opcao, message)

# Enviando ao servidor
socket_object.sendall(tupla)

But I'm having this error

TypeError: a bytes-like object is required, not 'tuple'

Is there any way to transform the tuple into bytes to send it through the socket?

PS: I'm using the default python3 from the ubuntu terminal

    
asked by anonymous 06.04.2017 / 20:05

1 answer

3

I suggest that you use json or pickle , although with json the serialization can be faster .

That said, this question inadvertently becomes a bit nabragente / defiant.

The error description itself speaks in the problem, that is, you need to send bytes and not a tuple, and since you can not convert a tuple into bytes directly but can do it with strings, you can send a json in this case becomes more laborious and so I will not do this, I explain below the reason).

However, we still have a problem, you can not send the bytes of the file in json because serialization problems occur ( list of data types that json understands ), you would have to send two separate messages , one with (name, file size etc .., in the form of a dict for example) and another with the bytes that compose it, and VERY IMPORTANT, you would have to send a flag (byte null eg, b'\x00' ) in the end of the first one to indicate that it has reached the end and that the server can then start receiving the binary data from the file.

This flag must exist because TCP is a streaming protocol there is no guarantee that the recv (server side in this case) method received exactly the json with the information before, it may contain only a part of the json or it may include some of the binary file information to the mix. p>

Here I put a basic example of upoload of files to the server with pickle, where we can convert a data structure (objects, dictionaries, tuples, etc ...) into a

byte stream , so with pickle, we can send the required data " time ", so in this case it facilitates a lot:

Client:

import socket, pickle

f = input('escreva o nome do ficheiro')
f_bin = open(f, 'rb').read()
info = {'name': f, 'file': f_bin, 'opcao': 1} # ajustar opcao para adequar ao teu codigo
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
    s.connect(('', 9005))
    s.sendall(pickle.dumps(info))

Server:

import socket, threading, pickle, time

def run(conn):
    info_bin = b''
    st = time.time()
    while True:
        c = conn.recv(2048)
        if not c:
            break
        info_bin += c
        if time.time() - st >= 2: # opcional, informacao sobre o total ja carregado
            print('bytes downloaded:', len(info_bin))
            st = time.time()
    info = pickle.loads(info_bin)
    if info['file']:
        dest = 'files/{}'.format(info['name'])
        with open(dest, 'wb') as f:
            f.write(info['file'])
        print('success on receiving and saving {} for {}'.format(info['name'], conn.getpeername()))
        conn.close()

host, port = ('', 9005)
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    sock.bind((host, port))
    sock.listen(5)
    while True:
        conn, addr = sock.accept()
        print('conn', addr)
        threading.Thread(target=run, args=(conn,)).start()

I have not tested with multiple clients but in principle it will also work.

You need to adjust your connection and the site where the server will write the file

    
06.04.2017 / 20:25