VB.NET利用OBEX協(xié)議實現(xiàn)紅外線文件傳輸

2010-08-28 10:48:10來源:西部e網(wǎng)作者:

  十一月開始沒有做什么項目,每天站在在辦公室窗前靜靜地看著樓下的行人來來往往,然后等待著領(lǐng)工資的時刻。為了讓智慧的大腦不因無所事是而僵硬,我決定找點傷腦筋的事情來維持腦袋的正常運轉(zhuǎn)。經(jīng)過考慮,決定用VB.net實現(xiàn)紅外線文件傳輸?shù)睦獭?BR>
  一、OBEX協(xié)議淺析

  目前的紅外線傳輸大都遵循OBEX協(xié)議,這是由微軟、蘋果、諾基亞等公司專門為紅外線傳輸而制定的一整套協(xié)議規(guī)則。最新協(xié)議版本是1.3版,在官方網(wǎng)站上下載要20美元(有錢的可以去下,我反正是玩玩,叫我交錢是不可能的,本文中實現(xiàn)的依據(jù)是在網(wǎng)上找到的OBEX協(xié)議1.2版本的文檔)。協(xié)議文檔的第二章OBEX Object Model是關(guān)鍵部份,實現(xiàn)文件傳輸必須對這章說明仔細研究清楚。以下先就對這章的一些關(guān)鍵點進行講解。

  1、OBEX協(xié)議的對象模型

  1)OBEX協(xié)議使用一系列的數(shù)據(jù)包(header)來進行某種對象(通常是文件)的傳輸,其基本格式是這樣的:

  <Header ID>'數(shù)據(jù)包的標(biāo)識
  <Header Value> '數(shù)據(jù)包內(nèi)的數(shù)據(jù)

  其中<Header ID>是個單字節(jié)(八位二進制)字符,這個字符的低六位標(biāo)識數(shù)據(jù)包代表的意義,高兩位表示這個數(shù)據(jù)包的總長度的表達方式,如下表:

高倆位二進制數(shù)據(jù) 意義
00 這個數(shù)據(jù)包的<header Value>是一個以空字符結(jié)尾的unicode字符串
01 這個數(shù)據(jù)包的<header Value>是一個以空字符結(jié)尾的單字節(jié)組成的字符串,<header Value>的前兩個字節(jié)數(shù)據(jù)組成的16位整數(shù)表示整個數(shù)據(jù)包的長度(包括<header id>及<header value>的總長)
10 <header Value>的長度只有一個字節(jié)數(shù)據(jù)
11 <header Value>的長度只有四個字節(jié)數(shù)據(jù),并以網(wǎng)格數(shù)據(jù)格式排列(高位數(shù)據(jù)放在低位字節(jié)中存儲)

  注意:在<header Value>的16位數(shù)據(jù)(如包的長度、Unicode字符在發(fā)送方均要做高位字放在低位字發(fā)送的處理。由于沒注意這個問題,我曾在開頭的四五天時間里嘔血數(shù)升而一直沒有成功將數(shù)據(jù)發(fā)送成功)

  在應(yīng)用中,數(shù)據(jù)包可以嵌套。也就是:Header Value可以包含其它的數(shù)據(jù)包,所以長度標(biāo)識非常重要,它可以幫助軟件的實現(xiàn)根據(jù)包的長度迅速分離出包內(nèi)的數(shù)據(jù)。

  在本文實現(xiàn)中主要用到的數(shù)據(jù)包標(biāo)識如下(其余的項請參閱詳細官方協(xié)議):

  常用數(shù)據(jù)包標(biāo)識列表

十六進制值 標(biāo)識名稱 標(biāo)識含義
0x01 Name 標(biāo)記對象的名稱(通常是文件的文件名)
0xC3 Length 以字節(jié)為單位計算的對象長度
0x44 Time 時間(以ISO 8601規(guī)范為標(biāo)準(zhǔn))
0x480x49 BodyEnd of Body 標(biāo)識一個對象數(shù)據(jù)塊的開始標(biāo)識這是對象的最后一個數(shù)據(jù)塊

  OBEX協(xié)議數(shù)據(jù)對象傳輸是按照服務(wù)器端/客戶端的方式進行的,每個操作均提供一個操作碼以明確操作的含義。以下給出部分數(shù)據(jù)發(fā)送所需操作碼列表:

0x80 Connect 標(biāo)識申請開始一個對象傳輸會話,并可以在這個數(shù)據(jù)包中告知紅外接收方一些必要的兼容性信息。
0x81 Disconnect 標(biāo)識對象傳輸會話結(jié)束
0x020x82 PutFinal_Put 發(fā)送對象的put動作(當(dāng)標(biāo)識為0x82時說明這是最后的一個Put動作)
0xA0 Success 說明接收端已成功收到put動作發(fā)送的所有數(shù)據(jù)(一般是在成功收到Final_Put標(biāo)識的數(shù)據(jù)包后的反饋)
0x90 Continue 說明接收端已收到put動作發(fā)送的數(shù)據(jù),因為Final_Put還沒出現(xiàn),所以要求發(fā)送端繼續(xù)發(fā)送數(shù)據(jù)。

  發(fā)送方和接收方是的通信的基本格式如下:

字節(jié)0 字節(jié)1,2 字節(jié)三以后的數(shù)據(jù)
操作碼 整個通信數(shù)據(jù)包的長度 通訊的數(shù)據(jù)

  以下結(jié)合基本傳輸步驟,對上文列出的數(shù)據(jù)包使用方法進行講解:

  1、由發(fā)送方向接收文件的接收方進行連接請求。

  發(fā)送方需要使用的操作碼為Connect,在OBEX協(xié)議中對Connect數(shù)據(jù)包格式作如下規(guī)定:

