Octopusghost
Octopusghost

Reputation: 79

Making a 'byte type object' in python 3

I currently have a server running under this code:

    import socket                   


port = 60000                  
s = socket.socket()             
host = socket.gethostname()    
s.bind((host, port))           
s.listen(1)                     

print ('Server listening....')

while True:
    conn, addr = s.accept()     
    print ('Got connection from', addr)
    data = conn.recv(1024)
    print('Server received', repr(data))

    filename='mytext.txt'
    f = open(filename,'rb')
    l = f.read(1024)
    while (l):
       conn.send(l)
       print('Sent ',repr(l))
       l = f.read(1024)
    f.close()

    print('Done sending')
    conn.send('Thank you for connecting')
    conn.close()

And a client running under this code:

import socket

    s = socket.socket()              
host = socket.gethostname()      
port = 60000                    

    s.connect((host, port)) 
    s.send('Test')

with open('received_file', 'wb') as f:
    print ('file opened')
    while True:
        print('receiving data...')
        data = s.recv(1024)
        print('data=%s', (data))
        if not data:
            break
        # write data to a file
        f.write(data)

    f.close() 
print('Successfully get the file') 
s.close()

     print('connection closed')

The problem is that the when the client attempts to send the data it says that the data sent must be a byte-type object (Error code shown here: https://gyazo.com/97ef155f6809a801b02f381670895a2b.) I have searched the internet for an answer of how to create a byte type object inside of Python 3, but I have failed to find anything that has worked.

Upvotes: 1

Views: 237

Answers (2)

abarnert
abarnert

Reputation: 365925

If you’re just sending literals, you can just use a bytes literal instead of a str literal, by prefixing it with a b. Instead of this:

sock.send('Hello')

… just do this:

sock.send(b'Hello')

If you’re sending string variables, you will want to encode them for sending, and probably decode them on receiving. Instead of this:

sock.send(msg)
resp = sock.recv(4096)

… do:

sock.send(msg.encode('ascii')
resp = sock.recv(4096).decode('ascii')

If you want to send non-ASCII strings, you’ll need to pick an encoding. Unless you have a good reason to do otherwise, use UTF-8.


One more thing to keep in mind: TCP sockets are just streams of bytes, not messages, and they can be split up arbitrarily into packets. When you can recv(1024), you may only get part of what the other side sent with send. That’s probably obvious if you’re sending strings longer than 1024 bytes, but even for shorter strings, it can happen. Or, if you’re not strictly alternating sends and receives, you can get multiple sends concatenate into a single receive. And if you send hello and then world and receive them as helloworld you have no way to know that happened, or how to split them back up.

And, worse, it probably won’t happen when you’re testing on localhost on an idle machine, so things will look good during development, but then fail mysteriously all over the place once you deploy it somewhere.

So, you need some protocol that describes where one message ends and another begins. I have a blog post that explains some options, and shows how to implement them.

But if you’re just sending human-readable strings as messages, and those strings will never contain newlines, the simplest protocol is just a line for every message, the same way you’d write a text file. And look at socket.makefile: it gives you something that acts just like a file, handles the one line for every message protocol, and also automatically handles the encode and decode parts. So, instead of this:

sock.send(msg.encode('utf-8'))
resp = sock.recv(1024).decode('utf-8')

… you just do use makefile to get readable and writable file objects, then do:

wf.write(msg + '\n')
resp = next(rf)

… and then you don’t have to worry about how to buffer up the receives and split them into messages.

Upvotes: 2

Evandro de Paula
Evandro de Paula

Reputation: 2642

Change the client code line:

s.send('Test')

to:

s.send(b'Test')

Find more details about socket.send() at https://docs.python.org/3/library/socket.html.

Upvotes: 1

Related Questions