国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

在客戶端重新創建對象

2019-11-17 05:38:29
字體:
來源:轉載
供稿:網友

  至今我們還沒有涉及到客戶部分的操作,現在就討論一下。客戶端通過調用服務器端的GetArray()方法來開始整個處理。客戶端將會接收我們在服務器創建的安全對象。客戶端的程序則負責將這塊字節流變成為一個有效的C++對象。以下摘錄了做這部分工作的客戶端代碼:

  // create COM smart pointer from CLSID string

  IBlobDataPtr pI( "TestServer.BlobData.1" );

  SAFEARRAY *psa ;

  // Get the safearray from the server

  pI->GetArray( &psa );

  file:// create a pointer to an object

  CSimpleObj *dummy=NULL;

  file:// blob object to eXPand

  CBlob blob;

  file:// use the blob to expand the safearray into an object

  blob.Expand( (CObject*&)dummy, psa );

  file:// call a method on the object to test it

  dummy->Show(this->m_hWnd, "Client Message");

  // delete the object

  delete dummy;

這段代碼挺簡單的。它使用一個COM智能指針與服務器進行連接。假如你對智能指針不熟悉,這些方便的小對象通過調用CoCreateInstance()就可做所有的工作,與服務器進行連接。

  CBlob類再一次完成這個步驟,這個類與服務器端的那一個是完全相同的。該類代碼事實上是由服務器工程中得到的。將一個安全數組變成一個CSimpleObject的工作由Expand()方法完成。該方法與服務器端調用的Load()方法是相對的。

  // Re-create an object from a SAFEARRAY

  BOOL CBlob::Expand(CObject * &rpObj, SAFEARRAY *psa)

   {

    CMemFile memfile; // memory file for de-serialize

    long lLength; // number of bytes

    char *pBuffer; // buffer pointer

    file:// lock access to array data

    SafeArrayAccessData( psa, (void**)&pBuffer );

    // get number of elements in array. This is the number of bytes

    lLength = psa->rgsabound->cElements;

    // attach the buffer to the memory file

    memfile.Attach((unsigned char*)pBuffer, lLength);

    file:// start at beginning of buffer

    memfile.SeekToBegin();

    file:// create an archive with the attached memory file

    CArchive ar(&memfile, CArchive::loadCArchive::bNoFlushOnDelete);

    // document pointer is not used

    ar.m_pDocument = NULL;

    file:// inflate the object and get the pointer

    rpObj = ar.ReadObject(0);

    // close the archive

    ar.Close();

    file:// Note: pBuffer is freed when the SAFEARRAY is destroyed

    file:// Detach the buffer and close the file

    pBuffer = (char*) memfile.Detach();

    file:// release the safearray buffer

    SafeArrayUnaccessData( psa );

    return TRUE;

  }

這個方法的大部分代碼你也在前面見過了,該方法接收一個安全數組的輸入。我們由安全數組中取出緩沖的數據。CArchive對象負責將緩沖的數據重新創建為對象。

  以下就是我們在剛才的Expand()方法中完成的事情

   1、鎖定訪問安全數組結構,并且得到它的長度(以字節計)。

   2、將安全數組的數據緩沖與一個CMemFile關聯

   3、將CMemFile與一個archive相關聯

   4、使用Archives的ReadObject()方法重新創建對象

   5、將SAFEARRAY的數據緩沖由CMemFile脫離

   6、返回一個指向新創建對象的指針給調用者

  我們在這里談到了許多基層的東西。CBlob類負責串行化和還原對象的繁重工作。COM部分的程序確實是很易懂的。
  性能問題

  我并不是勸說你不要使用這里提出的技巧,不過在性能方面,我要提醒你一下。以上我們提到的東西,對于小和中等大小的對象,可工作得很好的。不過,大型的對象將會有問題,我指的是超過一兆的大型對象。

  問題是,這些大型對象必須放在內存中,它可令系統開始使用分頁。你可能也知道,分頁的效率是很低的,非凡是對于內存少的機器。

  這些問題產生的原因是幾個這樣大的對象都必須同時放在內存中。假如客戶和服務器應用都運行在同一部機器(或者一個進程中),那么在內存中同時可有高達三個這些對象的拷貝。這樣系統開銷就會很大,但這又是不可避免的。

  對于由許多小對象組成的大對象,在串行化處理方面可以作一些調整。你可以調用自己的CArchive,并且用更大的哈希表調用SetStoreParams和SetLoadParams。CArchive使用一個哈希表來存儲類的信息。假如哈希表填滿了,那么串行化的處理將會變得很慢。默認的大小適合用在1000或者更少的對象,要了解如何做到這一點,可看一下sample目錄的CBigArchive類。你可以使用這個類來代替CArchive。在這個工程的CBigArchive類中,我也包含了它的一個例子(在我的例子中并沒有使用CBigArchive)。

  安全數組外的選擇

  安全數組并不是傳送二進行數據的唯一方法。我還簡要提一下其它三個辦法。我可以肯定還有其它的方式。

  1、使用一個VARIANT

  調用VariantInit API函數可創建一個VARIANT數據。該函數初始化VARIANT的數據結構。你還需要設置variant的類型,這可以通過設置它的"vt"成員做到。以下的代碼片段創建一個variant并且將它放到一個安全數組中。

  VARIANT *pVar

  // initialize the variant

  VariantInit( pVar );

  file:// set the variant type to an array of bytes

  pVar->vt = VT_ARRAY + VT_UI1;

  file:// create the safe array pointer

  SAFEARRAY *psa;

  psa = SafeArrayCreateVector( VT_UI1, 0, llen );

  file://Code to load the SAFEARRAY with data

   ...

  file:// assign the SAFEARRAY pointer to the VARIANT

  pVar->parray = psa;

  2、使用MIDL提供的非自動類型

  我們使用SAFEARRAY和VARIANT的原因是可以利用MIDL產生的類庫。該類庫可以簡化調用數據的操作,還提供COM的智能指針。使用一個類庫并不是必須的,但是不這樣做的話,你需要做一些額外的工作。

  MIDL答應一些"custom"(自定義)的數據類型。這些數據類型并不兼容類庫和"automation"的接口。一個二進制對象的MIDL接口可以使用一個byte *,而不是一個安全數組。該接口規范需要包含一些關于調用的明確信息,這些信息在[IN]和[OUT]屬性中定義。

  在TesServer.IDL文件中,我提到了一個關于如何定義MIDL接口的例子。該串行化的處理與這篇文章談到的是一樣的,不過緩沖分配有點不同。以下是IDL的定義。

  file:// get data from server

  HRESULT GetData([out] long* pcLen,[out,size_is(,*pcLen)] byte **pBuffer );

  file:// send data to server

  HRESULT SetData([in] long cLen,[in,unique,size_is(cLen)] byte Buffer[]);

要使用這些接口你將必須做一些調用。"size_is"屬性告訴MIDL如何調用數據。(IDL屬性定義的信息與安全數組的成員變量存儲的信息是一樣的)。調用通過一個由MIDL產生的PRoxy/Stub DLL完成。Proxy/Stub DLL需要建立,并且在客戶和服務器端使用。

  3、使用IStream接口

   一個完全不同的方法是使用標準的IStream接口。我沒有研究過,不過一些編程者堅持說這是唯一的方法。我覺得安全數組也不錯,因此沒有嘗試過,這可能會在未來的文章中提到。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 辽阳县| 泰兴市| 平顺县| 常州市| 巫溪县| 云龙县| 奎屯市| 神农架林区| 昆明市| 长春市| 滕州市| 武胜县| 桓台县| 临汾市| 响水县| 临湘市| 东阳市| 澳门| 东乡族自治县| 司法| 墨脱县| 金昌市| 泰来县| 乐昌市| 文水县| 乾安县| 齐河县| 和林格尔县| 大化| 东丰县| 扬州市| 额济纳旗| 宜春市| 浮梁县| 嘉鱼县| 含山县| 澄江县| 石泉县| 大厂| 清徐县| 平遥县|