Python sockets error TypeError: a bytes-like object is required, not 'str' with send function
Asked Answered
C

4

42

I am trying to create a program that will open a port on the local machine and let others connect into it via netcat. My current code is.

s = socket.socket()
host = '127.0.0.1'
port = 12345
s.bind((host, port))

s.listen(5)
while True:
    c, addr = s.accept()
    print('Got connection from', addr)
    c.send('Thank you for connecting')
    c.close()

I am new to Python and sockets. But when I run this code it will allow me to send a netcat connection with the command:

nc 127.0.0.1 12345

But then on my Python script I get the error for the c.send:

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

I am basically just trying to open a port, allow netcat to connect and have a full shell on that machine.

Carousel answered 5/3, 2017 at 18:5 Comment(2)
Have you tried encoding yet?Monde
No. I can comment out the c.send and it will run. Do you think that string needs to be encoded?Carousel
S
71

The reason for this error is that in Python 3, strings are Unicode, but when transmitting on the network, the data needs to be bytes instead. So... a couple of suggestions:

  1. Suggest using c.sendall() instead of c.send() to prevent possible issues where you may not have sent the entire msg with one call (see docs).
  2. For literals, add a 'b' for bytes string: c.sendall(b'Thank you for connecting')
  3. For variables, you need to encode Unicode strings to byte strings (see below)

Best solution (should work w/both 2.x & 3.x):

output = 'Thank you for connecting'
c.sendall(output.encode('utf-8'))

Epilogue/background: this isn't an issue in Python 2 because strings are bytes strings already -- your OP code would work perfectly in that environment. Unicode strings were added to Python in releases 1.6 & 2.0 but took a back seat until 3.0 when they became the default string type. Also see this similar question as well as this one.

Selfaggrandizement answered 5/3, 2017 at 19:17 Comment(1)
Thank you for this. This is very helpful and also answers my question.Carousel
O
14

You can decode it to str with receive.decode('utf_8').

Orle answered 5/7, 2017 at 16:21 Comment(0)
H
11

You can change the send line to this:

c.send(b'Thank you for connecting')

The b makes it bytes instead.

Horseleech answered 5/3, 2017 at 18:28 Comment(0)
J
0

An alternative solution is to introduce a method to the file instance that would do the explicit conversion.

import types

def _write_str(self, ascii_str):
    self.write(ascii_str.encode('ascii'))

source_file = open("myfile.bin", "wb")
source_file.write_str = types.MethodType(_write_str, source_file)

And then you can use it as source_file.write_str("Hello World").

Joachima answered 20/5, 2020 at 11:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.