OPC客戶端開發的簡單整理

簡要

本文是對前段時間因公司需要而實現的opc客戶端的一個總結,主要是opcda的客戶端,opcua客戶端做了一個建模比較簡單的(涉及到建模,後面因公司決定採用其他方式對接,後續沒做深究)。關於opc協議,網上的資料很多,這裏主要是便於以後自己的溫習,結合開發過程中踩過的坑做一個簡單的整理,可能有些內容和別的博客有相似,如果有覺得不妥的,請及時聯繫我,謝謝大家!

OPC協議簡介

1、協議理解
OPC(OLE for Process Control)就是爲了不同的供應商的device和應用程序之間的接口標準化,使他們的數據變得更加的簡單化而提出的一種標準或者說是規範。

實際運用中以OPCDA、OPCUA這兩種類型爲主。筆者因公司要做行業集成,主要也是接觸這兩種協議。下面簡單介紹一下這兩種協議。

OPCDA是在windows的com/dcom技術上定義的接口定義,在TCP IP七層模型的最高層應用層,決定了它必須在windows平臺,不能夠跨平臺,靈活性和安全性不如OPC UA,因爲OPC DA的會話層和表示層用戶是有權利來決定的。

爲了應對標準化和跨平臺的趨勢,推出了新的標準OPC UA,該接口協議包含了之前的A&E,DA,OPC XMLDA or HDA,只使用一個地址空間就能訪問之前的所有對象,而且不受windows平臺的限制,具有跨平臺性。一個通用接口集成了之前所有OPC的特性和信息。
OPC UA不再是基於分佈式組件對象模型DCOM,而是以面向服務的架構SOA爲基礎

2、兩種類型的區別
a)OPC雖然通過配置COM\DOM來提供數據加密和簽名功能,配置防火牆,用戶權限來讓數據訪問變得更加安全,但是會增加額外的工作量,而對於OPC UA,這些都是默認的功能;
b)另外基於DOM的OPC使用的是動態端口分配,端口不固定,讓防火牆難以確定,但是對於OPC UA的端口都是唯一的;
c)核心的區別是因爲OPC和OPC UA協議使用的TCP層不一樣,OPC是基於DOM\COM上,應用層最頂層,OPC UA是基於TCP IPsocket傳輸層

COM技術

1、COM簡介
因爲OPC是基於COM組件進行通信的,因此對COM有個簡單的瞭解有利於後續對COM接口的使用,下面是百度百科對COM的解釋:

COM(Component Object Model,組件對象模型),是由微軟推出的一套接口規範,通過設定不同組件之間需要遵守的標準與協議,主要用來跨語言、跨進程之間的模塊通信

這裏推薦一個很好的博客,有助於對COM有個更好的瞭解。用VC進行COM編程所必須掌握的理論知識

2、OPC和COM之間的關係
OPC是建立在COM技術基礎之上的,COM技術的出現爲簡單的實現控制設備和控制管理系統之間的數據交換提供了技術基礎,但是如果不提供一個工業標準化的com接口,各個控制設備廠家開發的com組件之間的相互連接任然是不可能的。

客戶程序和組件程序通過接口進行相互之間的通信,組件程序就是通過接口暴露它的功能給客戶程序的,而com客戶程序是可能看見組件對象本身的,僅有接口時可見的,它告訴客戶程序能利用組件幹什麼,如何利用它的功能。

OPCDA客戶端開發流程

開發客戶端之前,要先確認opc的服務端採用的是哪個版本的協議庫,客戶端和服務端的協議庫版本必須保持一致,因爲每個版本的接口可能不太一樣。(如果需要2.0版本和3.0版本的接口標準說明書,如有需要可以聯繫我)
下面簡單介紹一下流程,因爲網上能找到代碼,這裏不再做過多的代碼體現。

1.註冊OPC接口組件

	hr = CoInitializeEx(NULL, COINITBASE_MULTITHREADED);    //註冊DCOM組件,獲取結果
	HRESULT hr_sec = CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_NONE, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL);

2.通過COM接口創建OPCServerlist接口指針,CoCreateInstance只能遍歷本機,CoCreateInstanceEx可以遍歷遠程機器OPC

	si.pwszName = A2W(strNode);
	mqi[0].hr = S_OK;
	mqi[0].pIID = &IID_IOPCServerList;
	mqi[0].pItf = NULL;
	hr = CoCreateInstanceEx(CLSID_OpcServerList, NULL, CLSCTX_REMOTE_SERVER, &si, 1, mqi);

3.枚舉OPC服務器列表。通過IOPCServerlist接口EnumClassesOfCategories方法

	do
	{
		hr_1 = pIEnumGUID->Next(20, clsid, &nCount);
		for (ULONG i = 0; i < nCount; i++)
		{
			LPOLESTR szProID;
			LPOLESTR szUserType;
			HRESULT hr_2 = pIServerList->GetClassDetails(clsid[i], &szProID, &szUserType);
			poco_assert(hr_2 == S_OK);
			USES_CONVERSION;
			char* ID = OLE2A((LPOLESTR)szProID);
			LOG_INFO("port%d:%s", i + 1, &ID);
			CoTaskMemFree(szProID);
			CoTaskMemFree(szUserType);
		}
	} while (hr_1 == S_OK);

