Search code examples
pythonsocketsdecodeencode

Python 3 Socket, can't receive data (encode, decode)


I have a game and I was working with some networking to make it multiplayer. I created a custom module (not the best in any way), to convert two values (XY) from -1048576 to +1048576 and a value from 0 to 60 (health), into 6 characters. So in 6 bytes I could send all that information.

But this was working in Python 2, in Python 3 I discovered that I couldn't send a 'str' with the characters, so I used the '.encode()' before sending it and '.decode()' before using it in any of my functions. But that doesn't seem to work.

I not really sure to do. Any help?

Module:

#IMPORT MODULES
from sys import version_info

#------------------------------------------------------------------------------

#FUNTIONS
#Binary String to Characters
def BinToMsg(text):
    if version_info[0] <= 2: return "".join(chr(int(text[i:i+8], 2)) for i in range(0, len(text), 8))
    else:
        data = "".join(chr(int(text[i:i+8], 2)) for i in range(0, len(text), 8))
        return data.encode()

#Characters to Binary String
def MsgToBin(text):
    if version_info[0] <= 2: return "".join('{:08b}'.format(ord(c)) for c in text)
    else:
        text = text.decode()
        return "".join('{:08b}'.format(ord(c)) for c in text)

#Corrects 0's values in Binary Strings
def fixDigit(text, digits):
    lenth = digits - len(text)
    for loop in range(lenth): text = "0" + text
    return text

#Data to Characters
def DataToMsg(x,y,health):

    if health >= 2**6 or health < 0: return None
    bins = fixDigit(bin(health)[2:],6)
    for cord in (x,y):
        if cord >= 2**20: return None
        if cord < 0: bins += "0"
        else: bins += "1"
        bins += fixDigit(bin(int(str(cord).replace("-","")))[2:],20)

    return BinToMsg(bins)

#Characters to Data
def MsgToData(msg):

    bins = MsgToBin(msg)
    data = {"Health":int(bins[:6],2)}
    data["X"] = int(bins[7:27],2)
    data["Y"] = int(bins[28:48],2)
    if bins[6] == "0": data["X"] *= -1
    if bins[27] == "0": data["Y"] *= -1

    return data

This would be used like this...

Player = {"X":-1234,"Y":5678,"Health":23}
...
connection.send(DataToMsg(Player["X"],Player["Y"],Player["Health"]))
...
print(MsgToData(connection.recv(6))
...
Output: {"X":-1234,"Y":5678,"Health":23}

Solution

  • When the String is encoded in UTF-8 (default encoding) the length increases. So if you set your connection.recv() to 6, it wouldn't not receive all the information. Just some chopped to pieces. So when you decode it it give you an error.

    To maintain the same length I found useful to encode it to "cp037".

    Usage

    string.encode("cp037")
    ...
    string.decode("cp037")