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