libjingle学习笔记Thread MessageQueue SocketServer.docx

上传人:b****6 文档编号:8598532 上传时间:2023-02-01 格式:DOCX 页数:13 大小:142.08KB
下载 相关 举报
libjingle学习笔记Thread MessageQueue SocketServer.docx_第1页
第1页 / 共13页
libjingle学习笔记Thread MessageQueue SocketServer.docx_第2页
第2页 / 共13页
libjingle学习笔记Thread MessageQueue SocketServer.docx_第3页
第3页 / 共13页
libjingle学习笔记Thread MessageQueue SocketServer.docx_第4页
第4页 / 共13页
libjingle学习笔记Thread MessageQueue SocketServer.docx_第5页
第5页 / 共13页
点击查看更多>>
下载资源
资源描述

libjingle学习笔记Thread MessageQueue SocketServer.docx

《libjingle学习笔记Thread MessageQueue SocketServer.docx》由会员分享,可在线阅读,更多相关《libjingle学习笔记Thread MessageQueue SocketServer.docx(13页珍藏版)》请在冰豆网上搜索。

libjingle学习笔记Thread MessageQueue SocketServer.docx

libjingle学习笔记ThreadMessageQueueSocketServer

libjingle中的重要概念

关于libjingle你应当理解下面的重要概念:

Signals

ThreadsandMessages

NamingConventions

SSLSupport

Connections

Transports,Channels,andConnections

Candidates

DataPackets

一、Signals

libjingleusesthesigslotlibrarytofacilitatecommunicationbetweenobjects.sigslotisagenericframeworkthatenablesyoutoconnectacallingmembertoareceivingfunctioninanyclass(includingthesameclass)verysimply.Thewayitworksisthis:

libjingle使用sigslotlibrary实现对象间通信,sigslot是一个通用的的框架,使你能够很简单的连接任意类(包括同一个类)的一个调用成员与一个收个函数。

它的工作方式如下:

发送类声明一个成员变量,叫做signalN<>,使用一个特殊的模版化的语法。

这个信号定义了监听函数参数。

监听类实现一个函数具有相同数量、类型和参数序列的信号。

这有时也被称为接收机或信槽。

(注意:

这个甚至可以是作为声明信号的那个相同的类。

)这个函数不能返回一个值(例如。

返回void)。

接收者必须继承sigslot:

:

has_slot<>。

监听类通过调用信号的连接方法连接到信号,传递一个指向对象的实例和该监听类实现函数的地址。

发送方调用它的信号成员,就好像它是一个函数,并传递声明时的适当参数类型。

它可以通过值传递参数或引用。

Youcanconnectasmanysignalsasyouliketoacommonslot.libjinglesometimesassignsmultiplesignalstoasingleslotinordertoconsolidateitsmessagehandling.Conversely,severalobjectsdeclareasignalobjectinordertobroadcastcommonlyneededmessagesfromasinglepoint(forexample,alertssentwhenaconnectionstatechanges).sigslottakescareofdisconnectingcallbacksanddereferencingwhenobjectsaredestroyed.

你可以连接尽可能多的信号使用一个通用的槽。

libjingle有时分配多个信号到一个槽为了巩固其消息处理。

相反地,几个对象声明一个信号对象以广播通常需要的消息从一个信源(例如,当一个连接状态改变时发送的警报状态)。

当对象被销毁时sigslot负责切断回调函数和解除关联。

下面的代码演示了使用sigslot:

//Classthatsendsthenotification.

classSender{

//信号声明.

//名字中的2标志参数数量,参数类型

//被声明为模板参数列表

sigslot:

:

signal2

:

time_ttime>SignalDanger;

//任何对Panic()的调用将会发送SignalDanger信号

voidPanic(){

SignalDanger("Help!

",std:

:

time(0));

}

//监听类必须继承自sigslot

classReceiver:

publicsigslot:

:

has_slots<>{

//接收注册以得到SignalDanger信号。

//当SignalDanger信号发送,它被OnDanger()捕获。

//第二个参数给地址的侦听器函数类定义。

//第一个参数指出这个类的实例来接收通知。

Receiver(Sendersender){

sender->SignalDanger.connect(this,&Receiver.OnDanger);

}

//任何对Panic()的调用,将使Receiver:

:

OnDanger获得消息.

//注意,数量和类型的参数匹配

voidOnDanger(stringmessage,std:

:

time_ttime){

if(message=="Help!

")

{

//Callthepolice

...

}

}

...

}

代码中的许多类发送信号以通知重要事件的监听器,例如,例如当你发送或收到一个连接请求时Call:

:

SignalSessionState发送通知。

你的应用程序必须连接这些信号与适当的处理过程。

在libjingle代码中的一般惯例是在信号的名称前加Signal,例如SignalStateChange,SignalSessionState,SignalSessionCreate,监听方法如。

SignalStateChange,SignalSessionState,SignalSessionCreate。

用来连接到信号的监听器方法通常在前面加上On。

例如:

OnPortDestroyed(),OnOutgoingMessage(),OnSendPacket()。

看到sigslot文档<>为更多的细节。

二、Threads

为了提高应用程序的性能libjingle支持多线程。

libjingle组件使用一个或两个全局可用的线程:

一、signalingthread

signalingthread是一个用于创建所有基本组件的线程,例如SessionManager和控制以及XMPP消息传递组件。

二、workerthread

workerthread(在代码中有时称为channelthread)被对等组件对象(PeertoPeercomponentobjects)来处理更多的资源密集型处理,比如数据流。

把这些放在一个单独的线程中可以防止数据流阻塞或被XMPP或用户接口组件阻塞。

使用工作线程的类包括ChannelManager,SocketMonitor,P2PTransportChannel,以及Port对象。

为了启用第二个线程,您必须创建一个新的线程对象并传递到SessionManager构造函数。

(如果没有线程被传递,那个创建SessionManager的线程将被用作工作线程)。

CallClient:

:

InitPhone演示了如何创建一个工作线程的底层组件。

此外,libjingle现在提供了一个叫做SignalThread的基类。

扩展这个类能使一个类对象存在于自己的线程中,可以被实例化,开始,独自完成和在完成后删除自己。

关于更多信息看signalthread.h/.cc。

注意:

尽管libjingle支持多个线程,只有某些方法通过验证调用线程支持线程安全,并且很少有方法做任何锁。

下面的代码片段演示了一个方法怎样验证它正在哪个线程中调用:

//检查我们被调用的通道(如.,worker)线程。

ASSERT(talk_base:

:

Thread:

:

Current()==channel_thread_);

channel_thread_->Clear(this);

ibjingle使用talk_base:

:

Threadobject(oraderivedobject)封装了所有线程,信号线程,工作线程,和任何其他线程,。

所有线程对象由ThreadManager来管理,ThreadManager针对请求检索这些线程。

SessionManager调用ThreadManager:

:

CurrentThread以提供给它一个signalingthread(和一个工作线程,如果没有被提供)当它被实例化;XmppPump使用当前线程用于其信号线程。

因此,在创建一个SessionManager对象之前或者期望XmppPump开始工作之前您必须创建一个线程对象(或派生对象)信号线程并放入ThreadManager的线程池,(参见注册服务器例如代码。

)有两种方法可以创建一个线程:

三、AutoThread   (自动线程)

ThiswrapstheexistingoperatingsystemthreadwithalibjingleThreadobjectandmakesitthecurrentthreadintheThreadManagerobject'sthreadpool(thatis,willreturnthethreadifThread:

:

CurrentThreadiscalled).

用一个libjingle线程对象封装现有的操作系统线程,并使它成为在ThreadManager线程池中的当前线程(即,如果Thread:

:

CurrentThrad被调用将返回这个线程)。

四、Thread   

Thiscreatesandwrapsanewthreadtouse,typicallyforaworkerthread.Inordertousethisthread,youhavetocreateanewThreadobject,callThreadManager:

:

AddorThreadManager:

:

SetCurrenttoaddittothepool,andcallRuntostartitinablockingloop,orStarttostartthethreadlistening.

这将创建和封装一个新的线程,用于,通常为一个工作线程。

为了使用这个线程,您必须创建一个新的线程对象,调用ThreadManager:

:

Add或ThreadManager:

:

SetCurrent将它添加到池中,并调用Run以启动它在一个阻塞循环中,或者Start以启动线程监听。

Threadsprovideaconduitformessagesbetween(orwithin)objects.Forinstance,SocketManagersendsamessagetoitselfonanotherthreadtodestroyasocket,ortoSessionManagerwhenconnectioncandidateshavebeengenerated.TheThreadobjectinheritsMessageQueue,andtogethertheyexposeSend,Post,andothermethodsforsendingmessagessynchronouslyandasynchronously.AnobjectthatwillreceivemessagessentusingMessageQueuemustinheritandimplementMessageHandler.MessageHandlerdefinestheOnMessagemethod,whichiscalledwiththeMessageQueuemessages.

线程在对象之间(或对象内部)为消息提供了一个渠道。

例如,SocketManager给它自己发送一个消息在另一个线程中摧毁一个套接字,或者当连接的候选人(candidates)被生成时给SessionManager发送消息。

线程对象继承MessageQueue,和他们一起暴露Send、Post其他方法用于同步和异步发送消息。

一个要收到MessageQueue发送的消息的对象必须继承和实现MessageHandler。

MessageHandler定义了OnMessage方法,在收到MessageQueue发送的消息时被调用。

Youcansendmessagestoanyobjectthatinheritstalk_base:

:

MessageHandleroveranythread.However,ifsendingamessagetoperformaresource-intensivethread,youshouldsendthemessageovertheworkerthread.YoucangetahandletotheworkerthreadbycallingSessionManager:

:

worker_thread().YoucangetahandletothesignalingthreadbycallingSessionManager:

:

signaling_thread().

Anobjecthasseveralwaystoaccessaspecificthread:

itcanrequestandstoreathreadpointerasaninputparameter;itcanassumethatthecurrentthreadwhenitiscreated(accessedbyThreadManager:

:

CurrentThreadinitsconstructor)isaparticularthreadandcacheamemberpointertoit;itcancallSessionManger:

:

signal_thread()orSessionManager:

:

worker_thread()toretrievethreads.Allthreetechniquesareusedinlibjingle.

你能够给任何继承自talk_base:

:

MessageHandler的对象跨越任何线程发送消息,然而,如果发送一个消息给一个执行资源密集型的线程,你应当发送消息到工作线程。

你能够通过调用SessionManager:

:

worker_thread()以得到一个工作线程的句柄。

你能够通过调用SessionManager:

:

signaling_thread()获得一个信号线程的句柄。

一个对象有几种方式去访问一个具体的线程:

:

它可以请求并存储一个线程指针作为输入参数,它可以假定当前线程创建时(在其构造函数中访问ThreadManager:

:

CurrentThread)是一个特定的线程并使用成员指针指向这个线程,它可以调用SessionManger:

:

signal_thread()或SessionManager:

:

worker_thread()来检索线程。

所有三个技术都可以在用于libjingle。

Becauseanobjectcanbecalledonanythread,anobjectmayneedtoverifywhichthreadamethodisbeingcalledfrom.Todothis,callThread:

:

Current(whichretrievesthecurrentthread)andcomparethatvalueagainstaknownthread--thiscanbeoneofthethreadsexposedbySessionManager,ortheobjectcanstoreapointertoitsinitialthreadintheconstructor.Hereisamoreextendedexampleofcallingamethodinthesameobjectonanotherthread.

因为一个对象能够在任何线程中被调用,一个对象需要验证被哪一个线程的哪个方法中调用,要做到这一点,调用Thread:

:

Current(检索当前线程)并且根据一个已知的线程—可能通过SessionManager或者在构造函数中存储的线程初始化时的指针来进行值的比较。

这是一个较为扩展的示例,在不同的线程上同一个对象中调用一个方法。

//请注意,工作线程是没有初始化,直到有人

//调用PseudoTcpChannel:

:

连接

//Alsonotethatthismethod*is*thread-safe.

boolPseudoTcpChannel:

:

Connect(conststd:

:

string&channel_name){

ASSERT(signal_thread_->IsCurrent());

CritScopelock(&cs_);

if(channel_)

returnfalse;

ASSERT(session_!

=NULL);

worker_thread_=session_->session_manager()->worker_thread();

...

}

voidPseudoTcpChannel:

:

SomeFunction(){

...

//Postamessagetoyourselfovertheworkerthread.

worker_thread_->Post(this,MSG_PING);//<-Goesinhere....

...

}

//Handlequeuedrequests.

voidPseudoTcpChannel:

:

OnMessage(Message*pmsg){

if(pmsg->message_id==MSG_SORT)

OnSort();

elseif(pmsg->message_id==MSG_PING)//->Andcomesouthere!

//Checkthatwe'reintheworkerthreadbeforeproceding.

ASSERT(worker_thread_->IsCurrent());

OnPing();

elseif(pmsg->message_id==MSG_ALLOCATE)

OnAllocate();

else

assert(false);

}

五、NamingConventions

libjinglehassomenamingconventionsthatitisusefultobeawareof:

OnSomeMethod   Methodsbeginningwith"On"areoftenconnectedtoasignal,eitherfromthisoranotherobject.Ifcalledfromthesameobject,itisprobablycalledonadifferentthread.

SomeMethod_w   Methodsendingwith"_w"existinthe"workerthread"andarecalledfromanotherthread

SignalSomeName   Thesearethesignalsthatsendmessagestocallbackmethods.

Libjingle有一些命名约定,知道这些是有用的:

OnSomeMethod方法以“On”开始,通常连接一个这个对象或另一个对象的信号,如果从同一个对象调用,它可能是调用一个不同的线程。

SomeMethod_w方法以“_w“结尾存在于工作线程中并且从另一个线程被调用。

SignalSomeName,这些是发送消息到回调方法的信号。

六、SSLSupport

libjingle支持两种类型的SSL:

OpenSSL(UNIX)

SChannel(对于Windows)

使用SSL,您必须执行以下步骤:

#defineFEATURE_ENABLE_SSL(在VisualStudio项目中,这个值是项目中定义的设置,而不是代码中).

EnsurethateitherSSL_USE_OPENSSLorSSL_USE_SCHANNELare#definedinssladapter.cc.Oneoftheseshouldbedefinedbydefault,dependingonthebuildsettingsforyouroperatingsystem.

确保SSL_USE_OPENSSL或SSL_USE_SCHANNEL被定义在ssladapter.cc中定义。

默认情况下其中一个应该被定义,根据构建设置您的操作系统。

CallInitializeSSLtoinitializerequiredcomponents.Thisfunctionisdefinedinssladapter.cc.Whentheapplicationclosesdown,callCleanupSSL.YoudonotneedtocallInitializeSSLThread(itisusedinternallybyInitializeSSL).

InitializeSSL调用初始化所需的组件。

该函数定义在ssladapter.cc中。

当应用程序关闭时调用CleanupSSL。

你不需要调用InitializeSSLThread(它被用于内部由InitializeSSL使用)。

七、Connections

Alibjinglepeer-to-peerconnectionactuallyconsistsoftwochannels:

Thesessionnegotiationchannel(alsocalledthesignalingchannel)isthecommunicationlinkusedtonegotiatethedataconnection.Thischannelisusedtorequestaconnection,exchangecandidates,andnegotiatethedetailsofthesession(suchas

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高等教育 > 农学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1