改進TightVNC 筆記

2010 4.2->4.8 這一星期裏我對TightVNC 1.3.10作了改進.

但願以下內容對你的調試,或者瞭解tightVNC 運行機制有所幫助.

 

目標是: 溶入到網絡會議系統, p2p 模式無客戶端請求數據. 帶寬要求越小越好.實時性要求不是太高.
可應用於大規模的網絡培訓, 網絡教學. 如 單服務器支持的基於p2p 的上W人的網絡培訓. 等情況.

 

目前我已經實現無連接驅動機制, 來調用TightVNC代碼.

達到了: 服務器到客戶端的數據通信, 完全可以自行處理.


1. 大概情況:
   TightVNC 應用了多種壓縮方法 zlib, jpeg, tight 等. 使用TCP通信, 由客戶端發出rfbFramebufferUpdateRequestMsg
   請求, 服務器端再給出數據的方式.  客戶端收到數據更新到DC, BITMAP, 然後再發出rfbFramebufferUpdateRequestMsg 請求.

   以此方式運行.

 

 本文出自: 阿呆 http://blog.csdn.net/davemin
宣傳: VC 十年技術羣 30107096 歡迎高手加入,本羣只研究VC

 

2. 消息機制:

 4 Bytes(其中1byte爲rbfMsgType, 客戶端代碼注意有一個地方是:MSG_PEEK ) 頭 + body

   rfbMsg -> Header -> body


3. Update 機制:

 RFBMsg Update + Rectangles ( Update )

 Full (全屏所有方塊數據)只應用於第一次.


4. 驅動機制:
 
 Client-> Update Request

 服務器端收到後: RFBMsg

 服務器端 1對多更新方式: TriggerUpdate

只調試第一次的數據方式:
// Update handling
void vncServer::TriggerUpdate()
{
 static bool debugfirst = false;
 if( debugfirst )
  return;

 vncClientList::iterator i;
 
 omni_mutex_lock l(m_clientsLock);

 // Post this update to all the connected clients
 for (i = m_authClients.begin(); i != m_authClients.end(); i++)
 {
  // Post the update
  GetClient(*i)->TriggerUpdate();
 }

 debugfirst = true;
}

 

 本文出自: 阿呆 http://blog.csdn.net/davemin
宣傳: VC 十年技術羣 30107096 歡迎高手加入,本羣只研究VC

 

5. 調試的主要API:
Server:
void vncClientThread::run(void *arg)

Client:
void* ClientConnection::Run();
void* ClientConnection::run_undetached(void* arg)


6. 最簡單PixelFormat 設置:
 因爲沒有客戶商反回請求數據了.所以只能直接設置.

  rfbClientToServerMsg msg;
  msg.spf.format.bitsPerPixel = 8;
  msg.spf.format.depth = 8;
  msg.spf.format.bigEndian = 0;
  msg.spf.format.trueColour = 1;

  msg.spf.format.redMax = 7;
  msg.spf.format.greenMax = 7;
  msg.spf.format.blueMax = 3;

  msg.spf.format.redShift = 0;
  msg.spf.format.greenShift = 3;
  msg.spf.format.blueShift = 6;

  msg.spf.format.pad1 = 0;
  msg.spf.format.pad2 = 0;

 

7. 服務器端MAIN LOOP

 此處只處理: Update Request, 當然這個Request 我只能自己製造出來.
 
因此在:
 // MAIN LOOP
 while (connected)
代碼之前必須設置兩個重要項:
 a. pixel format  參考 6
 b. encoding

encoding 我的設置如下:
void vncClientThread::setencoding()
{
 m_client->m_buffer->SetQualityLevel(-1);
 m_client->m_buffer->SetCompressLevel(6);
 m_client->m_buffer->EnableXCursor(FALSE);
 m_client->m_buffer->EnableRichCursor(FALSE);
 m_client->m_buffer->EnableLastRect(FALSE);
 m_client->m_use_PointerPos = FALSE;
 m_client->m_use_NewFBSize = FALSE;

 m_client->m_cursor_update_pending = FALSE;
 m_client->m_cursor_update_sent = FALSE;
 m_client->m_cursor_pos_changed = FALSE;

 // Read in the preferred encodings
int msg_se_nEncodings = 15;//Swap16IfLE(msg.se.nEncodings);

 {
  int x;
  BOOL encoding_set = FALSE;
  BOOL shapeupdates_requested = FALSE;
  BOOL pointerpos_requested = FALSE;

  {
   omni_mutex_lock l(m_client->m_regionLock);
   // By default, don't use copyrect!
   m_client->m_copyrect_use = FALSE;
  }

  // x = 0
  m_client->m_buffer->SetEncoding( 7 );
  // x = 6
  m_client->m_copyrect_use = TRUE;
  // x = 8
  m_client->m_buffer->SetCompressLevel( 6 );
  vnclog.Print(LL_INTINFO, VNCLOG("compression level requested: %d/n"), 6 );
  // x = 9
  m_client->m_buffer->EnableXCursor(TRUE);
  shapeupdates_requested = TRUE;
  vnclog.Print(LL_INTINFO, VNCLOG("X-style cursor shape updates enabled/n"));
  // x = 10
  m_client->m_buffer->EnableRichCursor(TRUE);
  shapeupdates_requested = TRUE;
  vnclog.Print(LL_INTINFO, VNCLOG("Full-color cursor shape updates enabled/n"));
  // x = 11
  pointerpos_requested = TRUE;
  // x = 12
  m_client->m_buffer->SetQualityLevel( 12 );
  vnclog.Print(LL_INTINFO, VNCLOG("image quality level requested: %d/n"), 12 );
  // x = 13
  m_client->m_buffer->EnableLastRect(TRUE);
  vnclog.Print(LL_INTINFO, VNCLOG("LastRect protocol extension enabled/n"));
  // x = 14
  m_client->m_use_NewFBSize = TRUE;
  vnclog.Print(LL_INTINFO, VNCLOG("NewFBSize protocol extension enabled/n"));

  // Enable CursorPos encoding only if cursor shape updates were
  // requested by the client.
  if (shapeupdates_requested && pointerpos_requested) {
   m_client->m_use_PointerPos = TRUE;
   m_client->SetCursorPosChanged();
   vnclog.Print(LL_INTINFO, VNCLOG("PointerPos protocol extension enabled/n"));
  }
 }
}


8. 服務器端有關數據讀取的機制, 驅動數據請求問題:
 讀取數據採用select 模式並且超時後處理: SendFromQueue

 而數據發送全都是通過: SendQueued 方式實現. 此機制唯一不好的地方是總要new 內存以存儲數據塊.

 
  因此驅動請求, 而不使用TCP, 不採用通信的方法是修改VSocket::ReadExtra API

  以下代碼爲我修改的代碼:

 VBool VSocket::ReadExact(char *buff, const VCard bufflen)
 {
 DWORD dwTickCount = GetTickCount();
 while( TRUE )
 {
  Sleep( 1 );
  if( out_queue )
  {
   if( !SendFromQueue() )
    return VFalse;
  }
  else
  {
   if( GetTickCount() - dwTickCount > 500 )
   {
    Myrecv( buff, bufflen );
    break;
   }
  }
 }
 return VTrue;


 Myrecv( buff, bufflen ); 這個API 實際上只是: 給出以下兩個消息之一.

 static rfbFramebufferUpdateRequestMsg full;
 static rfbFramebufferUpdateRequestMsg update;

 full 消息只使用於第一次.
 update 使用於以後.

 從以上代碼可以瞭解, 最小爲500 tick 一次更新請求. 這個值可以隨便設置.

 如果你想1分鐘更新一下全屏,當然可以多調用full.

 

 本文出自: 阿呆 http://blog.csdn.net/davemin
宣傳: VC 十年技術羣 30107096 歡迎高手加入,本羣只研究VC

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