1, Problem description
In tcp programming, the most important problem to be solved is packet sticking. Therefore, we need to add the length of each packet in front of each packet to divide the conglutinated packets.
2, Design of package structure
Package composition: package length + data field
Packet length: store the length of data field with 4 bytes, and the length of data field is the number of bytes it occupies
Data field: it is composed of several variables. If it is a fixed length variable, the variable length is not added
Fixed length variable: it is artificially specified that int in transmission is a fixed length variable of 4 bytes
Variable length: that's string
The words are hard to understand. Let me draw a picture:
The first line in the figure above is an overall structure of the data package
The second line is a structure inside the data field (the number and location of variables in the data field are all determined by ourselves, and the figure above is just an example)
The third line is the structure of specific variables
If you don't know the structure clearly, it doesn't matter. Let's give a specific example
For example, let's create a data field as follows:
Data field: 666, "hello", "hello",888
This data field stores four variables in total, two integer variables at the beginning and the end, and two string variables in the middle. Then the data package we built for this data field looks like this:
Now that you understand, let's see how to use python to encapsulate a class to implement the package assembly of the above structure.
3, Code implementation
class Protocol: """ //Regulations: //4 bytes of packet header //Integer takes up 4 bytes //String length bits in 2 bytes //Indefinite length of string """ def __init__(self, bs=None): """ //If bs is None, a packet needs to be created //Otherwise, it means that a packet needs to be parsed """ if bs: self.bs = bytearray(bs) else: self.bs = bytearray(0) def get_int32(self): try: ret = self.bs[:4] self.bs = self.bs[4:] return int.from_bytes(ret, byteorder='little') except: raise Exception("Data exception!") def get_str(self): try: # Get string byte length (string length bit 2 bytes) length = int.from_bytes(self.bs[:2], byteorder='little') # Take the string again ret = self.bs[2:length + 2] # Delete the extracted part self.bs = self.bs[2 + length:] return ret.decode(encoding='utf8') except: raise Exception("Data exception!") def add_int32(self, val): bytes_val = bytearray(val.to_bytes(4, byteorder='little')) self.bs += bytes_val def add_str(self, val): bytes_val = bytearray(val.encode(encoding='utf8')) bytes_length = bytearray(len(bytes_val).to_bytes(2, byteorder='little')) self.bs += (bytes_length + bytes_val) def get_pck_not_head(self): return self.bs def get_pck_has_head(self): bytes_pck_length = bytearray(len(self.bs).to_bytes(4, byteorder='little')) return bytes_pck_length + self.bs if __name__ == '__main__': p = Protocol() p.add_int32(666) p.add_str("How do you do") p.add_str("hello") p.add_int32(888) r = Protocol(p.get_pck_not_head()) print(r.get_int32()) print(r.get_str()) print(r.get_str()) print(r.get_int32())
The code is simple and not rigorous enough. You can modify it according to your own needs.