Python 3 garbage data into the struct.unpack - python

I am trying to send and receive messages via socket using Python 3.
BUFFER_SIZE = 1024
# Create message
MLI = struct.pack("!I", len(MESSAGE))
MLI_MESSAGE = MLI + str.encode(MESSAGE)
When the message receive:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((TCP_IP, TCP_PORT))
s.send(MLI_MESSAGE)
print ("Sent data: ‘", MESSAGE, "’")
# Receive MLI from response (you might want to add some timeout handling as well
resp = s.recv(BUFFER_SIZE)
resp = struct.unpack("!I", resp)[0]
print(resp)
resp:
b'\x00\t\xeb\x07\xdf\x01\x00\xdf\x02\x010'
I am getting that error:
struct.error: unpack requires a buffer of 4 bytes
I think it is related with \t char into the resp but I am not sure. How can I remove that \t char and how to solve that issue?

You are basically trying to do the following (sockets removed):
1 import struct
2
3 msg = "foobar"
4 mli = struct.pack("!I", len(msg))
5 mli_msg = mli + str.encode(msg)
6
7 len = struct.unpack("!I", mli_msg)[0]
8 print(len)
The extraction of the length in line 7 will fail since you put the whole mli_msg as argument to unpack, not only the expected 4 bytes for the len. Instead you should do:
7 len = struct.unpack("!I", mli_msg[:4])[0]
Apart from that it is wrong to first take the length of the message and then convert the message to bytes. The first takes the number of characters while the latter takes the number of bytes, which will differ when non-ASCII characters are involved - check len("ü") vs. len(str.encode("ü")). You need to first convert the message to bytes thus and then take the length to provide the correct byte length for what you send.
4 encoded_msg = str.encode(msg)
5 mli_msg = struct.pack("!I", len(encoded_msg)) + encoded_msg

Explanation of !I:
! indicates big endian alignment
I indicates unsigned integer type, occupying 4 bytes.
The variable resp value is b'\x00\t\xeb\x07\xdf\x01\x00\xdf\x02\x010', and the length exceeds 4.
You can intercept 4 bytes for parsing, like below.
import struct
resp = b'\x00\t\xeb\x07\xdf\x01\x00\xdf\x02\x010'
print(struct.unpack("!I", resp[:4])[0])
# 649991

Related

Problem with the delimiter of data packet

The following example reads data from the UART. In my case, the delimiter where packet starts with b '\x02' everything works, but the problem appears when b '\x02' appears in the packet and it is not the beginning of the packet because uart data often comes in one string. I will add that the packet that needs to be read always starts with b '\x02\x84' the only question is how to check if the first byte b '\x02’ followed by b '\x84' and if so then do a split.
Sample package consisting of several and with the problem:
\x02\x84"\x00\x19\x03\x00l\xe0\x02D\x00\x02\x84"\x00\x19\x03\x00l
I want to get two as handle_packet:
b'\x84"\x00\x19\x03\x00l\xe0\x02D\x00'
b'\x84"\x00\x19\x03\x00l'
rx_buff = bytes()
while True:
recv = reader.read(-1)
if not recv:
continue
rx_buff += recv
packets = rx_buff.split(bytes(b'\x02'))
for packet in packets:
if not packet:
continue
msg = mod.handle_packet(packet)
if (msg):
get_response(msg)
rx_buff = (bytes() if mod.handle_packet(packet) else packet)
I spent a little more time reading. If you do it this way, your problem is going to be the first packet you split, because, I am assuming it doesn't follow the splitting pattern b'\x02\x84". If that is the case, you can just take the first of split_bytes and remove the first byte.
my_bytes = b'\x02\x84"\x00\x19\x03\x00l\xe0\x02D\x00\x02\x84"\x00\x19\x03\x00l'
split_bytes = my_bytes.split(b'\x02\x84"')
packets = []
for e in split_bytes:
if e != b'':
packets.append(b'\x84"' + e)
print(packets)
Yields:
[b'\x84"\x00\x19\x03\x00l\xe0\x02D\x00', b'\x84"\x00\x19\x03\x00l']
Your desired packets:
[b'\x84"\x00\x19\x03\x00l\xe0\x02D\x00', b'\x84"\x00\x19\x03\x00l']
If I am missing something, please point it out.

How to wait for a large number packet erminator pyserial

I am debugging packets sent from a device with pyserial. The packets have a specific terminator pattern to differentiate between packets of data. The pattern is a large number (0x3423fe67). I am able to receive bytes and concatenate them as they come in with the code below.
ser = serial.Serial(
ports="/dev/ttyUSB0",
baudrate=115200,
parity=serial.PARITY_NONE,
stopbits=serial.STOPBITS_ONE,
bytesize=serial.EIGHTBITS
)
y = b''
while True:
bytes = ser.inWaiting()
if bytes > 0:
x = ser.read(bytes)
y += binascii.hexify(x)
print(y)
I can see the pattern I'm looking for but how do I grab the packet and terminator once I see the terminator. I tried indexing the bytes object but that returns strange values. Everything received before the terminator is part of the packet.
Here is code that accumulates packets in a list. The code can be used as a guide.
The serialData is data that would be received over the serial port as an example (i.e. ser.read() which would replace the for piece in x: loop). Note that an arbitrary number of bytes can be received, and the test variable n is only used to test the algorithm at arbitrary incoming received character lengths.
The term variable needed hexlify to match the hexlify on the incoming data.
import binascii
import re
term = binascii.hexlify(b'\x34\x23\xfe\x67')
serialData = b'packet0\x34\x23\xfe\x67packet1\x34\x23\xfe\x67'
n = 5
x = [serialData[i:i+n] for i in range(0, len(serialData), n)]
y = b''
packets = []
for piece in x:
y += binascii.hexlify(piece)
for i in re.finditer(term, y):
packets.append(y[:i.start()])
y = y[i.end():]
print('packets = ', packets)

Python Memorybuffer pywin32

I got some code:
def get_text(self, id):
edit_hwnd = win32gui.GetDlgItem(self.hwnd, id) # 获取窗口句柄
time.sleep(0.2)
self.edit_hwnd = edit_hwnd
length = win32api.SendMessage(
edit_hwnd, win32con.WM_GETTEXTLENGTH) + 1 # 获取窗体内容长度
buf = win32gui.PyMakeBuffer(length) # 准备buffer对象作为容器
win32gui.SendMessage(edit_hwnd, win32con.WM_GETTEXT,
length, buf) # 获取窗体内容放入容器
try:
address, length = win32gui.PyGetBufferAddressAndLen(buf) # 获取容器的内存地址
except ValueError:
print('error')
return
text = win32gui.PyGetString(address, length) # 取得字符串
buf.release()
del buf
return text
This function for get string at windows.I need to while this func to always get this value.When the value changed,i do something.But now when i done this while,my program exit with error code C000005.How can i fix it.
buf.release()
del buf
It's i added when i found this problem.It look like does't work.
The messages WM_GETTEXTLENGTH returns the length of the text in characters (excluding the terminating null character) and the maximum buffer length given to WM_GETTEXT also is based on characters (including the terminating null character).
A character in the NT-based Windows systems is encoded in a double-byte character set (DBCS), meaning two bytes per character.
The function win32gui.PyMakeBuffer(length) returns a buffer of length bytes.
So if length is the return value of WM_GETTEXTLENGTH, the reserved buffer should be length * 2 + 2 bytes long and the maximum buffer length given to WM_GETTEXT should be length + 1.

how to send an hexadecimal from python to the UART?

I need to understand how to send a message in hexadecimal format from UART for example:
msg='99' +'70b4c55ad8cdb7806a7b043069c4e0d8'
'99'is to distinct the start of message and the rest is the data.
As
import serial
import time
#serial port
ser = serial.Serial(
port='COM4',\
baudrate=230400,\
parity=serial.PARITY_NONE,\
stopbits=serial.STOPBITS_ONE,\
bytesize=serial.EIGHTBITS,\
timeout=0)
msg=b'\x99\x70\xb4\xc5\x5a\xd8\xcd\xb7\x80\x6a\x7b\x04\x30\x69\xc4\xe0\xd8'
ser.write(msg)
time.sleep(0.4)
while True:
print(ser.read(30))
ser.close() # close ports
But i don't unerstand th error:
msg= b'\x99\x70\xb4\xc5\x5a\xd8\xcd\xb7\x80\x6a\x7b\x04\x30\x69\xc4\xe0\xd8'
^
IndentationError: unexpected indent
I need then to compare by using c langage, to compare the first received byte 99 with 0x99.
int lenght = dev_uart_ptr->uart_read((void*)buffer,34 );
if (lenght<34)
{
if buffer [0]='0x99'
}
Thanks in advance.
It seems like you are loading to buf but using buffer in your c code.
You are reading 34 bytes to the buffer, then checking if the length is less than 34. Shouldn't work well. And judging by your example, it should be 17.
Encode will not convert msg to hex string. It will treat every character as a char, i.e. '0' is 48, '1' is 49 etc
Create bytes object using
msg = b'\x99\x70\xb4\xc5\x5a\xd8\xcd\xb7\x80\x6a\x7b\x04\x30\x69\xc4\xe0\xd8'
ser.write(msg)

Python String Prefix by 4 Byte Length

I'm trying to write a server in Python to communicate with a pre-existing client whose message packets are ASCII strings, but prepended by four-byte unsigned integer values representative of the length of the remaining string.
I've done a receiver, but I'm sure there's a a more pythonic way. Until I find it, I haven't done the sender. I can easily calculate the message length, convert it to bytes and transmit the message.The bit I'm struggling with is creating an integer which is an array of four bytes.
Let me clarify: If my string is 260 characters in length, I wish to prepend a big-endian four byte integer representation of 260. So, I don't want the ASCII string "0260" in front of the string, rather, I want four (non-ASCII) bytes representative of 0x00000104.
My code to receive the length prepended string from the client looks like this:
sizeBytes = 4 # size of the integer representing the string length
# receive big-endian 4 byte integer from client
data = conn.recv(sizeBytes)
if not data:
break
dLen = 0
for i in range(sizeBytes):
dLen = dLen + pow(2,i) * data[sizeBytes-i-1]
data = str(conn.recv(dLen),'UTF-8')
I could simply do the reverse. I'm new to Python and feel that what I've done is probably longhand!!
1) Is there a better way of receiving and decoding the length?
2) What's the "sister" method to encode the length for transmission?
Thanks.
The struct module is helpful here
for writing:
import struct
msg = 'some message containing 260 ascii characters'
length = len(msg)
encoded_length = struct.pack('>I', length)
encoded_length will be a string of 4 bytes with value '\x00\x00\x01\x04'
for reading:
length = struct.unpack('>I', received_msg[:4])[0]
An example using asyncio:
import asyncio
import struct
def send_message(writer, message):
data = message.encode()
size = struct.pack('>L', len(data))
writer.write(size + data)
async def receive_message(reader):
data = await reader.readexactly(4)
size = struct.unpack('>L', data)[0]
data = await reader.readexactly(size)
return data.decode()
The complete code is here

Categories

Resources