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