Transfer of python files, client-server

Asked

Viewed 2,796 times

1

Guys I have a problem in my code, I need to develop an application that is able to send a file to a server and also be able to recover files from the server I’m 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 mistake

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 am using the standard Ubuntu terminal python3

  • How the object is defined socket_object? Use the package socket python?

  • socket_object = socket(AF_INET, SOCK_STREAM)

  • First, I believe you can’t send a tuple through the socket, just a string, so you can convert it to JSON before, for example: socket_object.sendall(str.encode(json.dumps(tupla))), or something similar.

  • I made a mistake NameError: name 'json' is not defined, I’m working with Ubuntu terminals and his standard python3

  • You need to include the package import json

  • I managed to send it through the socket, but I could not recover them on the server, I used it data = socket_object.recv(1024)
 data = (str.decode(json.dumps()))

  • And I got this error on the server OSError: [Errno 107] Transport endpoint is not connected

  • I was able to fix the bug OSError: [Errno 107] Transport endpoint is not connected, the problem is to perform the Decode, as could be done on the server side to go back to being a tuple?

  • See in the answer given.

  • @Andersoncarloswoss I’m sorry, maybe you were getting ready to answer and "I got in the way" I didn’t realize you were talking here. If you think it’s less correct I’ll remove it

  • @Miguel, no problem. I had not answered for not being sure if it would solve the problem.

  • Because @Andersoncarloswoss I think it didn’t solve, it wasn’t enough lol. Ricardo you should be sure that you are excutating the function recv under the right socket, and that this is connected.

  • I got this error: tupla_recebida = json.loads(data.decode())
 File "/usr/lib/python3.5/json/__init__.py", line 319, in loads
 return _default_decoder.decode(s)
 File "/usr/lib/python3.5/json/decoder.py", line 339, in decode
 obj, end = self.raw_decode(s, idx=_w(s, 0).end())
 File "/usr/lib/python3.5/json/decoder.py", line 355, in raw_decode
 obj, end = self.scan_once(s, idx)
json.decoder.JSONDecodeError: Unterminated string starting at: line 1 column 7 (char 6)

  • Ricardo, I chose to take the answer because to send data in binary cannot be inside a json. But I’m working to help you anyway

  • All right, no problem, thanks to @Miguel

  • Look I’m creating the functionality, tell me something... Is your server for multiple clients? Or just one?

  • Only one customer

  • Ricardo tests this: https://pastebin.com/53GDpmCg. It is very basic but it does the supposed... Python3 . Sets the name of the folder where the file will be saved on the server side

  • The trick is to send a json with the information you want (in this case, the file size/name), and only then the bytes that make up the file. And Inform the server that the json message has been fully received, we do this by sending a null byte at the end of the json message.... And only then the server starts receiving bytes from the file

Show 14 more comments

1 answer

3

I suggest to transfer data structures use json or pickle, although with json the serialization can be faster.

That being said, this question unintentionally becomes a bit of a blatant/challenging.

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

However we still have a problem, you cannot send the bytes of the file to json because there are problems with serialization (list of the types of data that json understands), you’d have to send two separate messages, one with the adjacent information (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 (null byte for ex, b'\x00') at the end of the first to indicate that it has come to an end and that the server can then start receiving binary data from the file.

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

Here I put a basic example of file upoload for the server with pickle, where we can convert a data structure (objects, dictionaries, tuples, etc...) into a data structure byte stream, so with pickle, we can immediately send the necessary data "at once", so in this case it makes it easier:

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 will also work.

You must adjust your connection and where the server will write the file

  • I did it here, but I got this mistake data = socket_object.recv(1024)
OSError: [Errno 107] Transport endpoint is not connected

  • I guess I’d have to see your code from that part, do you have any place you can show it? The name of the socket on the server side is socket_object?

  • I’m having the same problem with Code @Miguel

  • I got this error: tupla_recebida = json.loads(data.decode())
 File "/usr/lib/python3.5/json/__init__.py", line 319, in loads
 return _default_decoder.decode(s)
 File "/usr/lib/python3.5/json/decoder.py", line 339, in decode
 obj, end = self.raw_decode(s, idx=_w(s, 0).end())
 File "/usr/lib/python3.5/json/decoder.py", line 355, in raw_decode
 obj, end = self.scan_once(s, idx)
json.decoder.JSONDecodeError: Unterminated string starting at: line 1 column 7 (char 6)

  • You can display the sff code. Place it here sff http://ideone.com/ . Both client and server side

  • Server: http://ideone.com/DhFl35 Client: http://ideone.com/4sutJ1

  • @Ricardomendes, but in that code you showed me, you don’t make use of this I put in the answer. You may not bytecode json, https://docs.python.org/2/library/json.html#encoders-and-decoders these are the types of data you can put into a json string. In my answer I’m not using json, but I could, it would be more work but could

Show 2 more comments

Browser other questions tagged

You are not signed in. Login or sign up in order to post.