python网络编程(gtp报文发送案例)


1、python网络编程的实现过程:

python网络编程通过socket实现。

(1)通过socket.socket( , )创建套接字,具体分为TCP编程(tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM))和UDP编程(udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)),我用的是udp通信;

(2)将socket套接字绑定源地址(源地址最好设置接受输入而避免不断修改脚本,包括源IP和源端口),udp_socket.bind((srcIP, srcPort));

(3)接受待发送的消息(消息需要进行encode()编码,我这里传入的消息是函数生成的gtp报文字节流);

(4)向目的地址(目的地址接受输入,包括目的IP和目的端口)发送消息,socket.sendto(gtpDatagram, (dstIP, dstPort))

(5)发完消息,关闭套接字,释放端口。

2、gtp报文的生成:

重点讲一下gtp报文(需要发送的消息)的生成。

(1)根据输入字段确定需要发送的gtp报文版本(gtpv1或gtpv2,gtp版本不同对应的gtp头的格式不同),根据版本选择使用哪个gtp生成器;

(2)根据输入字段,匹配获取gtp头的详细信息,主要包括消息类型、teid、seqNo(gtp头的详细格式可自行查询);

(3)按照gtp头的格式进行字段编码,可使用python的struct包里的pack()函数进行编码,例如struct.pack('!BHI6s',  ,  ,  , '      '),这里‘!’代表网络通信的字节存储按照大端存储,B代表将整数编码为1字节,H代表将整数编码为2字节,I代表将整数编码为4字节。struct.pack()得到的是bytes类型,可利用‘+’进行拼接。gtp数据部分可利用str.encode()进行编码,默认utf-8.***这里还有一个小问题就是struct.pack()无法将整数编码为大于1的奇数个字节,比如gtpv2的seqNo需要编码为3个字节,这里我的处理方法是通过对256(即2的8次方)取余和取整得到每个字节上代表的数值,然后再分别按照单字节编码后进行拼接***,其他需要编码为奇数个字节的整数可类似处理。

(4)gtp头编码完成后,与编码的数据进行拼接,得到gtp数据报,然后传给udp_socket进行发送。

3、关于发送消息的相关输入:

源地址、目的地址、使用的gtp版本以及相关gtp头信息等可以在每次运行脚本的时候输入(略显麻烦)。也可以将相关输入按格式写入文本文件中,一次处理文本中的所有信息。这里我使用的是txt文件。

指定文本编辑格式,例如:

srcIP srcPort dstIP dstPort gtpVersion messageType Teid seqNo
127.0.0.1 10022 127.0.0.1 10023 1 16 0 0
127.0.0.1 10022 127.0.0.1 10023 2 32 0 0

 

 

 

然后通过python的open()函数打开文件,按行读取每行信息,在脚本中进行字段匹配即可。(这里需要跳过第一行,可以导入itertools中的islice(),从指定行开始读取)。

当然文本也可以编辑成其他格式,如json文本。

4、关于输入信息合法性的问题:

网络协议通信中经常需要判断协议规范的问题,即发送的消息格式是否合法。这里建议在接收字段的过程中进行合法性的判断,若某个字段不合法,则打印异常日志以便于定位错误,并终止当前行的数据读取,读取下一行。

5、gtp报文发送示例代码:

 1 # -*- coding: utf-8 -*-
 2 """
 3 Created on Tue Aug 13 19:41:42 2019
 4 
 5 @author: wulei
 6 """
 7 
 8 #支持输入源IP和目的IP
 9 
