您的位置:首页 > 其它

winvnc源码阅读笔记(三)---------vncClient::SendUpdate线程

2011-03-11 11:51 465 查看
此线程用来发送更新数据,啥也不说,贴代码:

BOOL
vncClient::SendUpdate(rfb::SimpleUpdateTracker &update)
{
//如果没有需要更新的,我们推出此线程
if (update.is_empty() && !m_cursor_update_pending && !m_NewSWUpdateWaiting && !m_cursor_pos_changed) return FALSE;

//从触发器获取信息
rfb::UpdateInfo update_info;
update.get_update(update_info);
update.clear();

//老的更新屏幕大小和新的可能不同,我们首先确保新的更新大小被发送到客户端,此后客户端会请求一次全屏幕更新
if (m_NewSWUpdateWaiting)
{
m_socket->ClearQueue();
rfbFramebufferUpdateRectHeader hdr;
if (m_use_NewSWSize) {
hdr.r.x = 0;
hdr.r.y = 0;
hdr.r.w = Swap16IfLE(NewsizeW);
hdr.r.h = Swap16IfLE(NewsizeH);
hdr.encoding = Swap32IfLE(rfbEncodingNewFBSize);
rfbFramebufferUpdateMsg header;
header.nRects = Swap16IfLE(1);
SendRFBMsg(rfbFramebufferUpdate, (BYTE *)&header,sz_rfbFramebufferUpdateMsg);
m_socket->SendExact((char *)&hdr, sizeof(hdr));
m_NewSWUpdateWaiting=false;
m_ScaledScreen = m_encodemgr.m_buffer->GetViewerSize();
m_nScale = m_encodemgr.m_buffer->GetScale();
return TRUE;
}
}

//查看总共有多少区域需要被更新,包含已经编码的拷贝矩形和改变矩形
int updates = 0;
int numsubrects = 0;
updates += update_info.copied.size();
if (m_encodemgr.IsCacheEnabled())
{
if (update_info.cached.size() > 5)
{
updates++;
}
else
{
updates += update_info.cached.size();
//vnclog.Print(LL_INTERR, "cached %d/n", updates);
}
}

rfb::RectVector::const_iterator i;
if (updates!= 0xFFFF)
{
for ( i=update_info.changed.begin(); i != update_info.changed.end(); i++)
{
// Tight specific (lastrect)
numsubrects = m_encodemgr.GetNumCodedRects(*i);

// Skip rest rectangles if an encoder will use LastRect extension.
if (numsubrects == 0) {
updates = 0xFFFF;
break;
}
updates += numsubrects;
//vnclog.Print(LL_INTERR, "changed %d/n", updates);
}
}
//如果客户端不支持缓冲,我们就需要发送缓冲像正常的更新一样
if (!m_encodemgr.IsCacheEnabled() && updates!= 0xFFFF)
{
for (i=update_info.cached.begin(); i != update_info.cached.end(); i++)
{
// Tight specific (lastrect)
numsubrects = m_encodemgr.GetNumCodedRects(*i);

// Skip rest rectangles if an encoder will use LastRect extension.
if (numsubrects == 0) {
updates = 0xFFFF;
break;
}
updates += numsubrects;
//vnclog.Print(LL_INTERR, "cached2 %d/n", updates);
}
}

//
if (!m_encodemgr.IsXCursorSupported()) m_cursor_update_pending=false;
// Tight specific (lastrect)
if (updates != 0xFFFF)
{
// Tight - CURSOR HANDLING
if (m_cursor_update_pending)
{
updates++;
}
// nyama/marscha - PointerPos
if (m_cursor_pos_changed)
updates++;
if (updates == 0) return FALSE;
}

//	Sendtimer.start();

//debug by qz,注销了下面的一行
omni_mutex_lock l(GetUpdateLock());

//发送矩形的头
rfbFramebufferUpdateMsg header;
header.nRects = Swap16IfLE(updates);
if (!SendRFBMsg(rfbFramebufferUpdate, (BYTE *) &header, sz_rfbFramebufferUpdateMsg))
return TRUE;

//光标处理
if (m_cursor_update_pending) {
if (!SendCursorShapeUpdate())
return FALSE;
}
// nyama/marscha - PointerPos
if (m_cursor_pos_changed)
if (!SendCursorPosUpdate())
return FALSE;

//发送拷贝矩形
if (!update_info.copied.empty()) {
rfb::Point to_src_delta = update_info.copy_delta.negate();
for (i=update_info.copied.begin(); i!=update_info.copied.end(); i++) {
rfb::Point src = (*i).tl.translate(to_src_delta);
if (!SendCopyRect(*i, src))
return FALSE;
}
}

if (m_encodemgr.IsCacheEnabled())
{
if (update_info.cached.size() > 5)
{
if (!SendCacheZip(update_info.cached))
return FALSE;
}
else
{
if (!SendCacheRectangles(update_info.cached))
return FALSE;
}
}
else
{
if (!SendRectangles(update_info.cached))
return FALSE;
}

if (!SendRectangles(update_info.changed))	//发送矩形数据,重要部分,程序在这里有时间延迟100ms左右
return FALSE;

// Tight specific - Send LastRect marker if needed.
if (updates == 0xFFFF)
{
m_encodemgr.LastRect(m_socket);
if (!SendLastRect())
return FALSE;
}

m_socket->ClearQueue();
// vnclog.Print(LL_INTINFO, VNCLOG("Update cycle/n"));

return TRUE;
}


从上面的代码看到,我们关心的地方在SendRectangles函数,追踪它:

BOOL
vncClient::SendRectangles(const rfb::RectVector &rects)		//debug by qz,批量发送矩形数据
{
//	rfb::Rect rect;
rfb::RectVector::const_iterator i;
int waitetime;
static DWORD	newtick;
static DWORD	oldtick;

// Work through the list of rectangles, sending each one
for (i=rects.begin();i!=rects.end();i++) {		//debug by qz,在此处耗费时间比较长
if (!SendRectangle(*i))			//debug by qz,单个发送矩形数据,重要
return FALSE;
}

return TRUE;
}


在此函数中,用for循环来发送每个矩形数据,我们追踪SendRectangle(*i)函数

//告诉编码器发送一个矩形
BOOL
vncClient::SendRectangle(const rfb::Rect &rect)			//debug by qz,单个发送矩形数据
{
// Get the buffer to encode the rectangle
// Modif sf@2002 - Scaling
rfb::Rect ScaledRect;
ScaledRect.tl.y = rect.tl.y / m_nScale;
ScaledRect.br.y = rect.br.y / m_nScale;
ScaledRect.tl.x = rect.tl.x / m_nScale;
ScaledRect.br.x = rect.br.x / m_nScale;

//	Totalsend+=(ScaledRect.br.x-ScaledRect.tl.x)*(ScaledRect.br.y-ScaledRect.tl.y);

// sf@2002 - DSMPlugin
// Some encoders (Hextile, ZRLE, Raw..) store all the data to send into
// m_clientbuffer and return the total size from EncodeRect()
// Some Encoders (Tight, Zlib, ZlibHex..) send data on the fly and return
// a partial size from EncodeRect().
// On the viewer side, the data is read piece by piece or in one shot
// still depending on the encoding...
// It is not compatible with DSM: we need to read/write data blocks of same
// size on both sides in one shot
// We create a common method to send the data
if (m_socket->IsUsePluginEnabled() && m_server->GetDSMPluginPointer()->IsEnabled())
{
// Tell the SendExact() calls to write into the local NetRectBuffer memory buffer
m_socket->SetWriteToNetRectBuffer(true);
m_socket->SetNetRectBufOffset(0);
// sf@2003 - we can't easely predict how many rects are going to be sent
// (for Tight encoding for instance)
// Then we take the worse case (screen buffer size * 1.5) for the net rect buffer size.
// m_socket->CheckNetRectBufferSize((int)(m_encodemgr.GetClientBuffSize() * 2));
m_socket->CheckNetRectBufferSize((int)(m_encodemgr.m_buffer->m_desktop->ScreenBuffSize() * 3 / 2));
UINT bytes = m_encodemgr.EncodeRect(ScaledRect, m_socket);
m_socket->SetWriteToNetRectBuffer(false);

BYTE* pDataBuffer = NULL;
UINT TheSize = 0;

// If SendExact() was called from inside the encoder
if (m_socket->GetNetRectBufOffset() > 0)
{
TheSize = m_socket->GetNetRectBufOffset();
m_socket->SetNetRectBufOffset(0);
pDataBuffer = m_socket->GetNetRectBuf();
// Add the rest to the data buffer if it exists
if (bytes > 0)
{
memcpy(pDataBuffer + TheSize, m_encodemgr.GetClientBuffer(), bytes);
}
}
else // If all data was stored in m_clientbuffer
{
TheSize = bytes;
bytes = 0;
pDataBuffer = m_encodemgr.GetClientBuffer();
}

// Send the header
m_socket->SendExactQueue((char *)pDataBuffer, sz_rfbFramebufferUpdateRectHeader);		//发送矩形队列头

// Send the size of the following rects data buffer
CARD32 Size = (CARD32)(TheSize + bytes - sz_rfbFramebufferUpdateRectHeader);
Size = Swap32IfLE(Size);
m_socket->SendExactQueue((char*)&Size, sizeof(CARD32));			//发送矩形数据大小
// Send the data buffer
m_socket->SendExactQueue(((char *)pDataBuffer + sz_rfbFramebufferUpdateRectHeader),			//发送矩形数据,重要
TheSize + bytes - sz_rfbFramebufferUpdateRectHeader
);

}
else // Normal case - No DSM - Symetry is not important
{
UINT bytes = m_encodemgr.EncodeRect(ScaledRect, m_socket);		//此处耗费时间较长.
t   =   (unsigned   long)GetCycleCount();

// if (bytes == 0) return false; // From realvnc337. No! Causes viewer disconnections/

// Send the encoded data,发送编码数据
return m_socket->SendExactQueue((char *)(m_encodemgr.GetClientBuffer()), bytes);		//发送矩形数据,重要
}

return true;
}


