winvnc源码阅读笔记(三)---------vncClient::SendUpdate线程
2011-03-11 11:51
465 查看
此线程用来发送更新数据,啥也不说,贴代码:
从上面的代码看到,我们关心的地方在SendRectangles函数,追踪它:
在此函数中,用for循环来发送每个矩形数据,我们追踪SendRectangle(*i)函数
上面的函数首先进行编码,然后发送数据。我们看到一个重要的函数,发送矩形队列SendExactQueue((char *)(m_encodemgr.GetClientBuffer()), bytes),我们追踪它
继续看代码,追踪SendQueued(pBuffer, nBufflen)函数
看到最终调用windows socket 的api函数send,来向客户端发送数据。
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,来向客户端发送数据。
相关文章推荐
- OBS源码阅读笔记--取出licence和update
- Netty源码阅读笔记2: 线程模型
- Caffe 源码阅读笔记 [基本模块] Caffe.cpp
- Mina源码阅读笔记(七)—Mina的拦截器FilterChain
- WINVNC源码阅读(六)
- jquery 源码阅读笔记 大杂烩
- String源码阅读笔记
- OBS源码阅读笔记---32位编译
- CodeIgniter源码阅读笔记(7)——路由类Router.php
- jdk源码阅读笔记(1.9版)非concurrent包的集合
- ejoy2d源码阅读笔记1
- zookeeper源码阅读分析笔记--客户端服务端通信机制以及session超时、过期处理
- linux-Tcp IP协议栈源码阅读笔记
- spark源码阅读笔记Dataset(二)Dataset中Actions、function、transformations
- AFNetworking 3.0 源码阅读笔记(六)
- LZ77源码阅读笔记
- Redis源码阅读笔记(1)-- 动态字符串sds
- mesa源码阅读笔记(7)_顶点变换流程解析
- springmvc源码阅读笔记 -- handleRequest