UC故事2011/12/04 总结与规划 (续)


1. 要点总结

* 2011/11/22: Client核心类图及关于XXXSink的理解

* Chat窗口中的信息如何传递到服务器

UI线程:UI上的button消息响应函数

UI线程:得到网络线程的Reactor指针pReactor

UI线程:pReactor->PostEvent(SendDataEvent),投递event,并呼叫NotifyHandler通知reactor处理event

                (Win32下本质上是发Windows Message WM_WIN32_SOCKET_NOTIFY)

网络线程:接收到WM_WIN32_SOCKET_NOTIFY消息

网络线程:调用pReactor->HandleProcessEvent

网络线程:从event queue里pop出pending events,并对每一个pEvent,调用pEvent->OnEventFire

网络线程:调用Connection之类东东,将数据发给Server


2. 问题汇总

关于component/container等相关的几个问题(回顾)

Q:虚拟打印:目前文档共享使用了虚拟打印技术,但若非Windows客户端又当如何?

Q:似乎ThreadManager中对Main thread及network thread的启动与初始化放在了diagnose module,WHY ?

Q:关于只有一份ConfMain.exe运行的控制是在LaunchConf中完成,为什么要做这种控制?

Q:Client主界面上的东东如何显示出来的?比如ChatMainDlg如何嵌入到主界面上的?

Q:rtconfsess.dll的load

在load rtconfclient.dll的时候,load了

Loaded symbols for 'D:\study\uc-study-workspace\box-infoserver-trunk-20111116\bin\dlls\Debug\rtconfclient.dll'
Loaded 'C:\WINDOWS\system32\comdlg32.dll', no matching symbolic information found.
Loaded 'C:\WINDOWS\system32\winmm.dll', no matching symbolic information found.
Loaded symbols for 'D:\study\uc-study-workspace\box-infoserver-trunk-20111116\bin\dlls\Debug\rtconfsess.dll'
Loaded symbols for 'D:\study\uc-study-workspace\box-infoserver-trunk-20111116\bin\dlls\Debug\sdclient.dll'

为什么rtconfsess.dll在rtconfclient.dll后load进来?机制在哪里?


Q:IConnection, IConnProvider, IConnProviderSink之间的关系?

Q:CConfPort的职责是什么?

    CRtAutoPtr<CConfConnection>    m_reliable_connection;
    CRtAutoPtr<CConfConnection>    m_assistant_connection;                        // 区别了reliable与assistant connection,有何用?选择tcp/udp?


Q:在Client启动及运行的所有时间里,与Server端的交互都是通过network thread而非main(UI)thread?

Q:从语义上说,IEventQueue.PostEvent()完成了Event的投递,并且,也触发了对Event的异步处理?



3. 下步计划


4. 杂问杂记

* CRtReactorWin32Message与CRtReactorWoin32Asyncselect

OnHandleRegister的调用试验:

XXXMessage没有被调用过,XXXAsyncselect被调用了N次(为什么?),但最终client crash了,没有能启动(此时已经看到界面了,同时出现了N个线程在后台,WHY?)。

注:N个线程,很多是由其它模块启动的(如与audio有关的东东),非ThreadManager启动。ThreadManager启动的线程似乎只有一个,即网络线程。


* thread

以下thread在干嘛?

NTDLL! 7c92e514()
KERNEL32! 7c802542()
CRtConditionVariableThread::Wait(CRtTimeValue * 0x00000000) line 190 + 26 bytes
CRtEventQueueUsingConditionVariable::PopOrWaitPendingEvents(std::list<IRtEvent *,std::allocator<IRtEvent *> > & {...}, CRtTimeValue * 0x00000000, unsigned long 4294967295) line 159 + 15 bytes
CRtThreadTaskWithEventQueueOnly::OnThreadRun() line 32 + 22 bytes
CRtThread::ThreadProc(void * 0x0208c8b8) line 151 + 13 bytes
_threadstartex(void * 0x0208c9d8) line 227 + 13 bytes
KERNEL32! 7c80b729()

* CRtReactorBase::ProcessHandleEvent

