改进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

你可能感兴趣的:(System,Socket)