Design of tcp packet protocol class by python

Keywords: encoding Programming Python

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.

Posted by scotchegg78 on Fri, 03 Jan 2020 11:00:51 -0800