這兩天想實現PC和安卓手機的通訊,限於水平,知道的方法大概有兩種:基於資料包的socket和藍芽。雖然看起來簡單,但調也調了兩天多。自己測試了下socket,在室內WIFI環境下時延大概是0.1s。而在3G網路下時延居然達3s之多,而且只要不發資料,連接埠貌似就會斷掉,總之,很不爽。於是,便考慮了藍芽的方法。
實現手機和PC的藍芽通訊,一種是最常用的藍芽虛擬串口,這種方法可以通過配置非常簡單地實現,很多外置藍芽GPS都用這種做法。但大名鼎鼎的安卓卻不支援,因此對大部分外置GPS都不提供支援(可能安卓手機大部分包含內建GPS,覺得外置的太雞肋了)。因此必須採用第二種,藍芽socket。
在電腦上,實在不想去在C++下開發,於是便尋找.NET組件,但實際上微軟的NET庫中不支援藍芽,因此必須採用第三方的控制項,名字叫inthehand.
這篇文章中詳細的介紹了inthehan
d組件,http://www.cnblogs.com/procoder/archive/2009/09/22/1571580.html。由於它討論了實現檔案傳輸的思路,我們在這篇文章中就只討論簡單的字元傳輸。
它的官方網站是inthehand.net,其中多數的類庫和方法都能找到。
下面是手機端的初始化代碼。其中的具體含義可參照http://android.tgbus.com/Android/tutorial/201103/346657.shtml。
private PrintStream mPrintStream = null;
private BufferedReader mBufferedReader = null;
BluetoothAdapter myBluetoothAdapter = null;
BluetoothServerSocket mBThServer = null;
BluetoothSocket mBTHSocket = null;
myBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
myBluetoothAdapter.enable();//open bth
Intent discoverableIntent = new Intent(
BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);//使得藍芽處於可發現模式,期間150s
discoverableIntent.putExtra(
BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 150);
下面是PC上的初始化核心代碼:PC是作為用戶端出現的。它需要通過搜尋擷取手機的藍芽MAC地址,實現通訊。GUID又名UUID,是標記硬體地址的一種方法。
/// <summary>
/// 開啟連接埠
/// </summary>
/// <param name="Name">連接埠名稱</param>
/// <returns>成功否</returns>
public bool OpenPort(string Name)
{
InTheHand.Net.Bluetooth.BluetoothRadio.PrimaryRadio.Mode = InTheHand.Net.Bluetooth.RadioMode.Connectable;
InTheHand.Net.Sockets.BluetoothClient cli = new InTheHand.Net.Sockets.BluetoothClient();
InTheHand.Net.Sockets.BluetoothDeviceInfo[] devices = cli.DiscoverDevices();
foreach (InTheHand.Net.Sockets.BluetoothDeviceInfo device in devices)//裝置搜尋
{
device.Update();
device.Refresh();
MessageBox.Show("裝置已找到");
break;
}
BluetoothDeviceInfo bd = new BluetoothDeviceInfo(devices[0].DeviceAddress);
bluetoothClient = new BluetoothClient();
Guid mGUID = Guid.Parse("fa87c0d0-afac-11de-8a39-0800200c9a66");
bluetoothClient.Connect(devices[0].DeviceAddress, mGUID);//用戶端對地址實現串連,這是一個阻塞線程,需要伺服器端的回應
ReceiveThread = new Thread(ReceiveMethod);
ReceiveThread.Start();
return true;
}
下面是手機接受PC端串連請求的方法:
View Code
1 if (connected)
2 {
3 return;
4 }
5 try
6 {
7 mBThServer = myBluetoothAdapter
8 .listenUsingRfcommWithServiceRecord(NAME_SECURE,
9 MY_UUID_SECURE);
10 } catch (IOException e)
11 {
12 // TODO Auto-generated catch block
13 e.printStackTrace();
14 }
15
16 try
17 {
18 mBTHSocket = mBThServer.accept();
19 } catch (IOException e)
20 {
21 // TODO Auto-generated catch block
22 e.printStackTrace();
23 }
24 try
25 {
26 mBufferedReader = new BufferedReader(new InputStreamReader(
27 mBTHSocket.getInputStream()));
28 } catch (IOException e1)
29 {
30 // TODO Auto-generated catch block
31 e1.printStackTrace();
32 }// 取得輸入、輸出資料流
33 try
34 {
35 mPrintStream = new PrintStream(
36 mBTHSocket.getOutputStream(), true);
37 connected = true;
38 } catch (IOException e)
39 {
40 // TODO Auto-generated catch block
41 e.printStackTrace();
42 }
要通過手機發送資料,執行以下代碼即可:
mPrintStream.write(buff);
} catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}// 發送給伺服器
mPrintStream.flush();
PC端的接受代碼:
while (isConnecting)
{
try
{
Stream peerStream = bluetoothClient.GetStream();
peerStream.Read(buffer, 0, PACKETLENGTH);
//dataprocess();
}
catch (Exception ex)
{
isConnecting = false;
MessageBox.Show(ex.ToString());
}
這裡要注意以下幾個小問題,但也就是這幾個問題,耽誤了我很久時間:
inthehand.net.personal是PC端上一定要用得到的庫,但注意這個庫函數的版本,我一開始用了的dll是600K左右的,編譯沒問題,運行就會報錯,提示找不到dll。但後來左思右想,才發現還有另外的一個同名dll,150K左右,換過來以後一切OK,太坑爹了!
手機裝置的藍芽硬體許可權要開啟,否則就沒法運行。
還有我特想將手機做個藍芽HID裝置,但這樣貌似是不行的。因為這個庫本身提供的方法不夠底層...總之還想再研究下。
有任何問題歡迎討論