(其它线程调用本线程的EventQueue.PostEvent投递Event

其它线程调用本线程的NotifyHandler通知事处理(PostMessage(hWnd, WM_WIN32_SOCKET_NOTIFY...)

本地线程EventQueue::RunEvent(对于Win32就是Windows Messaging循环),收到WM_WIN32_SOCKET_NOTIFY消息从而进入处理循环

调用 CRtReactorBase::ProcessHandleEvent)


从EventQueue里将pending events全部pop up

对所有events进行处理,调用event->OnEventFire()

NotifyHandler: NotifyHandler(NULL, IRtEventHandler::EVENTQUEUE_MASK);                 // WHY THIS ???有点在NotifyHandler这里搞成多次调用,死循环了?


* 跟踪WinMain,找出client与server真正开始通讯的地方

使用WireShark来跟踪

Q:如何设置Capture Filter及Display Filter?


* 当前DSW中有哪些DLL能被Build

查程序启动的时候,有哪些symbol未被load,即可知。


* 关于主线程(UI)消息循环

STRACK TRACE

CConfManage::OnConferenceJoinConfirm(int 40206, const CInfoSID & {...}, const CInfoSID & {...}, const CInfoSID & {...}, unsigned long 0) line 325
CConference::OnPingResult(int 40206, unsigned long 0, unsigned short 0, const TransportAddress * 0x00000000, const TransportAddress & {...}) line 861 + 68 bytes
CConfPing::OnReceiveData(CGcPduBase * 0x0208ba30) line 92 + 90 bytes
CPingBase::OnReceiveData(CRtMessageBlock & {...}, IConnection * 0x0208b864) line 187 + 27 bytes
CRtIMConnection::OnReceive(CRtMessageBlock & {...}, IRtTransport * 0x0208b718, CRtTransportParameter * 0x00000000) line 890 + 50 bytes
CRtEventOnReceive::OnEventFire() line 375 + 50 bytes
CRtEventQueueBase::ProcessOneEvent(IRtEvent * 0x02087d58) line 229 + 12 bytes
CRtEventQueueBase::ProcessEvents(const std::list<IRtEvent *,std::allocator<IRtEvent *> > & {...}) line 217
CRtReactorBase::ProcessHandleEvent(void * 0xffffffff, long 256, int 0, int 1, int 0) line 324 + 18 bytes
CRtReactorWin32Message::Win32SocketWndProc(HWND__ * 0x000b0dce, unsigned int 1058, unsigned int 4294967295, long 256) line 115
USER32! 77d18734()
USER32! 77d18816()
USER32! 77d189cd()
USER32! 77d196c7()
WTL::CMessageLoop::Run() line 468 + 15 bytes
Run(char * 0x00151f28, int 1) line 207 + 11 bytes
LaunchConf(HINSTANCE__ * 0x00400000, char * 0x00151f28, int 1) line 318 + 13 bytes
WinMain(HINSTANCE__ * 0x00400000, HINSTANCE__ * 0x00000000, char * 0x00151f28, int 1) line 85 + 20 bytes
WinMainCRTStartup() line 330 + 54 bytes
KERNEL32! 7c817077()

注:说明在系统启动后,主消息循环的处理中居然有Win32SocketWndProc,如何发生的?

Q:是否在某个时间,把当前hWnd通过某种方式与Win32SocketWndProc相对应的Windows Class注册了?

Q:或者是因为在某个线程中,其消息对列实际上可以给多个窗口的WindowsMessagingHandler使用? I think so.

所以,主线程(UI)其实至少有两人Windows Handler,一个是WTL用于处理UI的,一个是自已定义的Win32SocketWndProc,用于处理当前线程的Reactor。也就是说,当网络线程从网络获得输入的时候,它要通过PostEvent/NotifyHandler来通知主线程的Win32SocketWndProc,以响应来自Server端的信息。


* client/server之间是同步还是异步

Client在向Server发送了Ping请求(或Leave Conference)后,是否要等到Server应答后再进行以下动作?

从代码跟踪看,似乎并非如此?


* 主线程与网络线程通信方式细节?

发出数据到server?

从Server接收数据?

都是通过EventQueue完成的?

主线程会直接向Server收发数据吗?( I think not)


# SendData的本质:向网络线程Post一个SendEvent

STACK TRACE:

CRtEventQueueBase::PostEvent(IRtEvent * 0x0211c110, IRtEventQueue::EPriority EPRIORITY_NORMAL) line 132
CRtEventQueueUsingMutex::PostEventWithOldSize(IRtEvent * 0x0211c110, IRtEventQueue::EPriority EPRIORITY_NORMAL, unsigned long * 0x0012f900) line 267 + 16 bytes
CRtReactorBase::PostEvent(IRtEvent * 0x0211c110, IRtEventQueue::EPriority EPRIORITY_NORMAL) line 517 + 23 bytes
CRtTransportThreadProxy::SendData(CRtMessageBlock & {...}, int 0, int 0, IRtTransport::DataPriority DP_MEDIUM, int 0) line 128 + 59 bytes


CODE:

RtResult CRtTransportThreadProxy::SendData(...) {

   ......

    return m_networkThread->GetEventQueue()->PostEvent(sendDataEvent);

   ......

}



* IRtEvent:理解系统功能的关键!

找出所有CEventXXX?


* RtResult CRtReactorBase::ProcessHandleEvent()

从EventQueue里取出pending events

Handle Each Event: pEvent->OnFireEvent()

Notify Handler ???       // 也就是在当前pending events都处理后,notify handler。 For what ???


注1:这个方法需要被Reactor的客户代码所调用,WHY NOT DEFINED IN IRtReactor?

注2:这个方法逻辑非常重要,需要仔细再研读下。


* 单线程与多线程

Client实际上是多线程的,但提供给程序员的接口表现成单线程的。

Q:哪些地方做了这项工作?


* CRtTransportTcp

这是实际发生Input/output的地方,使用SOCKET。

    CRtTransportTcp(IRtReactor *pReactor);

Q:有reactor在constructor中,但哪里在使用?


* CConfConnetion

    CRtAutoPtr<CConference>        m_conference;
    CRtAutoPtr<IConnection>        m_work_connection;
    CPackageQueue                m_queues[4];


注:最重要的是,这不是一个原始的Connection,有conference的语义,表现在有一个package queue,每一个优先级有一个,发送的时候,高优先级先发,再发低优先级,故在此能对优先级进行控制,代码如下:

void CConfConnection::SendData_i()
{
    if (!m_canSend)
    { return; }

    for (int i = 0; i < 4; i++)
    {
    ...
    while (currentPackage = m_queues[i].GetFirst(TRUE))
    {

          ...

          RtResult ret = SendBufData(*currentPackage);

          ...
    }
}


* UI thread 如何接收Network thread(也就是server)的信息?


CRtEventOnReceive::OnEventFire() line 375 + 50 bytes
CRtEventQueueBase::ProcessOneEvent(IRtEvent * 0x020b0780) line 229 + 12 bytes
CRtEventQueueBase::ProcessEvents(const std::list<IRtEvent *,std::allocator<IRtEvent *> > & {...}) line 217
CRtReactorBase::ProcessHandleEvent(void * 0xffffffff, long 256, int 0, int 1, int 0) line 324 + 18 bytes

                                       ^ 这一步,从event queue里pop up所有pending events并进行处理
CRtReactorWin32Message::Win32SocketWndProc(HWND__ * 0x001007da, unsigned int 1058, unsigned int 4294967295, long 256) line 115

                                                           ^ 在这一步,肯定是因为network thread向UI Thread发送了Event,并Notify Handler 2011/12/04

                                                          ^ 从WM_WIN32_SOCKET_SELECT的代码应该能跟踪到
USER32! 77d18734()
USER32! 77d18816()
USER32! 77d189cd()
USER32! 77d196c7()
WTL::CMessageLoop::Run() line 468 + 15 bytes
Run(char * 0x00151f28, int 1) line 207 + 11 bytes
LaunchConf(HINSTANCE__ * 0x00400000, char * 0x00151f28, int 1) line 318 + 13 bytes
WinMain(HINSTANCE__ * 0x00400000, HINSTANCE__ * 0x00000000, char * 0x00151f28, int 1) line 85 + 20 bytes
WinMainCRTStartup() line 330 + 54 bytes
KERNEL32! 7c817077()


* 接上步,从WM_WIN32_SOCKET_SELECT设断点,跟踪

STACK TRACE

CRtSocketBase::SendV(const iovec * 0x00f28ef0, unsigned long 1) line 306
CRtTransportTcp::SendData(CRtMessageBlock & {...}, int 1, int 0, IRtTransport::DataPriority DP_MEDIUM, int 1) line 152 + 20 bytes
CRtConnRlbTcpClient::SendConnReq() line 664 + 48 bytes
CRtConnRlbTcpClient::OnConnectIndication(int 0, IRtTransport * 0x0208b5dc, IRtAcceptorConnectorId * 0x0208b250) line 467
CRtConnectorWrapper::OnConnectIndication(int 0, IRtTransport * 0x0208b5dc, IRtConnectorInternal * 0x0208b2bc) line 150 + 30 bytes
CRtConnectorTcpT<CRtConnectorWrapper,CRtTransportTcp,CRtSocketStream>::OnOutput(void * 0x00000668) line 141
CRtReactorBase::ProcessHandleEvent(void * 0x00000668, long 2, int 0, int 0, int 0) line 387 + 23 bytes
CRtReactorWin32Message::Win32SocketWndProc(HWND__ * 0x00020f80, unsigned int 1057, unsigned int 1640, long 16) line 95
USER32! 77d18734()
USER32! 77d18816()
USER32! 77d189cd()
USER32! 77d196c7()
CRtReactorWin32Message::RunEventLoop() line 262 + 15 bytes
CRtThreadReactor::OnThreadRun() line 67 + 19 bytes
CRtThread::ThreadProc(void * 0x02087ef0) line 151 + 13 bytes
_threadstartex(void * 0x02087fa0) line 227 + 13 bytes
KERNEL32! 7c80b729()

Q:这里似乎network thread没有向UI thread发东东,可能因为这是一个connect动作?connect应该是从UI Thread发起的(但如何放进Asyncselect的呢?)试下read动作。


* 接上步,尝试input事件流

STACK TRACE:

CRtAcceptorConnectorSinkThreadProxyT<CRtConnectorThreadProxy>::OnConnectIndication(int 0, IRtTransport * 0x0208b530, IRtAcceptorConnectorId * 0x0208b420) line 146

                                                                           ^ 在这里,终于看到对UI线程调用PostEvent,代码见后。

CRtConnRlbTcpClient::OnRecvConnResp() line 613 + 66 bytes
CRtConnRlbTcp::OnReceive(CRtMessageBlock & {...}, IRtTransport * 0x0208b724, CRtTransportParameter * 0x00000000) line 254 + 17 bytes
CRtTransportTcp::OnInput(void * 0x00000664) line 70 + 52 bytes
CRtReactorBase::ProcessHandleEvent(void * 0x00000664, long 4, int 0, int 0, int 0) line 381 + 23 bytes
CRtReactorWin32Message::Win32SocketWndProc(HWND__ * 0x000c082c, unsigned int 1057, unsigned int 1636, long 1) line 95
USER32! 77d18734()
USER32! 77d18816()
USER32! 77d189cd()
USER32! 77d196c7()
CRtReactorWin32Message::RunEventLoop() line 262 + 15 bytes
CRtThreadReactor::OnThreadRun() line 67 + 19 bytes
CRtThread::ThreadProc(void * 0x02087ef0) line 151 + 13 bytes
_threadstartex(void * 0x02087fa0) line 227 + 13 bytes
KERNEL32! 7c80b729()


CODE:

template <class ThreadProxyType>
class CRtAcceptorConnectorSinkThreadProxyT
    : public IRtAcceptorConnectorSink


CRtAcceptorConnectorSinkThreadProxyT::OnConnectIndication() {

       ....

        CEventOnConnectIndication<ThreadProxyType> *pEvent =
            new CEventOnConnectIndication<ThreadProxyType>(
                m_pThreadProxy,
                aReason,
                pTransportThreadProxy,
                m_pThreadProxy);
        m_pThreadProxy->m_pThreadUser->GetEventQueue()->PostEvent(pEvent);

                                                       ^ main(UI) thread !!!

       ....

}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值