如何截獲安卓報文
Ⅰ android udp接收不到數據
1、可先在oncreate()方法裡面實例化一個WifiManager.MulticastLock 對象lock;具體如下:
WifiManager manager = (WifiManager) this
.getSystemService(Context.WIFI_SERVICE);
WifiManager.MulticastLock lock= manager.createMulticastLock("test wifi");
2、在調用廣播發送、接收報文之前先調用lock.acquire()方法;
3、用完之後及時調用lock.release()釋放資源,否決多次調用lock.acquire()方法,程序可能會崩,詳情請見
Caused by: java.lang.UnsupportedOperationException: Exceeded maximum number of wifi locks
注;記得在配置文件裡面添加如下許可權:
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />
經過這樣處理後,多數手機都能正常發送接收到廣播報文。
本小點轉載自Android手機接收不到UDP報文
二、在UDP通信中,android端發送UDP廣播包沒有問題。至於接收的話,有時候不能接收到包。
在UDP通信中,android端發送UDP廣播包沒有問題。至於接收的話,有時候不能接收到包。但是如果UDP包中指定了目標主機的地址的話,那麼android端就能正常接收。
下面上一段代碼,大家可用這段代碼進行測試。
1、在一個Service裡面,我們創建一個線程
public void onCreate() {//用於創建線程
WifiManager manager = (WifiManager) this
.getSystemService(Context.WIFI_SERVICE);
udphelper = new UdpHelper(manager);
//傳遞WifiManager對象,以便在UDPHelper類裡面使用MulticastLock
udphelper.addObserver(MsgReceiveService.this);
tReceived = new Thread(udphelper);
tReceived.start();
super.onCreate();
}
2、弄一個UDP幫助類,這個類主要用於發送和接收數據
package com.example.com.ihome.bang.util;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Observable;
import com.example.com.ihome.bang.tool.SendThread;
import android.net.wifi.WifiManager;
import android.util.Log;
/**
*
* UdpHelper幫助類
*
* @author 陳喆榕
*
*/
public class UdpHelper implements Runnable {
public Boolean IsThreadDisable = false;//指示監聽線程是否終止
private static WifiManager.MulticastLock lock;
InetAddress mInetAddress;
public UdpHelper(WifiManager manager) {
this.lock= manager.createMulticastLock("UDPwifi");
}
public void StartListen() {
// UDP伺服器監聽的埠
Integer port = 8903;
// 接收的位元組大小,客戶端發送的數據不能超過這個大小
byte[] message = new byte[100];
try {
// 建立Socket連接
DatagramSocket datagramSocket = new DatagramSocket(port);
datagramSocket.setBroadcast(true);
DatagramPacket datagramPacket = new DatagramPacket(message,
message.length);
try {
while (!IsThreadDisable) {
// 准備接收數據
Log.d("UDP Demo", "准備接受");
this.lock.acquire();
datagramSocket.receive(datagramPacket);
String strMsg=new String(datagramPacket.getData()).trim();
Log.d("UDP Demo", datagramPacket.getAddress()
.getHostAddress().toString()
+ ":" +strMsg );this.lock.release();
}
} catch (IOException e) {//IOException
e.printStackTrace();
}
} catch (SocketException e) {
e.printStackTrace();
}
}
public static void send(String message) {
message = (message == null ? "Hello IdeasAndroid!" : message);
int server_port = 8904;
Log.d("UDP Demo", "UDP發送數據:"+message);
DatagramSocket s = null;
try {
s = new DatagramSocket();
} catch (SocketException e) {
e.printStackTrace();
}
InetAddress local = null;
try {
local = InetAddress.getByName("255.255.255.255");
} catch (UnknownHostException e) {
e.printStackTrace();
}
int msg_length = message.length();
byte[] messageByte = message.getBytes();
DatagramPacket p = new DatagramPacket(messageByte, msg_length, local,
server_port);
try {
s.send(p);
s.close();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void run() {
StartListen();
}
}
希望能幫到你。
Ⅱ Android 中流量,電量,弱網環境怎麼測
用Charles工具做弱網的測試,或者模擬2G、3G的網路情況。
通過抓包是流量測試直接的方法。在App運行器件,把手機收發的所有報文抓取下來,在計算收發報文總大小,即app消耗的流量。如果我們需要測試某個app消耗 的流量需要禁用其他app的連網許可權。
1)限制其他app的連網許可權,因為有些app的進程是常駐後台的,即使不運行,也會有網路報文。可以藉助一些手機管家軟體禁用網路。
2)手機上抓包,下載tcpmp,手機鏈接電腦,獲得root許可權
3)將tcpmp(forAndroid)上傳至android手機上,在命令提示符窗口中輸入命令:adbpush <LocalPath of tcpmp> /data/local/tcpmp
4)給tcpmp增加可執行許可權
adb shell
su
chmod 6755 /data/local/tcpmp
5)啟動抓包,使用命令/data/local/tcpmp-v -i any -s 0 -w /sdcard/zhangyu.pcap
Got後面的數字表示當前抓到的包的數量。如果有變化,表示有網路流量
6)導出抓包結果adb pull /sdcard/zhangyu.pcap <LocalPathof PcapFile >
7)用Wireshark打開剛才的抓包結果,點擊StatisticsàSummary,流量的數值為Bytes一行的Displayed一欄。
Ⅲ android藍牙BLE(三) —— 廣播
在藍牙開發中,有些情況是不需要連接的,只要外設廣播自己的數據即可,例如蘋果的 ibeacon 。自 Android 5.0 更新藍牙API後,手機可以作為外設廣播數據。
廣播包有兩種:
其中 廣播包是每個外設都必須廣播的,而響應包是可選的 。每個廣播包的長度必須是 31個位元組 ,如果不到 31個位元組 ,則剩下的全用 0 填充 補全,這部分的數據是無效的
廣播包中包含若干個廣播數據單元,廣播數據單元也稱為 AD Structure 。
廣播數據單元 = 長度值Length + AD type + AD Data。
長度值 Length 只佔 一個位元組 ,並且位於廣播數據單元的 第一個位元組 。
概念的東西有些抽象,先看看下面的廣播報文:
0x代表這串字元串是十六進制的字元串。 兩位十六進制數代表一個位元組 。因為兩個字元組成的十六進制字元串最大為 FF ,即255,而Java中byte類型的取值范圍是-128到127,剛好可以表示一個255的大小。所以兩個十六進制的字元串表示一個位元組。
繼續查看報文內容,開始讀取第一個廣播數據單元。讀取 第一個 位元組: 0x07 ,轉換為十進制就是7,即表示後面的7個位元組是這個廣播數據單元的數據內容。超過這7個位元組的數據內容後,表示是一個新的廣播數據單元。
而第二個廣播數據單元,第一個位元組的值是 0x16 ,轉換為十進制就是22,表示後面22個位元組為第二個廣播數據單元。
在廣播數據單元的 數據部分 中, 第一個位元組 代表 數據類型 (AD type),決定數據部分表示的是什麼數據。(即廣播數據單元第二個位元組為AD type)
AD Type 的類型如下:
這bit 1~7分別代表著發送該廣播的藍牙晶元的物理連接狀態。當bit的值為1時,表示支持該功能。
例:
藍牙廣播的數據格式大致講了一下,有助於下面的廣播操作的理解。
先看看廣播設置( AdvertiseSettings )如何定義:
(1)、通過 AdvertiseSettings.Builder#setAdvertiseMode() 設置廣播模式。其中有3種模式:
(2)、通過 AdvertiseSettings.Builder#setAdvertiseMode() 設置廣播發射功率。共有4種功率模式:
(3)、通過 AdvertiseSettings.Builder#setTimeout() 設置持續廣播的時間,單位為毫秒。最多180000毫秒。當值為0則無時間限制,持續廣播,除非調用 BluetoothLeAdvertiser#stopAdvertising() 停止廣播。
(4)、通過 AdvertiseSettings.Builder#setConnectable() 設置該廣播是否可以連接的。
之前說過,外設必須廣播廣播包,掃描包是可選。但添加掃描包也意味著廣播更多得數據,即可廣播62個位元組。
可見無論是廣播包還是掃描包,其廣播的內容都是用 AdvertiseData 類封裝的。
(1)、 AdvertiseData.Builder#setIncludeDeviceName() 方法,可以設置廣播包中是否包含藍牙的名稱。
(2)、 AdvertiseData.Builder#setIncludeTxPowerLevel() 方法,可以設置廣播包中是否包含藍牙的發射功率。
(3)、 AdvertiseData.Builder#addService UUID (Parcel UUID ) 方法,可以設置特定的 UUID 在廣播包中。
(4)、 AdvertiseData.Builder#addServiceData(Parcel UUID ,byte[]) 方法,可以設置特定的 UUID 和其數據在廣播包中。
(5)、 AdvertiseData.Builder#addManufacturerData(int,byte[]) 方法,可以設置特定廠商Id和其數據在廣播包中。
從 AdvertiseData.Builder 的設置中可以看出,如果一個外設需要在不連接的情況下對外廣播數據,其數據可以存儲在 UUID 對應的數據中,也可以存儲在廠商數據中。但由於廠商ID是需要由Bluetooth SIG進行分配的,廠商間一般都將數據設置在廠商數據。
另外可以通過 BluetoothAdapter#setName() 設置廣播的名稱
先看一個例子,我們分別在 廣播包 和 掃描包 中設置 AdvertiseData.Builder 的 每一種廣播報文參數 ,得到一下報文內容:
(1)、Type = 0x01 表示設備LE物理連接。
(2)、Type = 0x09 表示設備的全名
(3)、Type = 0x03 表示完整的16bit UUID 。其值為0xFFF7。
(4)、Type = 0xFF 表示廠商數據。前兩個位元組表示廠商ID,即廠商ID為0x11。後面的為廠商數據,具體由用戶自行定義。
(5)、Type = 0x16 表示16 bit UUID 的數據,所以前兩個位元組為 UUID ,即 UUID 為0xF117,後續為 UUID 對應的數據,具體由用戶自行定義。
最後繼承 AdvertiseCallback 自定義廣播回調。
初始化完畢上面的對象後,就可以進行廣播:
廣播主要是通過 BluetoothLeAdvertiser#startAdvertising() 方法實現,但在之前需要先獲取 BluetoothLeAdvertiser 對象。
BluetoothLeAdvertiser 對象存在兩個情況獲取為Null:
所以在調用 BluetoothAdapter#getBluetoothLeAdvertiser() 前,需要先調用判斷藍牙已開啟,並判斷在 BluetoothAdapter 中獲取的 BluetoothLeAdvertiser 是否為空(測試過某些華為手機 mBluetoothAdapter.() 為 false , 但是能發送ble廣播)。
與廣播成對出現就是 BluetoothLeAdvertiser.stopAdvertising() 停止廣播了,傳入開啟廣播時傳遞的廣播回調對象,即可關閉廣播:
雖然通過廣播告知外邊自身擁有這些Service,但手機自身並沒有初始化Gattd的Service。導致外部的中心設備連接手機後,並不能找到對應的 GATT Service 和 獲取對應的數據。
Service類型有兩個級別:
創建 BluetoothGattService 時,傳入兩個參數: UUID 和Service類型:
我們都知道Gatt中, Service 的下一級是 Characteristic , Characteristic 是最小的通信單元,通過對 Characteristic 進行讀寫操作來進行通信。
特徵屬性表示該 BluetoothGattCharacteristic 擁有什麼功能,即能對 BluetoothGattCharacteristic 進行什麼操作。其中主要有3種:
許可權屬性用於配置該特徵值所具有的功能。主要兩種:
Characteristic 下還有 Descriptor ,初始化 BluetoothGattDescriptor 時傳入: Descriptor UUID 和 許可權屬性
為 Service 添加 Characteristic ,為 Characteristic 添加 Descriptor :
通過藍牙管理器 mBluetoothManager 獲取 Gatt Server ,用來添加 Gatt Service 。添加完 Gatt Service 後,外部中心設備連接手機時,將能獲取到對應的 GATT Service 和 獲取對應的數據
定義 Gatt Server 回調。當中心設備連接該手機外設、修改特徵值、讀取特徵值等情況時,會得到相應情況的回調。
最後開啟廣播後,用nRF連接後看到的特徵值信息如下圖所示:(加多了一個只能都的特徵值)
android藍牙BLE(一) —— 掃描
android藍牙BLE(二) —— 通信
android藍牙BLE(三) —— 廣播
android藍牙BLE(四) —— 實戰