10 import socket
11 import struct
12 #import re
13 from itertools import islice
14 
15 #定义UDP客户端函数
16 def udp_client():
17     
18     #读取数据文本,引号内输入数据文本路径
19     file = open(r'C:\Users\17974\Desktop\data2.txt')
20     #跳过第1行读取发送信息
21     for data in islice(file, 1, None):
22     #for data in open(r'C:\Users\w50005151\Desktop\data.txt'):
23         #split默认以任意多个空格分割字符串,并获得发送信息列表(切片)
24         dataList = data.split()
25         #按顺序匹配列表中的数据信息
26         srcIP = dataList[0]
27         srcPort = int(dataList[1])
28         dstIP = dataList[2]
29         dstPort = int(dataList[3])
30         gtpVersion = int(dataList[4])
31         messageType = int(dataList[5])
32         teid = int(dataList[6])
33         seqNo = int(dataList[7])
34         clientAddr = (srcIP, srcPort)
35         severAddr = (dstIP, dstPort)
36         #创建套接字udp_socket,其中AF_INET表示IPv4,SOCK_DGRAM表示UDP
37         udpClient_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
38         #绑定客户端地址(源地址)
39         udpClient_socket.bind(clientAddr)
40         ##获取待发送的gtp报文
41         if gtpVersion == 1:                                                      #生成gtpv1报文
42             data_send = gtpv1Generator(messageType, teid, seqNo)
43         elif gtpVersion == 2:
44             data_send = gtpv2Generator(messageType, teid, seqNo)                 #生成gtpv2报文
45         else:
46             print('消息类型错误!')
47             continue
48         #向目的地址发送gtp报文
49         udpClient_socket.sendto(data_send, severAddr)
50         print('发送完成!')
51         udpClient_socket.close()
52 
53 def gtpv1Generator(messageType, teid, seqNo):
54     print('正在生成GTPv1数据报!')                            #目前设为空
55     #gtpDatagram = ''.encode()
56     gtpVersion = '001'                                    #固定
57     protocal = '1'                                        #固定
58     reserve = '0'                                         #固定
59     extension = '0'                                       #0或1
60     sequence = '1'                                        #0或1
61     PN = '0'                                              #0或1
62     byte1 = int(gtpVersion + protocal + reserve + extension + sequence + PN, 2)  #1字节
63     #messageType = 16                                                             #1字节
64     payLoadLen = 4 + 84                                          #占2字节,84为数据长度,应该是用len()求
65     #Teid = 0                                                              #占4字节
66     #seqNo = 0                                                   #占2字节
67     exHeader = 0                                                 #占2字节
68     gtpv1Datagram = struct.pack('!BBHIHH', byte1, messageType, payLoadLen, teid, seqNo, exHeader) + b'\x02d\x00`f\x01\x00\x00\xf0\x0f\xfd\x10 \xa0\x0b\x84\x11\x0c\xfb\xd4\x87\x14\x07\x1a\x00\x01\x80\x00\x06\xf1!\x7f\x00\x00\x01\x83\x00\x07\x06ggsn61\x85\x00\x04\xb4\x16\x1fP\x85\x00\x04\xb4\x16 n\x86\x00\x07h1\t\x01\x00\x00\xf0\x87\x00\x0c\x02\rC\x1fQ\x04DD!B\x01\x01'
69     return gtpv1Datagram
70 
71 def gtpv2Generator(messageType, teid, seqNo):
72     print('正在生成GTPv2数据报!')
73     gtpVersion = '010'
74     p = '0'                                                     #是否搭载消息,0不搭载,1搭载
75     T = '1'                                                     #是否有TEID字段
76     MP = '0'                                                    #是否指定消息优先级
77     spare = '00'                                                #备用
78     byte1 = int(gtpVersion + p + T + MP + spare, 2)             #1字节
79     #messageType                                                #1字节
80     messageLen = 8 + 84                                         #2字节
81     #teid                                                       #4字节
82     #seqNo                                                      #3字节
83     #根据seqNo分别得到其三个字节的上的数
84     seqNo1 = seqNo//(2**16)
85     seqNo2 = (seqNo - seqNo1*2**16)//(2**8)
86     seqNo3 = seqNo%(2**8)
87     messagePrio = '0000'                                        #MP==0,则无优先级
88     Spare = '0000'                                              #备用
89     byteLast = int(messagePrio + Spare, 2)                      #1字节
90     gtpv2Datagram = struct.pack('!BBHIBBBB', byte1, messageType, messageLen, teid, seqNo1, seqNo2, seqNo3, byteLast) + b'\x02d\x00`f\x01\x00\x00\xf0\x0f\xfd\x10 \xa0\x0b\x84\x11\x0c\xfb\xd4\x87\x14\x07\x1a\x00\x01\x80\x00\x06\xf1!\x7f\x00\x00\x01\x83\x00\x07\x06ggsn61\x85\x00\x04\xb4\x16\x1fP\x85\x00\x04\xb4\x16 n\x86\x00\x07h1\t\x01\x00\x00\xf0\x87\x00\x0c\x02\rC\x1fQ\x04DD!B\x01\x01'
91     return gtpv2Datagram
92     
93 if __name__ == "__main__":
94     udp_client()

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM