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