字節(jié)0 字節(jié)1、2 字節(jié)3 字節(jié)4 字節(jié)5、6 字節(jié)7
Connect操作碼(0x80) Connect數(shù)據(jù)包的總長度 OBEX協(xié)議的版本(目前為1.0,16進制表示為0x10) 保留未用,設(shè)為0 最大可處理的OBEX包長度 其它的數(shù)據(jù)包(可選)

  服務(wù)端根據(jù)連接的請求向客戶端做出響應(yīng):

字節(jié)0 字節(jié)1、2 字節(jié)3 字節(jié)4 字節(jié)5、6 字節(jié)7
響應(yīng)的操作碼 響應(yīng)數(shù)據(jù)包的總長度 OBEX協(xié)議的版本(目前為1.0,16進制表示為0x10) 保留未用,設(shè)為0 最大可處理的OBEX包長度 其它的數(shù)據(jù)包(可選)

  如果接收方允許連接,響應(yīng)的操作碼會為Success(0xA0)其它的響應(yīng)操作碼均被認為連接失敗。

  2、發(fā)送方向接收方發(fā)送數(shù)據(jù)

  發(fā)送方通過put和Final_Put這兩個操作將傳輸?shù)臄?shù)據(jù)信息向接收方發(fā)送。

  發(fā)送方的Put/Final_Put使用格式。

字節(jié)0 字節(jié)1,2 字節(jié)三以后的數(shù)據(jù)
Put操作碼(0x02)Final_Put操作碼(0x82) 整個通信數(shù)據(jù)包的長度 通訊的數(shù)據(jù)(由其它的例如name/body等數(shù)據(jù)包構(gòu)成)

  當(dāng)最后一次傳輸對象的數(shù)據(jù)時要使用Final_Put告知接收方這是最后一個數(shù)據(jù)包了,以便接收方根據(jù)接收到的數(shù)據(jù)進行處理(例如將接收到的文件存盤)。

  接收方的響應(yīng)格式:

字節(jié)0 字節(jié)1,2 字節(jié)三以后的數(shù)據(jù)
響應(yīng)操作碼典型的有兩個值:Success操作碼(0xA0)Continue操作碼(0x90 ) 整個通信數(shù)據(jù)包的長度 通訊的數(shù)據(jù)(由其它的例如name/body等數(shù)據(jù)包構(gòu)成)

  如果接收方成功收到put操作的數(shù)據(jù),應(yīng)該返回Continue開始的響應(yīng)信息,告知發(fā)送方繼續(xù)發(fā)送,在成功收到Final_Put發(fā)送的數(shù)據(jù)后,應(yīng)返回Success響應(yīng)信息,告知發(fā)送方整個對象都接收完成。(但由于部分適配器只會返回Success響應(yīng),出于兼容性考慮,在編程中應(yīng)理解為無論接收到Success或Continue響應(yīng)都代表數(shù)據(jù)發(fā)送成功。)

  3、發(fā)送方關(guān)閉連接

  發(fā)送方在最后應(yīng)以Disconnect信息明確結(jié)束連接,這并不是必須的,但推薦使用。

  發(fā)送方格式:

字節(jié)0 字節(jié)1,2 字節(jié)三以后的數(shù)據(jù)
Disconnect操作碼 整個通信數(shù)據(jù)包的長度 可選的通訊的數(shù)據(jù)(由其它的數(shù)據(jù)包構(gòu)成)

  接收方響應(yīng):

字節(jié)0 字節(jié)1,2 字節(jié)三以后的數(shù)據(jù)
Success操作碼(0xA0)服務(wù)不可用操作碼(0xD3) 整個通信數(shù)據(jù)包的長度 可選的通訊的數(shù)據(jù)(由其它的數(shù)據(jù)包構(gòu)成)


  當(dāng)成功斷開時,接收方會發(fā)送Success信息。否則,如果發(fā)送方的disconnect操作包含錯誤信息(例如一個錯誤的連接ID)時,會返加0xD3操作碼。但并不能操作所有接收方的程序都實現(xiàn)這個響應(yīng)的功能,也就是說,發(fā)送方并不能保證一定會得到響應(yīng)信息。

  二、程序?qū)崿F(xiàn)

  .net1.0中對紅外的支持全部在System.Net.Sockets空間中,使用很簡單,和普通的網(wǎng)絡(luò)連接差不多,主要有三個類:

IrDAClient 提供連接信息,并創(chuàng)建客戶端連接對象,用以打開和關(guān)閉與服務(wù)器的連接。
IrDADeviceInfo 提供客戶端在發(fā)現(xiàn)查詢過程中獲取的有關(guān)可用服務(wù)器和端口的信息。
IrDAListener 將套接字置于偵聽狀態(tài),以監(jiān)視來自指定服務(wù)或網(wǎng)絡(luò)地址的連接。
  
 。ㄒ唬、獲取附近可用紅外設(shè)備的信息

  在這個示例中,我獲取紅外設(shè)備通過IrDAClient的DiscoverDevices方法實現(xiàn),該方法以IrDADeviceInfo類型的對象數(shù)組返回附近可用紅外設(shè)備的相關(guān)信息。這個方法唯一的參數(shù)表示如果附近有許多紅外設(shè)備時,最多收集多少個設(shè)備的信息。

  示例代碼如下:

Dim taobjIrDADeviceInfo() As Sockets.IrDADeviceInfo
Dim tobjIrDAClient As New Sockets.IrDAClient
'開始檢索附近的紅外設(shè)備并加入到列表中,最多只搜索7個設(shè)備
taobjIrDADeviceInfo = tobjIrDAClient.DiscoverDevices(7)

  在得到的IrDADeviceInfo類型的變量有三個有用的屬性,你可根據(jù)這些屬性的值給用戶提示,以便由用戶選擇應(yīng)連接到那一個紅外設(shè)備上:

  DeviceID 獲取紅外設(shè)備標(biāo)識符,在連接紅外設(shè)備中使用

  DeviceName 獲取紅設(shè)備名稱。

  Hints 獲取設(shè)備的類型,例如是紅外手機還是紅外PDA之類的說明

 。ǘ、用IrDAClient對象實現(xiàn)紅外連接及數(shù)據(jù)發(fā)送

  IrDAClient和一般的網(wǎng)絡(luò)連接對象的使用很相似,使用的基本步驟如下:

  1)、先使用connect方法連接指定的紅外設(shè)備,這個方法需要一個IrDAEndPoint對象作為參數(shù)(這個對象指定需連接的紅外設(shè)備,以及連接到紅外設(shè)備提供的指定服務(wù)上)

  示例:

Dim tobjIrDAClient As New Sockets.IrDAClient
'ni_objIrDADeviceInfo是上文介紹的IrDADeviceInfo對象,以下語句的含義就是連接到'DeviceID指定的紅外設(shè)備上,這個設(shè)備提供OBEX服務(wù)。
Dim tobjIrDAEndPoint As New IrDAEndPoint(ni_objIrDADeviceInfo.DeviceID, "OBEX")
Try
tobjIrDAClient.Connect(tobjIrDAEndPoint)
Catch ex As Exception
MessageBox.Show("IrDA Socket Connect 狀態(tài)失敗")
End Try

  2)、連接成功后就可以使用IrDAClient對象的GetStream 方法獲得基礎(chǔ)數(shù)據(jù)流,并利用流Read/Write方法實現(xiàn)數(shù)據(jù)傳輸?shù)慕邮?發(fā)送。

  示例:兩個方法的第一個參數(shù)都是一個字節(jié)數(shù)組

  數(shù)據(jù)發(fā)送:tobjIrDAClient.GetStream.Write(tabytTempa, 0, tabytTempa.Length)

  數(shù)據(jù)接收:tobjIrDAClient.GetStream.Read(tabytReceiveBuffer, 0, 7)

  3)、完成所有通信后使用流以及IrDAClient的Close方法 關(guān)閉連接。

  示例:tobjIrDAClient.GetStream.Close()
     tobjIrDAClient.Close()

 。ㄈ┩暾麑崿F(xiàn)代碼

  其實紅外操作在net中實現(xiàn)就是這么簡單,不過困難的是對OBEX協(xié)議的解釋,基于代碼重用的原則,我的程序主框架有兩個基礎(chǔ)類,clsIrDAOBEXOperator封裝了文件發(fā)送的方法,方法中調(diào)用另一個類clsOBEXHeaders,這個類主門用來構(gòu)建obex協(xié)議需要的數(shù)據(jù)包。代碼如下,其中已包括必要的注釋:

  clsIrDAOBEXOperator.vb的代碼(代碼中fnSendFileToIrDADevice是向紅外設(shè)備發(fā)送文件的方法,它的第一個參數(shù)是代表紅外設(shè)備的IrDADeviceInfo對象,第二個參數(shù)就是要發(fā)送的文件名),:

Imports System.Net
Imports System.Net.Sockets

Public Class clsIrDAOBEXOperator
'OBEX常數(shù)
Public Const cOBEX_VERSION As Byte = &H10
Public Const cOBEX_CONNECTFLAGS As Byte = &H0

Public Const cOBEX_CONNECT As Byte = &H80
Public Const cOBEX_DISCONNECT As Byte = &H81
Public Const cOBEX_PUT As Byte = &H2
Public Const cOBEX_NAME As Byte = &H1
Public Const cOBEX_PUT_FINAL As Byte = &H82
Public Const cOBEX_LENGTH As Byte = &HC3
Public Const cOBEX_BODY As Byte = &H48
Public Const cOBEX_END_OF_BODY As Byte = &H49

Public Const cOBEX_CONTINUE As Byte = &H90
Public Const cOBEX_SUCCESS As Byte = &HA0


'向外界公布可直接修改的變量
Public m_i32OBEXMAXSendBufferLen As Int32 = 255
Public m_i32OBEXMAXReceiveBufferLen As Int32 = 1024
Public m_i32OBEXMAXPacketSize As Int16 = &H808

'將一個16位整數(shù)轉(zhuǎn)為2個字節(jié)的數(shù)組,并存入?yún)?shù)中指定索引開始的字節(jié)數(shù)組處(低位字在低字節(jié),高位字在高字節(jié))
Private Function fnInt16ToByteArray(ByVal ni_i16Convert As Int16, ByRef ni_abytDest() As Byte, ByVal ni_i32StartIndex As Int32) As Boolean
ni_abytDest(ni_i32StartIndex) = ni_i16Convert And &HFF
ni_abytDest(ni_i32StartIndex + 1) = ni_i16Convert >> 8

End Function

'將一個16位整數(shù)轉(zhuǎn)為2個字節(jié)的數(shù)組,并存入?yún)?shù)中指定索引開始的字節(jié)數(shù)組處
Private Function fnInt16ToByteArrayLowByteToHightPosition(ByVal ni_i16Convert As Int16, ByRef ni_abytDest() As Byte, ByVal ni_i32StartIndex As Int32) As Boolean
ni_abytDest(ni_i32StartIndex + 1) = ni_i16Convert And &HFF
ni_abytDest(ni_i32StartIndex) = ni_i16Convert >> 8

End Function

'將一個32位整數(shù)轉(zhuǎn)為4個字節(jié)的數(shù)組,并存入?yún)?shù)中指定索引開始的字節(jié)數(shù)組處
Private Function fnInt32ToByteArrayLowByteToHightPosition(ByVal ni_i32Convert As Int16, ByRef ni_abytDest() As Byte, ByVal ni_i32StartIndex As Int32) As Boolean
Dim ti32Tempa As Int32 = ni_i32Convert
ni_abytDest(ni_i32StartIndex + 3) = ni_i32Convert And &HFF
ni_abytDest(ni_i32StartIndex + 2) = (ni_i32Convert And &HFF00) >> 8
ni_abytDest(ni_i32StartIndex + 1) = (ni_i32Convert And &HFF0000) >> 16
ni_abytDest(ni_i32StartIndex) = (ti32Tempa And &HFF000000) >> 24

End Function


'將本設(shè)備中指定的文件傳到指定的設(shè)備中去
Public Function fnSendFileToIrDADevice(ByVal ni_objIrDADeviceInfo As IrDADeviceInfo, _
ByVal ni_strFilePath As String) As Boolean
'ni_objIrDADeviceInfo:指定紅外設(shè)備的IrDAInfo結(jié)構(gòu)
'ni_strFilePath:要傳輸?shù)奈募窂?BR>'返回值:成功返回true

Dim tobjIrDAClient As New Sockets.IrDAClient
Dim tobjIrDAEndPoint As New IrDAEndPoint(ni_objIrDADeviceInfo.DeviceID, "OBEX")
Dim tabytSendBuffer(m_i32OBEXMAXSendBufferLen * 2) As Byte
Dim tabytReceiveBuffer(m_i32OBEXMAXReceiveBufferLen) As Byte
Dim tblnTemp As Boolean
Dim ti32Tempa As Int32, ti32TempB As Int32, tieTempC As Int32
Dim tbytTempa As Byte
Dim ti32LoopA As Int32
Dim tobjBinaryReader As IO.BinaryReader
Dim tobjFileStream As IO.FileStream
Dim tabytTempa() As Byte, tabytTempb() As Byte, tabytTempC() As Byte, tabytTempD() As Byte
Dim tabytTempE() As Byte
Dim tobjOBEX_HEADERS As New clsOBEXHeaders
Dim ti32SendPackageSpare As Int32 '保存最大發(fā)送包數(shù)組-當(dāng)前數(shù)據(jù)后的剩余空間
Dim tobjFileInfo As IO.FileInfo

tobjFileInfo = New IO.FileInfo(ni_strFilePath)

Try

Try
tobjIrDAClient.Connect(tobjIrDAEndPoint)

Catch ex As Exception
MessageBox.Show("IrDA Socket Connect 狀態(tài)失敗")
Return False
End Try

'創(chuàng)建一個最簡單的連接信息
tabytTempa = tobjOBEX_HEADERS.fnCreateConnectHeaderRequest(, , , m_i32OBEXMAXPacketSize)

Try
tobjIrDAClient.GetStream.Write(tabytTempa, 0, tabytTempa.Length)
tobjIrDAClient.GetStream.Flush()

Catch ex As Exception
MessageBox.Show("OBEX_CONNECT信息發(fā)送失敗")
Application.DoEvents()
Return False
End Try

If tobjIrDAClient.GetStream.CanRead = True Then
Try
tobjIrDAClient.GetStream.Read(tabytReceiveBuffer, 0, 7)

Catch ex As Exception
MessageBox.Show("接收OBEX_CONNECT響應(yīng)消息失敗")
Return False
End Try

If tabytReceiveBuffer(0) <> cOBEX_SUCCESS Then
MessageBox.Show("OBEX_CONNECT沒接收到相應(yīng)的響應(yīng)")
Return False
End If

End If

'發(fā)送put包
'Name包
tabytTempa = tobjOBEX_HEADERS.fnCreateNameHeader(IO.Path.GetFileName(ni_strFilePath))
ti32Tempa = tabytTempa.Length

'lenght包
tabytTempb = tobjOBEX_HEADERS.fnCreateLengthHeader(tobjFileInfo.Length)
ti32TempB = tabytTempb.Length


'時間
tabytTempC = tobjOBEX_HEADERS.fnCreateTimeHeaderISO(Now)

ReDim Preserve tabytTempa(tabytTempa.Length + tabytTempb.Length + tabytTempC.Length)

tabytTempb.CopyTo(tabytTempa, ti32Tempa)
tabytTempC.CopyTo(tabytTempa, ti32Tempa + ti32TempB)
tabytTempa = tobjOBEX_HEADERS.fnCreatePutHeader(tabytTempa)

'將名稱、時間、文件長度等基本信息先發(fā)出去
Try
tobjIrDAClient.GetStream.Write(tabytTempa, 0, tabytTempa.Length)
Catch ex As Exception
Return False
End Try

Try
tobjIrDAClient.GetStream.Read(tabytReceiveBuffer, 0, tabytReceiveBuffer.Length)
Catch ex As Exception
'接收服務(wù)器端響應(yīng)時失敗
tobjIrDAClient.GetStream.Close()
tobjIrDAClient.Close()
Return False

End Try

If tabytReceiveBuffer(0) <> cOBEX_SUCCESS And tabytReceiveBuffer(0) <> cOBEX_CONTINUE Then
'沒有收到服務(wù)器的對應(yīng)的響應(yīng)信息
tobjIrDAClient.GetStream.Close()
tobjIrDAClient.Close()
Return False
End If


'開始正式發(fā)送文件的數(shù)據(jù)
Try
tobjFileStream = IO.File.Open(ni_strFilePath, IO.FileMode.Open, IO.FileAccess.Read)
tobjBinaryReader = New IO.BinaryReader(tobjFileStream)

Catch ex As Exception
MessageBox.Show("打開文件時出現(xiàn)錯誤")
tobjIrDAClient.GetStream.Close()
tobjIrDAClient.Close()
Return False
End Try

'讀出文件的數(shù)據(jù)放到body中,總長度必須少于最大發(fā)送長度-put標(biāo)志的3字節(jié)-body標(biāo)志的3字節(jié)
'最多可發(fā)送的文件信息長度
ti32SendPackageSpare = m_i32OBEXMAXSendBufferLen - 6

'循環(huán)讀取文件的內(nèi)容,并發(fā)送到服務(wù)方
For ti32LoopA = 1 To Math.Ceiling(tobjFileInfo.Length / ti32SendPackageSpare)
Try
tabytTempa = tobjBinaryReader.ReadBytes(ti32SendPackageSpare)
Catch ex As Exception
tobjIrDAClient.GetStream.Close()
tobjIrDAClient.Close()
Return False
End Try

'構(gòu)建合適的put包并發(fā)送
tabytTempb = tobjOBEX_HEADERS.fnCreateBodyHeader(tabytTempa) 'body標(biāo)志
tabytTempa = tobjOBEX_HEADERS.fnCreatePutHeader(tabytTempb)

'開始發(fā)送
Try
tobjIrDAClient.GetStream.Write(tabytTempa, 0, tabytTempa.Length)
tobjIrDAClient.GetStream.Flush()

Catch ex As Exception
tobjIrDAClient.GetStream.Close()
tobjIrDAClient.Close()
Return False
End Try

Try
tobjIrDAClient.GetStream.Read(tabytReceiveBuffer, 0, tabytReceiveBuffer.Length)
Catch ex As Exception
'接收服務(wù)器端響應(yīng)時失敗
tobjIrDAClient.GetStream.Close()
tobjIrDAClient.Close()
Return False

End Try

If tabytReceiveBuffer(0) <> cOBEX_SUCCESS And tabytReceiveBuffer(0) <> cOBEX_CONTINUE Then
'沒有收到服務(wù)器的對應(yīng)的響應(yīng)信息
tobjIrDAClient.GetStream.Close()
tobjIrDAClient.Close()
Return False
End If

Next

'關(guān)閉文件
tobjBinaryReader.Close()
tobjFileStream.Close()

If ti32Tempa Then

End If
'文件數(shù)據(jù)已全部發(fā)送完畢,發(fā)送結(jié)束的final_put 包
'endbody包
tabytTempa = tobjOBEX_HEADERS.fnCreateEndOfBodyHeader(Nothing)
'putfinal
tabytTempa = tobjOBEX_HEADERS.fnCreatePut_FinalHeaderResponse(tabytTempa)
Try
tobjIrDAClient.GetStream.Write(tabytTempa, 0, tabytTempa.Length)
tobjIrDAClient.GetStream.Flush()
Catch ex As Exception
tobjIrDAClient.GetStream.Close()
tobjIrDAClient.Close()
Return False
End Try


Try
tobjIrDAClient.GetStream.Read(tabytReceiveBuffer, 0, tabytReceiveBuffer.Length)
Catch ex As Exception
tobjIrDAClient.GetStream.Close()
tobjIrDAClient.Close()
Return False
End Try

If tabytReceiveBuffer(0) <> cOBEX_SUCCESS Then
'沒有收到服務(wù)器的對應(yīng)的響應(yīng)信息
tobjIrDAClient.GetStream.Close()
tobjIrDAClient.Close()
Return False
End If

'發(fā)送disconnect包
tabytTempa = tobjOBEX_HEADERS.fnCreateDisConnectHeaderRequest()
Try
tobjIrDAClient.GetStream.Write(tabytTempa, 0, tabytTempa.Length)
tobjIrDAClient.GetStream.Flush()
Catch ex As Exception
tobjIrDAClient.GetStream.Close()
tobjIrDAClient.Close()
Return False
End Try

tobjIrDAClient.Close()

Catch ex As Exception
MessageBox.Show("過程發(fā)生不明錯誤")
Return False
End Try


'代碼能來到這兒就是正常完成任務(wù)了
MsgBox("紅外操作成功")
Return True

End Function
End Class
clsOBEXHeaders.vb文件的代碼:
Public Class clsOBEXHeaders
#Region "OBEX常數(shù)"
Public Const cOBEX_VERSION As Byte = &H10
Public Const cOBEX_CONNECTFLAGS As Byte = &H0

Public Const cOBEX_CONNECT As Byte = &H80
Public Const cOBEX_DISCONNECT As Byte = &H81
Public Const cOBEX_PUT As Byte = &H2
Public Const cOBEX_NAME As Byte = &H1
Public Const cOBEX_PUT_FINAL As Byte = &H82
Public Const cOBEX_LENGTH As Byte = &HC3
Public Const cOBEX_BODY As Byte = &H48
Public Const cOBEX_END_OF_BODY As Byte = &H49
Public Const cOBEX_TIME_ISO As Byte = &H44

Public Const cOBEX_CONTINUE As Byte = &H90
Public Const cOBEX_SUCCESS As Byte = &HA0

#End Region

#Region "類內(nèi)私有函數(shù)"

'將一個16位整數(shù)轉(zhuǎn)為2個字節(jié)的數(shù)組,并存入?yún)?shù)中指定索引開始的字節(jié)數(shù)組處
Private Sub sbInt16ToByteArrayLowByteToHightPosition(ByVal ni_i16Convert As Int16, ByRef ni_abytDest() As Byte, ByVal ni_i32StartIndex As Int32)

ni_abytDest(ni_i32StartIndex + 1) = ni_i16Convert And &HFF
ni_abytDest(ni_i32StartIndex) = ni_i16Convert >> 8

End Sub

''將一個16位整數(shù)轉(zhuǎn)為2個字節(jié)的數(shù)組,高位字放入高字節(jié),并存入?yún)?shù)中指定索引開始的字節(jié)數(shù)組處
'Private Sub sbInt16ToByteArrayHightByteToHightPosition(ByVal ni_i16Convert As Int16, ByRef ni_abytDest() As Byte, ByVal ni_i32StartIndex As Int32)

' ni_abytDest(ni_i32StartIndex) = ni_i16Convert And &HFF
' ni_abytDest(ni_i32StartIndex + 1) = ni_i16Convert >> 8

'End Sub

'將一個32位整數(shù)轉(zhuǎn)為4個字節(jié)的數(shù)組,并存入?yún)?shù)中指定索引開始的字節(jié)數(shù)組處
Private Sub sbInt32ToByteArrayLowByteToHightPosition(ByVal ni_i32Convert As Int16, ByRef ni_abytDest() As Byte, ByVal ni_i32StartIndex As Int32)

