賈小文,賀秀良
(軍事交通學(xué)院 基礎(chǔ)部,天津300161)
串行通信是計算機(jī)與外圍設(shè)備進(jìn)行數(shù)據(jù)通信常見的通信方式。按電氣標(biāo)準(zhǔn)和協(xié)議串行通信標(biāo)準(zhǔn) 有 RS232-C、RS422、RS485、USB 等[1-2]。RS232-C(ANSI/EIA232 標(biāo)準(zhǔn))是IBM-PC 及其兼容機(jī)上的串行連接標(biāo)準(zhǔn)。由于個人計算機(jī)的普及,RS232-C 成為使用最為廣泛的串口通信標(biāo)準(zhǔn)。通用串行總線(universal serial bus,USB)是一個新的外部總線標(biāo)準(zhǔn),于20 世紀(jì)90 年代由英特爾、康柏、IBM、微軟等多家公司聯(lián)合推出,由于支持熱插拔、即插即用、傳輸速率高等原因,目前被計算機(jī)廣泛用為與外設(shè)進(jìn)行串行通信的標(biāo)準(zhǔn)接口[3]。筆記本計算機(jī)由于其輕薄的特點,絕大多數(shù)并不提供RS232-C 串口,也即普通意義上的“COM”串口,但都提供USB 接口。當(dāng)筆記本計算機(jī)與僅支持RS232 串口的設(shè)備進(jìn)行串行通信時,通常需要從USB 到RS232 的轉(zhuǎn)換。這種轉(zhuǎn)換可以通過專用的芯片完成,比較成熟的芯片有PL2303、CP2102 等[4-5]。通過USB—RS232 轉(zhuǎn)換,可以方便地利用筆記本對支持串口通信的設(shè)備進(jìn)行讀寫操作。
CSerialPort 類是為了方便對RS232 串口操作而開發(fā)的一個C + +類,可以代替常用的ActiveX控件進(jìn)行串口應(yīng)用開發(fā)。該類封裝了相關(guān)的文件操作Windows API 函數(shù),采用異步文件讀寫模型,結(jié)構(gòu)良好,功能明確,能夠滿足絕大多數(shù)串口開發(fā)應(yīng)用場合[6]。但是,由于串口應(yīng)用環(huán)境的復(fù)雜性,CSerialPort 類存在一些漏洞,特別是在進(jìn)行USB—RS232 串口讀寫操作時,不能向串口寫入數(shù)據(jù)。本文分析了這些漏洞產(chǎn)生的原因,并給出了修正漏洞的方案。
1 CSerialPort 類分析和使用
在Windows 環(huán)境下,開發(fā)RS232 串口經(jīng)常采用的方法是使用ActiveX 控件或者直接采用Windows API 函數(shù)。
當(dāng)采用ActiveX 控件時,通常使用的是微軟開發(fā)的MSComm 控件。MSComm 控件屬于微軟組件對象模型(component object model,COM)的產(chǎn)品,為應(yīng)用程序提供了串行接口收發(fā)數(shù)據(jù)的簡便方法。
MSComm 采用事件驅(qū)動方式和查詢方式,提供了一系列標(biāo)準(zhǔn)通信命令和接口,可以方便地與串口建立連接并對串口發(fā)送數(shù)據(jù)和接收數(shù)據(jù)。MSComm 與開發(fā)環(huán)境無關(guān),無論是VC、VB,還是Dephi 等流行開發(fā)工具都能使用。MSComm 的缺點是可定制性不強(qiáng),對于復(fù)雜的串口應(yīng)用場合缺乏靈活性。MSComm 屬于ActiveX 控件,必須注冊以后才能使用,增加了程序的體積,給使用上帶來不便。當(dāng)MSComm 不能滿足使用要求時,就必須利用Windows API 直接進(jìn)行串口操作。
利用Windows API 對串口讀寫操作的困難在于異步文件讀寫的復(fù)雜性,要寫出高效穩(wěn)定的串口讀寫程序需要相當(dāng)?shù)木幊讨R和技巧。這實際上限制了利用API 直接操作串口的可行性。
CSerialPort 本質(zhì)上屬于利用Windows API 對串口進(jìn)行操作這種形式。但它以類的形式將相關(guān)Win32 API 以及對串口文件異步操作所涉及到的多線程、線程同步等復(fù)雜編程技術(shù)封裝起來,大大降低了對串口讀寫操作的復(fù)雜性,提供給使用者比MSComm 更簡單和直接的使用接口。與MSComm 控件COM 訪問方式相比較,CSerialPort不涉及對讀寫數(shù)據(jù)的封裝和轉(zhuǎn)換。CSerialPort 以C + +代碼類的方式提供,可以直接包含到程序源代碼里,不像MSComm 必須安裝注冊控件才能使用。CSerialPort 結(jié)構(gòu)良好,對串口的操作采用典型成熟的多線程異步Overlapped 文件讀寫模型,所有的源代碼都是公開透明的,使用者可以通過修改或者直接從該類派生而擴(kuò)展該類的功能,寫出功能更強(qiáng)的串口操作應(yīng)用程序。同時該類也是一份很好的關(guān)于串口讀寫操作Win32 API 編程的技術(shù)范例,對于開發(fā)自己個性化的串口讀寫應(yīng)用具有一定參考價值[2]。
CSerialPort 屬于事件驅(qū)動,使用非常簡單,讀寫串口前先產(chǎn)生該類的實例,1 個串口對應(yīng)1 個實例。主程序通過直接調(diào)用實例的寫操作接口和關(guān)閉接口進(jìn)行寫操作和關(guān)閉操作,通過響應(yīng)消息的方式進(jìn)行讀操作。串口檢測到的其他事件也以消息的方式發(fā)送給主程序,主程序通過響應(yīng)該消息來處理相應(yīng)的串口事件。表1 為CSerialPort 定義的基本消息,表2 為CSerialPort 提供的接口函數(shù)。關(guān)于該類的詳細(xì)使用方法可參考文獻(xiàn)[7]。