上面的函数首先进行编码,然后发送数据。我们看到一个重要的函数,发送矩形队列SendExactQueue((char *)(m_encodemgr.GetClientBuffer()), bytes),我们追踪它

VBool
VSocket::SendExactQueue(const char *buff, const VCard bufflen)		//发送单个矩形数据
{
//	vnclog.Print(LL_SOCKERR, VNCLOG("SendExactQueue %i %i/n") ,bufflen,queuebuffersize);
//	vnclog.Print(LL_SOCKERR, VNCLOG("socket size %i/n") ,bufflen);
// sf@2002 - DSMPlugin
VCard nBufflen = bufflen;
char* pBuffer = NULL;
if (m_fUsePlugin && m_pDSMPlugin->IsEnabled())
{
// omni_mutex_lock l(m_TransMutex);

// If required to store data into memory
if (m_fWriteToNetRectBuf)
{
memcpy((char*)(m_pNetRectBuf + m_nNetRectBufOffset), buff, bufflen);
m_nNetRectBufOffset += bufflen;
return VTrue;
}
else // Tell the plugin to transform data
{
int nTransDataLen = 0;
//adzm 2009-06-20
pBuffer = (char*)(TransformBuffer((BYTE*)buff, bufflen, &nTransDataLen));
if (pBuffer == NULL || (bufflen > 0 && nTransDataLen == 0))
{
// throw WarningException("SendExact: DSMPlugin-TransformBuffer Error.");
}
nBufflen = nTransDataLen;
}

}
else
pBuffer = (char*) buff;

VInt result=SendQueued(pBuffer, nBufflen);		//发送矩形数据,我们关注的地方在这里

return result == (VInt)nBufflen;
}


继续看代码,追踪SendQueued(pBuffer, nBufflen)函数

VInt
VSocket::SendQueued(const char *buff, const VCard bufflen)		//debug by qz,发送矩形数据
{
unsigned int newsize=queuebuffersize+bufflen;
char *buff2;
buff2=(char*)buff;
unsigned int bufflen2=bufflen;

omni_mutex_lock l();
//SYSTEMTIME st;

if (newsize >G_SENDBUFFER)		//debug by qz,G_SENDBUFFER为发送缓冲区
{
memcpy(queuebuffer+queuebuffersize,buff2,G_SENDBUFFER-queuebuffersize);
send(sock,queuebuffer,G_SENDBUFFER,0);
//	vnclog.Print(LL_SOCKERR, VNCLOG("SEND Q  %i/n") ,G_SENDBUFFER);
buff2+=(G_SENDBUFFER-queuebuffersize);
bufflen2-=(G_SENDBUFFER-queuebuffersize);
queuebuffersize=0;
while (bufflen2 > G_SENDBUFFER)
{
if (!send(sock,buff2,G_SENDBUFFER,0)) return false;		//核心函数,调用windows socket api函数。
//	vnclog.Print(LL_SOCKERR, VNCLOG("SEND Q  %i/n") ,G_SENDBUFFER);
buff2+=G_SENDBUFFER;
bufflen2-=G_SENDBUFFER;
}
}

memcpy(queuebuffer+queuebuffersize,buff2,bufflen2);
queuebuffersize+=bufflen2;

return bufflen;
}


看到最终调用windows socket 的api函数send,来向客户端发送数据。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: