How, in Python 3, can I have a client open a socket to a server, send 1 line of JSON-encoded data, read 1 line JSON-encoded data back, and continue?

Question:

I have the following code for a server listening on a port:

    def handle_oracle_query(self, sock, address):
        sockIn = sock.makefile('rb')
        sockOut = sock.makefile('wb')
        line = sockIn.readline()
        submitted_data = json.loads(line)
        self.get_thread_specific_storage()['environmental_variables'] = submitted_data['environmental_variables']
        self.get_thread_specific_storage()['cgi'] = submitted_data['cgi']
        generate_output()
        print_output(sockOut)
        sock.close()
        sockIn.close()
        sockOut.close()
        self.remove_thread_specific_storage()

I am attempting to connect to it with the client below:

        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        ip = server[0]
        try:
            port = int(server[1])
        except:
            port = DEFAULT_PORT
        sock.connect((ip, port))
        sockIn = sock.makefile("rb")
        sockOut = sock.makefile("wb")
        cgi_hash = {}
        for key in cgi.FieldStorage().keys():
            cgi_hash[key] = cgi.FieldStorage()[key].value
        as_dictionary = dict(os.environ)
        submitted_data = {
          'environmental_variables': as_dictionary,
          'cgi': cgi_hash}
        encoded_data = json.dumps(submitted_data)
        sys.stderr.write(encoded_data + 'rn')
        sockOut.write(encoded_data + 'rn')
        sockOut.flush()
        result = json.loads(sockIn.read())
        sock.close()
        sockIn.close()
        sockOut.close()

When I try to connect with the server I get the following stacktrace:

Traceback (most recent call last):
  File "/home/christos/fathers/bin/./fathersd", line 4075, in <module>
    multitasking.start_oracle()
  File "/home/christos/fathers/bin/./fathersd", line 2396, in start_oracle
    self.run_oracle()
  File "/home/christos/fathers/bin/./fathersd", line 2372, in run_oracle
    self.handle_oracle_query(newsocket, address)
  File "/home/christos/fathers/bin/./fathersd", line 2309, in handle_oracle_query
    submitted_data = json.loads(line)
  File "/usr/lib/python3.10/json/__init__.py", line 346, in loads
    return _default_decoder.decode(s)
  File "/usr/lib/python3.10/json/decoder.py", line 337, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
  File "/usr/lib/python3.10/json/decoder.py", line 355, in raw_decode
    raise JSONDecodeError("Expecting value", s, err.value) from None
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)

What changes should I be making to the above code in the client and/or server so the client sends a single line of input containing a JSON string and the server, after constructing the output, returns a single line of output containing a JSON string of output which the client can parse and work from there?

I am in the process of porting an application to Python 3. I would like a character encoding of UTF-8.

Asked By: Christos Hayward

||

Answers:

The problem here is at the client, not the server. Maybe you should take a look at your client’s output, you would get an error in line sockOut.write(encoded_data + 'rn'), because your sockOut is a binary interface (you created it as a wb and not w), so it requires a bytes object, not a string.

You can convert a string to bytes using .encode(), like sockOut.write((encoded_data + 'rn').encode()). You should take a look at the code where the server sends the response, if you did the same thing there.

And by the way: You can change 'rn' to 'n', because a new line is just a n character on every unix-like system, and python will also detect a new line by n. rn is a windows thing, but it’s not the standard way for new lines. Just wanted to mention that, but you can also leave it as it is.

Answered By: axolotlKing0722

Just change wb to w and rb to r when creating the socket IOs. You are working with strings, but "wb" stands for "write bytes" and expect a bytes object.

Answered By: blueSheesh
Categories: questions Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.