表1 CSerialPort 消息

表2 CSerialPort 主要接口函數(shù)(不含返回類型和函數(shù)參數(shù))
2 CSerialPort 類漏洞的分析和修正
CSerialPort 最初發(fā)布只是解決了串口讀寫操作最關(guān)鍵的部分,亦即多線程異步overlapped 文件讀寫機(jī)制實現(xiàn),并未充分考慮串口操作所涉及到的一些細(xì)節(jié)問題,而是把這些問題留給了使用者。使用者可以利用其開源特性,根據(jù)自己的應(yīng)用需求直接對源類進(jìn)行擴(kuò)充和修改,實現(xiàn)自己要求的功能。這些細(xì)節(jié)問題,如果在使用的過程中不注意,就會成為程序的漏洞,嚴(yán)重者會導(dǎo)致串口操作失敗。
2.1 寫操作漏洞
CSerialPort 提供寫操作接口如下:

當(dāng)要向串口寫入數(shù)據(jù)時,CSerialPort 將寫操作事件m_hWriteEvent 置為有信號狀態(tài),同時將待寫入字符串拷貝到寫入緩沖區(qū)m_szWriteBuffer,并指定寫入字符長度m_nWriteSize。由于寫事件為有信號狀態(tài),監(jiān)聽線程通過查詢該信號狀態(tài)調(diào)用Windows API 函數(shù)WriteFile 將數(shù)據(jù)寫入串口。上述寫操作函數(shù)在寫入二進(jìn)制數(shù)據(jù)時存在問題。
strcpy 和strlen 函數(shù)都是以標(biāo)準(zhǔn)C/C + +字符串作為操作對象。在C/C + + 規(guī)范中,標(biāo)準(zhǔn)字符串是以“