4.連接opc服務器

	mqi[0].hr = S_OK;
	mqi[0].pIID = &IID_IOPCServer;
	mqi[0].pItf = NULL;

	hr = CoCreateInstanceEx(clsid_citect, NULL, CLSCTX_REMOTE_SERVER, &si, 1, mqi);

5.添加group。這步如果沒有做,默認分配一個group名。

	hr = m_pOPCServer->AddGroup(L"Group", TRUE, 10, 1235, &lTimeBias, &fTem, 1033, &m_hOPCServer1, &dwActualRate, IID_IOPCItemMgt, (LPUNKNOWN*)&m_pIOPCItemMgt);

6.遍歷服務器上的Item項。這裏需要考慮到節點的結構,屬於flat、leaf還是branch的結構,依情況處理。


	HRESULT hr;
	hr = pBSAS->ChangeBrowsePosition(OPC_BROWSE_TO, lpcw);       //to root
	IEnumString *pEnum = 0;
	hr = pBSAS->BrowseOPCItemIDs(OPC_BRANCH, L"", VT_EMPTY, 0, &pEnum);
	LPOLESTR pStr = NULL;
	ULONG actual = 0;
	char bufName[256] = { 0 };   
	while ((hr = pEnum->Next(1, &pStr, &actual)) == S_OK)
	{
		WideCharToMultiByte(CP_ACP, 0, pStr, -1, bufName, 256, NULL, NULL);
		m_pItemName.push_back(bufName);
		m_size = m_pItemName.size();
		TryBrowseBranch(pBSAS, pStr);
    }

8.讀取數據。這裏可以選擇同步讀取,也可以採用訂閱式異步讀取。

	HRESULT hres = AtlAdvise(pIOPCGroupStateMgt, this, IID_IOPCDataCallback, &dwCookie);

筆者之前採用的是訂閱式的方式去讀取的,採用的這個接口:

STDMETHODIMP COPCClient::OnDataChange(DWORD dwTransID,
	OPCHANDLE hGroup,       //Group的句柄
	HRESULT hrMasterQuality,  //當所有的Items的qualitied是good,該值爲s_ok,否則是s_false
	HRESULT hrMasterError,   //當所有的Items的errors爲s_ok,該值爲s_ok,否則是s_false
	DWORD dwCount,           //item的個數
	OPCHANDLE *phClientItems,  //item的句柄
	VARIANT *pvValues,         //item的值
	WORD *pwQualities,    //
	FILETIME *pftTimeStamps,
	HRESULT *pErrors)  //item的hresults信息

opc dcom配置常見的問題

dcom配置的配置,因爲受COM組件的限制,如果採用opcda協議對接的話,就需要在客戶端和服務端都進行dcom配置,如果有一個沒有配好就會導致出錯。配置方法網上能夠找到,如果找不到,可以聯繫我我郵件發給大家。 這裏整理了幾個常見opc dcom配置過程中的問題:

1)Opcclient無法遍歷遠程計算機上的opcserver列表,日誌顯示get target opc serverlist failed
排錯思路: 檢測網絡是否暢通,防火牆是否關閉,Dcom配置未配置

2)opcclient能夠遍歷遠程計算機上的opcserverlist列表,日誌顯示Not connect opcserver which you want ,此時代碼的返回碼一般都是general access denied error
排錯思路:能夠遍歷遠程計算機的opc列表,說明遠程計算機整體的dcom配置已經ok,連接不到目標opcserver,一定是目標opcserver的配置或者opcserver本身的問題,如連接數,未授權等等

3)找不到opcEnum.exe ?
解決方法:將opc服務器文件夾中的四個動態庫以及exe文件分別在windows/system32或者是syswow64下注冊,註冊之後刷新就會出現opcEnum.exe

4)能夠遍歷遠程計算機上的opcserver,也可以連接指定的opcserver,但是無法增加組。
排錯思路:opcclient所在的計算機的opc配置不正確導致。

5)配置opcenum時,如果交互式用戶選項置灰?
解決方法: 找到C:\Windows\syswow64\opcenum.exe將它拖到cmd控制檯,重新註冊,C:Windows\syswow64\opcenum.exe /regserver ,然後重新打開opcenum屬性,32位的系統在C:windows\system32下

6)配置opcenum屬性時,“在此計算機上運行爲灰色”?
解決方法:cmd->mmc comexp.msc /32 .

待解決的問題

在行業集成過程中,因爲集成了多個廠家支持opcda的設備,遇到了個別廠家提供的opc服務器和opc的客戶端必須在一臺服務器上才能夠遍歷到item的情況,如果在不同的PC端,調試代碼會發現在遍歷item的時候會出現“枚舉值越界”的問題,筆者找了幾個開源的opcclient去和連接也是出現同樣的問題(兩臺pc端對接成功過其他支持opcda協議的設備,因此排除dcom未配置成功的原因)。目前還未找到原因,如果大家有知道的或者遇到過的,願不吝賜教,謝謝!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章