VB.NET利用OBEX协议实现红外线文件传输 作者:白猫黑爪子 点击数:322 文章来源:天极开发 更新时间:2007-8-14 十一月开始没有做什么项目,每天站在在办公室窗前静静地看着楼下的行人来来往往,然后等待着领工资的时刻。为了让智慧的大脑不因无所事是而僵硬,我决定找点伤脑筋的事情来维持脑袋的正常运转。经过考虑,决定用VB.net实现红外线文件传输的例程。 一、OBEX协议浅析 目前的红外线传输大都遵循OBEX协议,这是由微软、苹果、诺基亚等公司专门为红外线传输而制定的一整套协议规则。最新协议版本是1.3版,在官方网站上下载要20美元(有钱的可以去下,我反正是玩玩,叫我交钱是不可能的,本文中实现的依据是在网上找到的OBEX协议1.2版本的文档)。协议文档的第二章OBEX Object Model是关键部份,实现文件传输必须对这章说明仔细研究清楚。以下先就对这章的一些关键点进行讲解。 1、OBEX协议的对象模型 1)OBEX协议使用一系列的数据包(header)来进行某种对象(通常是文件)的传输,其基本格式是这样的: <Header ID>'数据包的标识 <Header Value> '数据包内的数据 其中<Header ID>是个单字节(八位二进制)字符,这个字符的低六位标识数据包代表的意义,高两位表示这个数据包的总长度的表达方式,如下表: 高俩位二进制数据 意义 00 这个数据包的<header Value>是一个以空字符结尾的unicode字符串 01 这个数据包的<header Value>是一个以空字符结尾的单字节组成的字符串,<header Value>的前两个字节数据组成的16位整数表示整个数据包的长度(包括<header id>及<header value>的总长) 10 <header Value>的长度只有一个字节数据 11 <header Value>的长度只有四个字节数据,并以网格数据格式排列(高位数据放在低位字节中存储) 注意:在<header Value>的16位数据(如包的长度、Unicode字符在发送方均要做高位字放在低位字发送的处理。由于没注意这个问题,我曾在开头的四五天时间里呕血数升而一直没有成功将数据发送成功) 在应用中,数据包可以嵌套。也就是:Header Value可以包含其它的数据包,所以长度标识非常重要,它可以帮助软件的实现根据包的长度迅速分离出包内的数据。 在本文实现中主要用到的数据包标识如下(其余的项请参阅详细官方协议): 常用数据包标识列表 十六进制值 标识名称 标识含义 0x01 Name 标记对象的名称(通常是文件的文件名) 0xC3 Length 以字节为单位计算的对象长度 0x44 Time 时间(以ISO 8601规范为标准) 0x480x49 BodyEnd of Body 标识一个对象数据块的开始标识这是对象的最后一个数据块 OBEX协议数据对象传输是按照服务器端/客户端的方式进行的,每个操作均提供一个操作码以明确操作的含义。以下给出部分数据发送所需操作码列表: 0x80 Connect 标识申请开始一个对象传输会话,并可以在这个数据包中告知红外接收方一些必要的兼容性信息。 0x81 Disconnect 标识对象传输会话结束 0x020x82 PutFinal_Put 发送对象的put动作(当标识为0x82时说明这是最后的一个Put动作) 0xA0 Success 说明接收端已成功收到put动作发送的所有数据(一般是在成功收到Final_Put标识的数据包后的反馈) 0x90 Continue 说明接收端已收到put动作发送的数据,因为Final_Put还没出现,所以要求发送端继续发送数据。 发送方和接收方是的通信的基本格式如下: 字节0 字节1,2 字节三以后的数据 操作码 整个通信数据包的长度 通讯的数据 以下结合基本传输步骤,对上文列出的数据包使用方法进行讲解: 1、由发送方向接收文件的接收方进行连接请求。 发送方需要使用的操作码为Connect,在OBEX协议中对Connect数据包格式作如下规定: 字节0 字节1、2 字节3 字节4 字节5、6 字节7 Connect操作码(0x80) Connect数据包的总长度 OBEX协议的版本(目前为1.0,16进制表示为0x10) 保留未用,设为0 最大可处理的OBEX包长度 其它的数据包(可选) 服务端根据连接的请求向客户端做出响应: 字节0 字节1、2 字节3 字节4 字节5、6 字节7 响应的操作码 响应数据包的总长度 OBEX协议的版本(目前为1.0,16进制表示为0x10) 保留未用,设为0 最大可处理的OBEX包长度 其它的数据包(可选) 如果接收方允许连接,响应的操作码会为Success(0xA0)其它的响应操作码均被认为连接失败。 2、发送方向接收方发送数据 发送方通过put和Final_Put这两个操作将传输的数据信息向接收方发送。 发送方的Put/Final_Put使用格式。 字节0 字节1,2 字节三以后的数据 Put操作码(0x02)Final_Put操作码(0x82) 整个通信数据包的长度 通讯的数据(由其它的例如name/body等数据包构成) 当最后一次传输对象的数据时要使用Final_Put告知接收方这是最后一个数据包了,以便接收方根据接收到的数据进行处理(例如将接收到的文件存盘)。 接收方的响应格式: 字节0 字节1,2 字节三以后的数据 响应操作码典型的有两个值:Success操作码(0xA0)Continue操作码(0x90 ) 整个通信数据包的长度 通讯的数据(由其它的例如name/body等数据包构成) 如果接收方成功收到put操作的数据,应该返回Continue开始的响应信息,告知发送方继续发送,在成功收到Final_Put发送的数据后,应返回Success响应信息,告知发送方整个对象都接收完成。(但由于部分适配器只会返回Success响应,出于兼容性考虑,在编程中应理解为无论接收到Success或Continue响应都代表数据发送成功。) 3、发送方关闭连接 发送方在最后应以Disconnect信息明确结束连接,这并不是必须的,但推荐使用。 发送方格式: 字节0 字节1,2 字节三以后的数据 Disconnect操作码 整个通信数据包的长度 可选的通讯的数据(由其它的数据包构成) 接收方响应: 字节0 字节1,2 字节三以后的数据 Success操作码(0xA0)服务不可用操作码(0xD3) 整个通信数据包的长度 可选的通讯的数据(由其它的数据包构成) 当成功断开时,接收方会发送Success信息。否则,如果发送方的disconnect操作包含错误信息(例如一个错误的连接ID)时,会返加0xD3操作码。但并不能操作所有接收方的程序都实现这个响应的功能,也就是说,发送方并不能保证一定会得到响应信息。 二、程序实现 .net1.0中对红外的支持全部在System.Net.Sockets空间中,使用很简单,和普通的网络连接差不多,主要有三个类: IrDAClient 提供连接信息,并创建客户端连接对象,用以打开和关闭与服务器的连接。 IrDADeviceInfo 提供客户端在发现查询过程中获取的有关可用服务器和端口的信息。 IrDAListener 将套接字置于侦听状态,以监视来自指定服务或网络地址的连接。 (一)、获取附近可用红外设备的信息 在这个示例中,我获取红外设备通过IrDAClient的DiscoverDevices方法实现,该方法以IrDADeviceInfo类型的对象数组返回附近可用红外设备的相关信息。这个方法唯一的参数表示如果附近有许多红外设备时,最多收集多少个设备的信息。 示例代码如下: Dim taobjIrDADeviceInfo() As Sockets.IrDADeviceInfoDim tobjIrDAClient As New Sockets.IrDAClient'开始检索附近的红外设备并加入到列表中,最多只搜索7个设备taobjIrDADeviceInfo = tobjIrDAClient.DiscoverDevices(7) 在得到的IrDADeviceInfo类型的变量有三个有用的属性,你可根据这些属性的值给用户提示,以便由用户选择应连接到那一个红外设备上: DeviceID 获取红外设备标识符,在连接红外设备中使用 DeviceName 获取红设备名称。 Hints 获取设备的类型,例如是红外手机还是红外PDA之类的说明 (二)、用IrDAClient对象实现红外连接及数据发送 IrDAClient和一般的网络连接对象的使用很相似,使用的基本步骤如下: 1)、先使用connect方法连接指定的红外设备,这个方法需要一个IrDAEndPoint对象作为参数(这个对象指定需连接的红外设备,以及连接到红外设备提供的指定服务上) 示例: Dim tobjIrDAClient As New Sockets.IrDAClient'ni_objIrDADeviceInfo是上文介绍的IrDADeviceInfo对象,以下语句的含义就是连接到'DeviceID指定的红外设备上,这个设备提供OBEX服务。Dim tobjIrDAEndPoint As New IrDAEndPoint(ni_objIrDADeviceInfo.DeviceID, "OBEX")TrytobjIrDAClient.Connect(tobjIrDAEndPoint)Catch ex As ExceptionMessageBox.Show("IrDA Socket Connect 状态失败")End Try 2)、连接成功后就可以使用IrDAClient对象的GetStream 方法获得基础数据流,并利用流Read/Write方法实现数据传输的接收/发送。 示例:两个方法的第一个参数都是一个字节数组 数据发送:tobjIrDAClient.GetStream.Write(tabytTempa, 0, tabytTempa.Length) 数据接收:tobjIrDAClient.GetStream.Read(tabytReceiveBuffer, 0, 7) 3)、完成所有通信后使用流以及IrDAClient的Close方法 关闭连接。 示例:tobjIrDAClient.GetStream.Close() tobjIrDAClient.Close() (三)完整实现代码 其实红外操作在net中实现就是这么简单,不过困难的是对OBEX协议的解释,基于代码重用的原则,我的程序主框架有两个基础类,clsIrDAOBEXOperator封装了文件发送的方法,方法中调用另一个类clsOBEXHeaders,这个类主门用来构建obex协议需要的数据包。代码如下,其中已包括必要的注释: clsIrDAOBEXOperator.vb的代码(代码中fnSendFileToIrDADevice是向红外设备发送文件的方法,它的第一个参数是代表红外设备的IrDADeviceInfo对象,第二个参数就是要发送的文件名),: Imports System.NetImports System.Net.SocketsPublic Class clsIrDAOBEXOperator'OBEX常数Public Const cOBEX_VERSION As Byte = &H10Public Const cOBEX_CONNECTFLAGS As Byte = &H0Public Const cOBEX_CONNECT As Byte = &H80Public Const cOBEX_DISCONNECT As Byte = &H81Public Const cOBEX_PUT As Byte = &H2Public Const cOBEX_NAME As Byte = &H1Public Const cOBEX_PUT_FINAL As Byte = &H82Public Const cOBEX_LENGTH As Byte = &HC3Public Const cOBEX_BODY As Byte = &H48Public Const cOBEX_END_OF_BODY As Byte = &H49Public Const cOBEX_CONTINUE As Byte = &H90Public Const cOBEX_SUCCESS As Byte = &HA0'向外界公布可直接修改的变量Public m_i32OBEXMAXSendBufferLen As Int32 = 255Public m_i32OBEXMAXReceiveBufferLen As Int32 = 1024Public m_i32OBEXMAXPacketSize As Int16 = &H808'将一个16位整数转为2个字节的数组,并存入参数中指定索引开始的字节数组处(低位字在低字节,高位字在高字节)Private Function fnInt16ToByteArray(ByVal ni_i16Convert As Int16, ByRef ni_abytDest() As Byte, ByVal ni_i32StartIndex As Int32) As Booleanni_abytDest(ni_i32StartIndex) = ni_i16Convert And &HFFni_abytDest(ni_i32StartIndex + 1) = ni_i16Convert >> 8End Function'将一个16位整数转为2个字节的数组,并存入参数中指定索引开始的字节数组处Private Function fnInt16ToByteArrayLowByteToHightPosition(ByVal ni_i16Convert As Int16, ByRef ni_abytDest() As Byte, ByVal ni_i32StartIndex As Int32) As Booleanni_abytDest(ni_i32StartIndex + 1) = ni_i16Convert And &HFFni_abytDest(ni_i32StartIndex) = ni_i16Convert >> 8End Function'将一个32位整数转为4个字节的数组,并存入参数中指定索引开始的字节数组处Private Function fnInt32ToByteArrayLowByteToHightPosition(ByVal ni_i32Convert As Int16, ByRef ni_abytDest() As Byte, ByVal ni_i32StartIndex As Int32) As BooleanDim ti32Tempa As Int32 = ni_i32Convertni_abytDest(ni_i32StartIndex + 3) = ni_i32Convert And &HFFni_abytDest(ni_i32StartIndex + 2) = (ni_i32Convert And &HFF00) >> 8ni_abytDest(ni_i32StartIndex + 1) = (ni_i32Convert And &HFF0000) >> 16ni_abytDest(ni_i32StartIndex) = (ti32Tempa And &HFF000000) >> 24End Function'将本设备中指定的文件传到指定的设备中去Public Function fnSendFileToIrDADevice(ByVal ni_objIrDADeviceInfo As IrDADeviceInfo, _ByVal ni_strFilePath As String) As Boolean'ni_objIrDADeviceInfo:指定红外设备的IrDAInfo结构'ni_strFilePath:要传输的文件路径'返回值:成功返回trueDim tobjIrDAClient As New Sockets.IrDAClientDim tobjIrDAEndPoint As New IrDAEndPoint(ni_objIrDADeviceInfo.DeviceID, "OBEX")Dim tabytSendBuffer(m_i32OBEXMAXSendBufferLen * 2) As ByteDim tabytReceiveBuffer(m_i32OBEXMAXReceiveBufferLen) As ByteDim tblnTemp As BooleanDim ti32Tempa As Int32, ti32TempB As Int32, tieTempC As Int32Dim tbytTempa As ByteDim ti32LoopA As Int32Dim tobjBinaryReader As IO.BinaryReaderDim tobjFileStream As IO.FileStreamDim tabytTempa() As Byte, tabytTempb() As Byte, tabytTempC() As Byte, tabytTempD() As ByteDim tabytTempE() As ByteDim tobjOBEX_HEADERS As New clsOBEXHeadersDim ti32SendPackageSpare As Int32 '保存最大发送包数组-当前数据后的剩余空间Dim tobjFileInfo As IO.FileInfotobjFileInfo = New IO.FileInfo(ni_strFilePath)TryTrytobjIrDAClient.Connect(tobjIrDAEndPoint)Catch ex As ExceptionMessageBox.Show("IrDA Socket Connect 状态失败")Return FalseEnd Try'创建一个最简单的连接信息tabytTempa = tobjOBEX_HEADERS.fnCreateConnectHeaderRequest(, , , m_i32OBEXMAXPacketSize)TrytobjIrDAClient.GetStream.Write(tabytTempa, 0, tabytTempa.Length)tobjIrDAClient.GetStream.Flush()Catch ex As ExceptionMessageBox.Show("OBEX_CONNECT信息发送失败")Application.DoEvents()Return FalseEnd TryIf tobjIrDAClient.GetStream.CanRead = True ThenTrytobjIrDAClient.GetStream.Read(tabytReceiveBuffer, 0, 7)Catch ex As ExceptionMessageBox.Show("接收OBEX_CONNECT响应消息失败")Return FalseEnd TryIf tabytReceiveBuffer(0) <> cOBEX_SUCCESS ThenMessageBox.Show("OBEX_CONNECT没接收到相应的响应")Return FalseEnd IfEnd If'发送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)'将名称、时间、文件长度等基本信息先发出去TrytobjIrDAClient.GetStream.Write(tabytTempa, 0, tabytTempa.Length)Catch ex As ExceptionReturn FalseEnd TryTrytobjIrDAClient.GetStream.Read(tabytReceiveBuffer, 0, tabytReceiveBuffer.Length)Catch ex As Exception'接收服务器端响应时失败tobjIrDAClient.GetStream.Close()tobjIrDAClient.Close()Return FalseEnd TryIf tabytReceiveBuffer(0) <> cOBEX_SUCCESS And tabytReceiveBuffer(0) <> cOBEX_CONTINUE Then'没有收到服务器的对应的响应信息 tobjIrDAClient.GetStream.Close()tobjIrDAClient.Close()Return FalseEnd If'开始正式发送文件的数据TrytobjFileStream = IO.File.Open(ni_strFilePath, IO.FileMode.Open, IO.FileAccess.Read)tobjBinaryReader = New IO.BinaryReader(tobjFileStream)Catch ex As ExceptionMessageBox.Show("打开文件时出现错误")tobjIrDAClient.GetStream.Close()tobjIrDAClient.Close()Return FalseEnd Try'读出文件的数据放到body中,总长度必须少于最大发送长度-put标志的3字节-body标志的3字节'最多可发送的文件信息长度ti32SendPackageSpare = m_i32OBEXMAXSendBufferLen - 6'循环读取文件的内容,并发送到服务方For ti32LoopA = 1 To Math.Ceiling(tobjFileInfo.Length / ti32SendPackageSpare)TrytabytTempa = tobjBinaryReader.ReadBytes(ti32SendPackageSpare)Catch ex As ExceptiontobjIrDAClient.GetStream.Close()tobjIrDAClient.Close()Return FalseEnd Try'构建合适的put包并发送tabytTempb = tobjOBEX_HEADERS.fnCreateBodyHeader(tabytTempa) 'body标志tabytTempa = tobjOBEX_HEADERS.fnCreatePutHeader(tabytTempb)'开始发送TrytobjIrDAClient.GetStream.Write(tabytTempa, 0, tabytTempa.Length)tobjIrDAClient.GetStream.Flush()Catch ex As ExceptiontobjIrDAClient.GetStream.Close()tobjIrDAClient.Close()Return FalseEnd TryTrytobjIrDAClient.GetStream.Read(tabytReceiveBuffer, 0, tabytReceiveBuffer.Length)Catch ex As Exception'接收服务器端响应时失败tobjIrDAClient.GetStream.Close()tobjIrDAClient.Close()Return FalseEnd TryIf tabytReceiveBuffer(0) <> cOBEX_SUCCESS And tabytReceiveBuffer(0) <> cOBEX_CONTINUE Then'没有收到服务器的对应的响应信息tobjIrDAClient.GetStream.Close()tobjIrDAClient.Close()Return FalseEnd IfNext'关闭文件tobjBinaryReader.Close()tobjFileStream.Close()If ti32Tempa ThenEnd If'文件数据已全部发送完毕,发送结束的final_put 包'endbody包tabytTempa = tobjOBEX_HEADERS.fnCreateEndOfBodyHeader(Nothing)'putfinaltabytTempa = tobjOBEX_HEADERS.fnCreatePut_FinalHeaderResponse(tabytTempa)TrytobjIrDAClient.GetStream.Write(tabytTempa, 0, tabytTempa.Length)tobjIrDAClient.GetStream.Flush()Catch ex As ExceptiontobjIrDAClient.GetStream.Close()tobjIrDAClient.Close()Return FalseEnd TryTrytobjIrDAClient.GetStream.Read(tabytReceiveBuffer, 0, tabytReceiveBuffer.Length)Catch ex As ExceptiontobjIrDAClient.GetStream.Close()tobjIrDAClient.Close()Return FalseEnd TryIf tabytReceiveBuffer(0) <> cOBEX_SUCCESS Then'没有收到服务器的对应的响应信息tobjIrDAClient.GetStream.Close()tobjIrDAClient.Close()Return FalseEnd If'发送disconnect包tabytTempa = tobjOBEX_HEADERS.fnCreateDisConnectHeaderRequest()TrytobjIrDAClient.GetStream.Write(tabytTempa, 0, tabytTempa.Length)tobjIrDAClient.GetStream.Flush()Catch ex As ExceptiontobjIrDAClient.GetStream.Close()tobjIrDAClient.Close()Return FalseEnd TrytobjIrDAClient.Close()Catch ex As ExceptionMessageBox.Show("过程发生不明错误")Return FalseEnd Try'代码能来到这儿就是正常完成任务了MsgBox("红外操作成功")Return TrueEnd FunctionEnd ClassclsOBEXHeaders.vb文件的代码:Public Class clsOBEXHeaders#Region "OBEX常数"Public Const cOBEX_VERSION As Byte = &H10Public Const cOBEX_CONNECTFLAGS As Byte = &H0Public Const cOBEX_CONNECT As Byte = &H80Public Const cOBEX_DISCONNECT As Byte = &H81Public Const cOBEX_PUT As Byte = &H2Public Const cOBEX_NAME As Byte = &H1Public Const cOBEX_PUT_FINAL As Byte = &H82Public Const cOBEX_LENGTH As Byte = &HC3Public Const cOBEX_BODY As Byte = &H48Public Const cOBEX_END_OF_BODY As Byte = &H49Public Const cOBEX_TIME_ISO As Byte = &H44Public Const cOBEX_CONTINUE As Byte = &H90Public Const cOBEX_SUCCESS As Byte = &HA0#End Region#Region "类内私有函数"'将一个16位整数转为2个字节的数组,并存入参数中指定索引开始的字节数组处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 &HFFni_abytDest(ni_i32StartIndex) = ni_i16Convert >> 8End Sub''将一个16位整数转为2个字节的数组,高位字放入高字节,并存入参数中指定索引开始的字节数组处'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位整数转为4个字节的数组,并存入参数中指定索引开始的字节数组处Private Sub sbInt32ToByteArrayLowByteToHightPosition(ByVal ni_i32Convert As Int16, ByRef ni_abytDest() As Byte, ByVal ni_i32StartIndex As Int32)Dim ti32Tempa As Int32 = ni_i32Convertni_abytDest(ni_i32StartIndex + 3) = ni_i32Convert And &HFFni_abytDest(ni_i32StartIndex + 2) = (ni_i32Convert And &HFF00) >> 8ni_abytDest(ni_i32StartIndex + 1) = (ni_i32Convert And &HFF0000) >> 16ni_abytDest(ni_i32StartIndex) = (ti32Tempa And &HFF000000) >> 24End Sub#End Region'创建一个新的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 ByteIf Not (ni_abytOtherHeaders Is Nothing) ThenReDim tabytFuncReturn(7 + ni_abytOtherHeaders.Length - 1)ElseReDim tabytFuncReturn(6)End IftabytFuncReturn(0) = cOBEX_CONNECTtabytFuncReturn(3) = ni_bytOBEX_VersiontabytFuncReturn(4) = ni_bytFlagssbInt16ToByteArrayLowByteToHightPosition(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 IfReturn tabytFuncReturnEnd Function'创建一个新的ConnectHeader的服务器端响应信息数据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 ByteIf Not (ni_abytOtherHeaders Is Nothing) ThenReDim tabytFuncReturn(7 + ni_abytOtherHeaders.Length - 1)ElseReDim tabytFuncReturn(6)End IftabytFuncReturn(0) = cOBEX_SUCCESStabytFuncReturn(3) = ni_bytOBEX_VersiontabytFuncReturn(4) = ni_bytFlagssbInt16ToByteArrayLowByteToHightPosition(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 IfReturn tabytFuncReturnEnd Function'创建一个新的DisConnectHeader客户请求信息Public Function fnCreateDisConnectHeaderRequest(Optional ByVal ni_abytOtherHeaders As Byte() = Nothing) As Byte()Dim tabytFuncReturn() As ByteIf Not (ni_abytOtherHeaders Is Nothing) Then '有其它的数据包要附在后面ReDim tabytFuncReturn(3 + ni_abytOtherHeaders.Length - 1)ElseReDim tabytFuncReturn(2)End IftabytFuncReturn(0) = cOBEX_DISCONNECTIf 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 IfReturn tabytFuncReturnEnd Function'创建一个新的ContinueHeader信息Public Function fnCreateContinueHeaderResponse(Optional ByVal ni_abytOtherHeaders As Byte() = Nothing) As Byte()Dim tabytFuncReturn() As ByteIf Not (ni_abytOtherHeaders Is Nothing) Then '有其它的数据包要附在后面ReDim tabytFuncReturn(3 + ni_abytOtherHeaders.Length - 1)ElseReDim tabytFuncReturn(2)End IftabytFuncReturn(0) = cOBEX_CONTINUEIf 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 IfReturn tabytFuncReturnEnd Function'创建一个新的SuccessHeader信息Public Function fnCreateSuccessHeaderResponse(Optional ByVal ni_abytOtherHeaders As Byte() = Nothing) As Byte()Dim tabytFuncReturn() As ByteIf Not (ni_abytOtherHeaders Is Nothing) Then '有其它的数据包要附在后面ReDim tabytFuncReturn(3 + ni_abytOtherHeaders.Length - 1)ElseReDim tabytFuncReturn(2)End IftabytFuncReturn(0) = cOBEX_SUCCESSIf 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 IfReturn tabytFuncReturnEnd Function'创建一个新的TimeHeader信息Public Function fnCreateTimeHeaderISO(ByVal ni_dtmDate As Date, Optional ByVal ni_abytOtherHeaders As Byte() = Nothing) As Byte()Dim tabytFuncReturn() As ByteDim tstrDate As StringDim 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.NullChartstrDate = String.Format("{0:yyyy/MM/dd\THH:mm:ss\Z}", ni_dtmDate) & ControlChars.NullChartabytTempa = Text.Encoding.BigEndianUnicode.GetBytes(tstrDate)If Not (ni_abytOtherHeaders Is Nothing) Then '有其它的数据包要附在后面ReDim tabytFuncReturn(3 + tabytTempa.Length + ni_abytOtherHeaders.Length - 1)ElseReDim tabytFuncReturn(2 + tabytTempa.Length)End IftabytFuncReturn(0) = cOBEX_TIME_ISOtabytTempa.CopyTo(tabytFuncReturn, 3) '将时间字节串放入返回数组中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 IfReturn tabytFuncReturnEnd Function'创建一个新的BodyHeader信息Public Function fnCreateBodyHeader(ByVal ni_abytBodyContent() As Byte, Optional ByVal ni_abytOtherHeaders As Byte() = Nothing) As Byte()Dim tabytFuncReturn() As ByteDim tabytTempa As ByteDim ti32BodyContentLength As Int32 = 0'定义合适大小的数组以容纳bodyheader的内容If Not (ni_abytBodyContent Is Nothing) Then '有body的内容If Not (ni_abytOtherHeaders Is Nothing) Then '有其它的数据包要附在后面ReDim tabytFuncReturn(3 + ni_abytBodyContent.Length + ni_abytOtherHeaders.Length - 1)ni_abytBodyContent.CopyTo(tabytFuncReturn, 3)ni_abytOtherHeaders.CopyTo(tabytFuncReturn, ni_abytBodyContent.Length + 3)ElseReDim tabytFuncReturn(2 + ni_abytBodyContent.Length)ni_abytBodyContent.CopyTo(tabytFuncReturn, 3)End IfElse '没有body的内容If Not (ni_abytOtherHeaders Is Nothing) Then '有其它的数据包要附在后面ReDim tabytFuncReturn(3 + ni_abytOtherHeaders.Length - 1)ni_abytOtherHeaders.CopyTo(tabytFuncReturn, 3)ElseReDim tabytFuncReturn(2)End IfEnd IftabytFuncReturn(0) = cOBEX_BODY'加入包的长度Call sbInt16ToByteArrayLowByteToHightPosition(tabytFuncReturn.Length, tabytFuncReturn, 1)Return tabytFuncReturnEnd Function'创建一个新的EndOfBodyHeader信息Public Function fnCreateEndOfBodyHeader(ByVal ni_abytBodyContent() As Byte, Optional ByVal ni_abytOtherHeaders As Byte() = Nothing) As Byte()Dim tabytFuncReturn() As ByteDim tabytTempa As ByteDim ti32BodyContentLength As Int32 = 0If Not (ni_abytBodyContent Is Nothing) ThenIf Not (ni_abytOtherHeaders Is Nothing) Then '有其它的数据包要附在后面ReDim tabytFuncReturn(3 + ni_abytBodyContent.Length + ni_abytOtherHeaders.Length - 1)ni_abytBodyContent.CopyTo(tabytFuncReturn, 3)ni_abytOtherHeaders.CopyTo(tabytFuncReturn, 3 + ni_abytBodyContent.Length)ElseReDim tabytFuncReturn(2 + ni_abytBodyContent.Length)ni_abytBodyContent.CopyTo(tabytFuncReturn, 3)End IfElse '没有body内容If Not (ni_abytOtherHeaders Is Nothing) Then '有其它的数据包要附在后面ReDim tabytFuncReturn(3 + ni_abytOtherHeaders.Length - 1)ni_abytOtherHeaders.CopyTo(tabytFuncReturn, 3)ElseReDim tabytFuncReturn(2)End IfEnd If'加入包的长度 Call sbInt16ToByteArrayLowByteToHightPosition(tabytFuncReturn.Length, tabytFuncReturn, 1)tabytFuncReturn(0) = cOBEX_END_OF_BODYReturn tabytFuncReturnEnd Function'创建一个新的LengthHeader信息Public Function fnCreateLengthHeader(ByVal ni_i32Length As Int32) As Byte()Dim tabytFuncReturn() As ByteReDim tabytFuncReturn(4)tabytFuncReturn(0) = cOBEX_LENGTH'加入包的内容Call sbInt32ToByteArrayLowByteToHightPosition(ni_i32Length, tabytFuncReturn, 1)Return tabytFuncReturnEnd Function'创建一个新的NameHeader信息Public Function fnCreateNameHeader(ByVal ni_strName As String, Optional ByVal ni_abytOtherHeaders As Byte() = Nothing) As Byte()Dim tabytFuncReturn() As ByteDim tabytTempa() As ByteDim ti32BodyContentLength As Int32 = 0tabytTempa = Text.Encoding.BigEndianUnicode.GetBytes(ni_strName & ControlChars.NullChar)If ni_strName <> "" ThenIf Not (ni_abytOtherHeaders Is Nothing) Then '有其它的数据包要附在后面ReDim tabytFuncReturn(3 + tabytTempa.Length + ni_abytOtherHeaders.Length - 1)Else '没有其它数据包附后ReDim tabytFuncReturn(2 + tabytTempa.Length)End IfElseIf Not (ni_abytOtherHeaders Is Nothing) Then '有其它的数据包要附在后面ReDim tabytFuncReturn(3 + ni_abytOtherHeaders.Length - 1)ElseReDim tabytFuncReturn(2)End IfEnd IftabytFuncReturn(0) = cOBEX_NAMEIf ni_strName <> "" ThenIf 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 IftabytTempa.CopyTo(tabytFuncReturn, 3)Else '没有实际的body数据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 IfEnd IfReturn tabytFuncReturnEnd Function'创建一个新的PutHeader信息Public Function fnCreatePutHeader(Optional ByVal ni_abytOtherHeaders As Byte() = Nothing) As Byte()Dim tabytFuncReturn() As ByteIf Not (ni_abytOtherHeaders Is Nothing) Then '有其它的数据包要附在后面ReDim tabytFuncReturn(3 + ni_abytOtherHeaders.Length - 1)ElseReDim tabytFuncReturn(2)End IftabytFuncReturn(0) = cOBEX_PUTIf 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 IfReturn tabytFuncReturnEnd Function'创建一个新的PutHeader信息Public Function fnCreatePut_FinalHeaderResponse(Optional ByVal ni_abytOtherHeaders As Byte() = Nothing) As Byte()Dim tabytFuncReturn() As ByteIf Not (ni_abytOtherHeaders Is Nothing) Then '有其它的数据包要附在后面ReDim tabytFuncReturn(3 + ni_abytOtherHeaders.Length - 1)ElseReDim tabytFuncReturn(2)End IftabytFuncReturn(0) = cOBEX_PUT_FINALIf 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 IfReturn tabytFuncReturnEnd FunctionEnd Class 以上代码均为VB.net 2003编写,在我的多普达515手机加红外适配器上测试通过,不过红外传输是一个相对比较专业的课题,我的代码并不是足够健壮和可靠,希望对这方面有研究的朋友与我探讨。我的QQ:85403578,邮箱:missilecat@163.com。

评论