Dim ti32Tempa As Int32 = ni_i32Convert
ni_abytDest(ni_i32StartIndex + 3) = ni_i32Convert And &HFF
ni_abytDest(ni_i32StartIndex + 2) = (ni_i32Convert And &HFF00) >> 8
ni_abytDest(ni_i32StartIndex + 1) = (ni_i32Convert And &HFF0000) >> 16
ni_abytDest(ni_i32StartIndex) = (ti32Tempa And &HFF000000) >> 24

End Sub

#End Region

'創(chuàng)建一個新的ConnectHeader客戶端請求信息
Public Function fnCreateConnectHeaderRequest(Optional ByVal ni_abytOtherHeaders As Byte() = Nothing, _
Optional ByVal ni_bytOBEX_Version As Byte = cOBEX_VERSION, _
Optional ByVal ni_bytFlags As Byte = cOBEX_CONNECTFLAGS, _
Optional ByVal ni_i16MaxPacketLength As Int16 = 255) As Byte()
Dim tabytFuncReturn() As Byte


If Not (ni_abytOtherHeaders Is Nothing) Then
ReDim tabytFuncReturn(7 + ni_abytOtherHeaders.Length - 1)
Else
ReDim tabytFuncReturn(6)
End If

tabytFuncReturn(0) = cOBEX_CONNECT
tabytFuncReturn(3) = ni_bytOBEX_Version
tabytFuncReturn(4) = ni_bytFlags
sbInt16ToByteArrayLowByteToHightPosition(ni_i16MaxPacketLength, tabytFuncReturn, 5)

If ni_abytOtherHeaders Is Nothing Then '沒有其它的頭信息了
'加入connect包的長度
Call sbInt16ToByteArrayLowByteToHightPosition(7, tabytFuncReturn, 1)
Else '還有其它頭信息
ni_abytOtherHeaders.CopyTo(tabytFuncReturn, 7)
Call sbInt16ToByteArrayLowByteToHightPosition(ni_abytOtherHeaders.Length + 7, tabytFuncReturn, 1)
End If

Return tabytFuncReturn

End Function

'創(chuàng)建一個新的ConnectHeader的服務(wù)器端響應(yīng)信息數(shù)據(jù)
Public Function fnCreateConnectHeaderResponse(Optional ByVal ni_abytOtherHeaders As Byte() = Nothing, _
Optional ByVal ni_bytOBEX_Version As Byte = cOBEX_VERSION, _
Optional ByVal ni_bytFlags As Byte = cOBEX_CONNECTFLAGS, _
Optional ByVal ni_i16MaxPacketLength As Int16 = 255) As Byte()
Dim tabytFuncReturn() As Byte


If Not (ni_abytOtherHeaders Is Nothing) Then
ReDim tabytFuncReturn(7 + ni_abytOtherHeaders.Length - 1)
Else
ReDim tabytFuncReturn(6)
End If

tabytFuncReturn(0) = cOBEX_SUCCESS
tabytFuncReturn(3) = ni_bytOBEX_Version
tabytFuncReturn(4) = ni_bytFlags
sbInt16ToByteArrayLowByteToHightPosition(ni_i16MaxPacketLength, tabytFuncReturn, 5)

If ni_abytOtherHeaders Is Nothing Then '沒有其它的頭信息了
'加入connect包的長度
Call sbInt16ToByteArrayLowByteToHightPosition(7, tabytFuncReturn, 1)
Else '還有其它頭信息
ni_abytOtherHeaders.CopyTo(tabytFuncReturn, 7)
Call sbInt16ToByteArrayLowByteToHightPosition(ni_abytOtherHeaders.Length + 7, tabytFuncReturn, 1)
End If

Return tabytFuncReturn

End Function


'創(chuàng)建一個新的DisConnectHeader客戶請求信息
Public Function fnCreateDisConnectHeaderRequest(Optional ByVal ni_abytOtherHeaders As Byte() = Nothing) As Byte()
Dim tabytFuncReturn() As Byte


If Not (ni_abytOtherHeaders Is Nothing) Then '有其它的數(shù)據(jù)包要附在后面
ReDim tabytFuncReturn(3 + ni_abytOtherHeaders.Length - 1)
Else
ReDim tabytFuncReturn(2)
End If

tabytFuncReturn(0) = cOBEX_DISCONNECT

If ni_abytOtherHeaders Is Nothing Then '沒有其它的頭信息了
'加入包的長度
Call sbInt16ToByteArrayLowByteToHightPosition(3, tabytFuncReturn, 1)
Else '還有其它頭信息
ni_abytOtherHeaders.CopyTo(tabytFuncReturn, 3)
Call sbInt16ToByteArrayLowByteToHightPosition(ni_abytOtherHeaders.Length + 3, tabytFuncReturn, 1)
End If

Return tabytFuncReturn

End Function

'創(chuàng)建一個新的ContinueHeader信息
Public Function fnCreateContinueHeaderResponse(Optional ByVal ni_abytOtherHeaders As Byte() = Nothing) As Byte()
Dim tabytFuncReturn() As Byte


If Not (ni_abytOtherHeaders Is Nothing) Then '有其它的數(shù)據(jù)包要附在后面
ReDim tabytFuncReturn(3 + ni_abytOtherHeaders.Length - 1)
Else
ReDim tabytFuncReturn(2)
End If

tabytFuncReturn(0) = cOBEX_CONTINUE

If ni_abytOtherHeaders Is Nothing Then '沒有其它的頭信息了
'加入包的長度
Call sbInt16ToByteArrayLowByteToHightPosition(3, tabytFuncReturn, 1)
Else '還有其它頭信息
ni_abytOtherHeaders.CopyTo(tabytFuncReturn, 3)
Call sbInt16ToByteArrayLowByteToHightPosition(ni_abytOtherHeaders.Length + 3, tabytFuncReturn, 1)
End If

Return tabytFuncReturn

End Function

'創(chuàng)建一個新的SuccessHeader信息
Public Function fnCreateSuccessHeaderResponse(Optional ByVal ni_abytOtherHeaders As Byte() = Nothing) As Byte()
Dim tabytFuncReturn() As Byte


If Not (ni_abytOtherHeaders Is Nothing) Then '有其它的數(shù)據(jù)包要附在后面
ReDim tabytFuncReturn(3 + ni_abytOtherHeaders.Length - 1)
Else
ReDim tabytFuncReturn(2)
End If

tabytFuncReturn(0) = cOBEX_SUCCESS

If ni_abytOtherHeaders Is Nothing Then '沒有其它的頭信息了
'加入包的長度
Call sbInt16ToByteArrayLowByteToHightPosition(3, tabytFuncReturn, 1)
Else '還有其它頭信息
ni_abytOtherHeaders.CopyTo(tabytFuncReturn, 3)
Call sbInt16ToByteArrayLowByteToHightPosition(ni_abytOtherHeaders.Length + 3, tabytFuncReturn, 1)
End If

Return tabytFuncReturn

End Function

'創(chuàng)建一個新的TimeHeader信息
Public Function fnCreateTimeHeaderISO(ByVal ni_dtmDate As Date, Optional ByVal ni_abytOtherHeaders As Byte() = Nothing) As Byte()
Dim tabytFuncReturn() As Byte
Dim tstrDate As String
Dim tabytTempa() As Byte

'tstrDate = ni_dtmDate.Year & "." & ni_dtmDate.Month & "." & ni_dtmDate.Day & "T" & _
' ni_dtmDate.Hour & ":" & ni_dtmDate.Minute & ":" & ni_dtmDate.Second & "Z" & ControlChars.NullChar

tstrDate = String.Format("{0:yyyy/MM/dd\THH:mm:ss\Z}", ni_dtmDate) & ControlChars.NullChar
tabytTempa = Text.Encoding.BigEndianUnicode.GetBytes(tstrDate)


If Not (ni_abytOtherHeaders Is Nothing) Then '有其它的數(shù)據(jù)包要附在后面
ReDim tabytFuncReturn(3 + tabytTempa.Length + ni_abytOtherHeaders.Length - 1)
Else
ReDim tabytFuncReturn(2 + tabytTempa.Length)
End If

tabytFuncReturn(0) = cOBEX_TIME_ISO

tabytTempa.CopyTo(tabytFuncReturn, 3) '將時間字節(jié)串放入返回數(shù)組中

If ni_abytOtherHeaders Is Nothing Then '沒有其它的頭信息了
'加入包的長度
Call sbInt16ToByteArrayLowByteToHightPosition(3 + tabytTempa.Length, tabytFuncReturn, 1)
Else '還有其它頭信息
ni_abytOtherHeaders.CopyTo(tabytFuncReturn, 3)
Call sbInt16ToByteArrayLowByteToHightPosition(ni_abytOtherHeaders.Length + 3 + tabytTempa.Length, tabytFuncReturn, 1)
End If

Return tabytFuncReturn


End Function

'創(chuàng)建一個新的BodyHeader信息
Public Function fnCreateBodyHeader(ByVal ni_abytBodyContent() As Byte, Optional ByVal ni_abytOtherHeaders As Byte() = Nothing) As Byte()
Dim tabytFuncReturn() As Byte
Dim tabytTempa As Byte
Dim ti32BodyContentLength As Int32 = 0


'定義合適大小的數(shù)組以容納bodyheader的內(nèi)容
If Not (ni_abytBodyContent Is Nothing) Then '有body的內(nèi)容
If Not (ni_abytOtherHeaders Is Nothing) Then '有其它的數(shù)據(jù)包要附在后面
ReDim tabytFuncReturn(3 + ni_abytBodyContent.Length + ni_abytOtherHeaders.Length - 1)
ni_abytBodyContent.CopyTo(tabytFuncReturn, 3)
ni_abytOtherHeaders.CopyTo(tabytFuncReturn, ni_abytBodyContent.Length + 3)
Else
ReDim tabytFuncReturn(2 + ni_abytBodyContent.Length)
ni_abytBodyContent.CopyTo(tabytFuncReturn, 3)
End If

Else '沒有body的內(nèi)容
If Not (ni_abytOtherHeaders Is Nothing) Then '有其它的數(shù)據(jù)包要附在后面
ReDim tabytFuncReturn(3 + ni_abytOtherHeaders.Length - 1)
ni_abytOtherHeaders.CopyTo(tabytFuncReturn, 3)

Else
ReDim tabytFuncReturn(2)
End If

End If

tabytFuncReturn(0) = cOBEX_BODY

'加入包的長度
Call sbInt16ToByteArrayLowByteToHightPosition(tabytFuncReturn.Length, tabytFuncReturn, 1)

Return tabytFuncReturn


End Function

'創(chuàng)建一個新的EndOfBodyHeader信息
Public Function fnCreateEndOfBodyHeader(ByVal ni_abytBodyContent() As Byte, Optional ByVal ni_abytOtherHeaders As Byte() = Nothing) As Byte()
Dim tabytFuncReturn() As Byte
Dim tabytTempa As Byte
Dim ti32BodyContentLength As Int32 = 0


If Not (ni_abytBodyContent Is Nothing) Then
If Not (ni_abytOtherHeaders Is Nothing) Then '有其它的數(shù)據(jù)包要附在后面
ReDim tabytFuncReturn(3 + ni_abytBodyContent.Length + ni_abytOtherHeaders.Length - 1)
ni_abytBodyContent.CopyTo(tabytFuncReturn, 3)
ni_abytOtherHeaders.CopyTo(tabytFuncReturn, 3 + ni_abytBodyContent.Length)
Else
ReDim tabytFuncReturn(2 + ni_abytBodyContent.Length)
ni_abytBodyContent.CopyTo(tabytFuncReturn, 3)
End If

Else '沒有body內(nèi)容
If Not (ni_abytOtherHeaders Is Nothing) Then '有其它的數(shù)據(jù)包要附在后面
ReDim tabytFuncReturn(3 + ni_abytOtherHeaders.Length - 1)
ni_abytOtherHeaders.CopyTo(tabytFuncReturn, 3)

Else
ReDim tabytFuncReturn(2)
End If

End If

'加入包的長度
Call sbInt16ToByteArrayLowByteToHightPosition(tabytFuncReturn.Length, tabytFuncReturn, 1)

tabytFuncReturn(0) = cOBEX_END_OF_BODY

Return tabytFuncReturn


End Function

'創(chuàng)建一個新的LengthHeader信息
Public Function fnCreateLengthHeader(ByVal ni_i32Length As Int32) As Byte()
Dim tabytFuncReturn() As Byte

ReDim tabytFuncReturn(4)

tabytFuncReturn(0) = cOBEX_LENGTH

'加入包的內(nèi)容
Call sbInt32ToByteArrayLowByteToHightPosition(ni_i32Length, tabytFuncReturn, 1)

Return tabytFuncReturn

End Function

'創(chuàng)建一個新的NameHeader信息
Public Function fnCreateNameHeader(ByVal ni_strName As String, Optional ByVal ni_abytOtherHeaders As Byte() = Nothing) As Byte()
Dim tabytFuncReturn() As Byte
Dim tabytTempa() As Byte
Dim ti32BodyContentLength As Int32 = 0


tabytTempa = Text.Encoding.BigEndianUnicode.GetBytes(ni_strName & ControlChars.NullChar)


If ni_strName <> "" Then
If Not (ni_abytOtherHeaders Is Nothing) Then '有其它的數(shù)據(jù)包要附在后面
ReDim tabytFuncReturn(3 + tabytTempa.Length + ni_abytOtherHeaders.Length - 1)
Else '沒有其它數(shù)據(jù)包附后
ReDim tabytFuncReturn(2 + tabytTempa.Length)
End If

Else
If Not (ni_abytOtherHeaders Is Nothing) Then '有其它的數(shù)據(jù)包要附在后面

ReDim tabytFuncReturn(3 + ni_abytOtherHeaders.Length - 1)
Else
ReDim tabytFuncReturn(2)
End If

End If



tabytFuncReturn(0) = cOBEX_NAME

If ni_strName <> "" Then

If ni_abytOtherHeaders Is Nothing Then '沒有其它的頭信息了
'加入包的長度
Call sbInt16ToByteArrayLowByteToHightPosition(3 + tabytTempa.Length, tabytFuncReturn, 1)
Else '還有其它頭信息
ni_abytOtherHeaders.CopyTo(tabytFuncReturn, 3)
Call sbInt16ToByteArrayLowByteToHightPosition(ni_abytOtherHeaders.Length + tabytTempa.Length + 3, tabytFuncReturn, 1)
End If
tabytTempa.CopyTo(tabytFuncReturn, 3)

Else '沒有實際的body數(shù)據(jù)

If ni_abytOtherHeaders Is Nothing Then '沒有其它的頭信息了
'加入包的長度
Call sbInt16ToByteArrayLowByteToHightPosition(3, tabytFuncReturn, 1)
Else '還有其它頭信息
ni_abytOtherHeaders.CopyTo(tabytFuncReturn, 3)
Call sbInt16ToByteArrayLowByteToHightPosition(ni_abytOtherHeaders.Length + 3, tabytFuncReturn, 1)
End If

End If

Return tabytFuncReturn

End Function

'創(chuàng)建一個新的PutHeader信息
Public Function fnCreatePutHeader(Optional ByVal ni_abytOtherHeaders As Byte() = Nothing) As Byte()
Dim tabytFuncReturn() As Byte


If Not (ni_abytOtherHeaders Is Nothing) Then '有其它的數(shù)據(jù)包要附在后面
ReDim tabytFuncReturn(3 + ni_abytOtherHeaders.Length - 1)
Else
ReDim tabytFuncReturn(2)
End If

tabytFuncReturn(0) = cOBEX_PUT

If ni_abytOtherHeaders Is Nothing Then '沒有其它的頭信息了
'加入包的長度
Call sbInt16ToByteArrayLowByteToHightPosition(3, tabytFuncReturn, 1)
Else '還有其它頭信息
ni_abytOtherHeaders.CopyTo(tabytFuncReturn, 3)
Call sbInt16ToByteArrayLowByteToHightPosition(ni_abytOtherHeaders.Length + 3, tabytFuncReturn, 1)
End If

Return tabytFuncReturn

End Function

'創(chuàng)建一個新的PutHeader信息
Public Function fnCreatePut_FinalHeaderResponse(Optional ByVal ni_abytOtherHeaders As Byte() = Nothing) As Byte()
Dim tabytFuncReturn() As Byte


If Not (ni_abytOtherHeaders Is Nothing) Then '有其它的數(shù)據(jù)包要附在后面
ReDim tabytFuncReturn(3 + ni_abytOtherHeaders.Length - 1)
Else
ReDim tabytFuncReturn(2)
End If

tabytFuncReturn(0) = cOBEX_PUT_FINAL

If ni_abytOtherHeaders Is Nothing Then '沒有其它的頭信息了
'加入包的長度
Call sbInt16ToByteArrayLowByteToHightPosition(3, tabytFuncReturn, 1)
Else '還有其它頭信息
ni_abytOtherHeaders.CopyTo(tabytFuncReturn, 3)
Call sbInt16ToByteArrayLowByteToHightPosition(ni_abytOtherHeaders.Length + 3, tabytFuncReturn, 1)
End If

Return tabytFuncReturn

End Function

End Class

  以上代碼均為VB.net 2003編寫,在我的多普達515手機加紅外適配器上測試通過,不過紅外傳輸是一個相對比較專業(yè)的課題,我的代碼并不是足夠健壯和可靠,希望對這方面有研究的朋友與我探討。我的QQ:85403578,郵箱:missilecat@163.com。

關(guān)鍵詞:.NETOBEX紅外線