libjingle开发(3)

2019-08-31 12:21

// Second parameter gives address of the listener function class definition.

// First parameter points to instance of this class to receive notifications.

Receiver(Sender sender){

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

// When anyone calls Panic(), Receiver::OnDanger gets the message.

// Notice that the number and type of parameters match

// those in Sender::SignalDanger, and that it doesn't return a value.

void Receiver::OnDanger(string message, std::time_t time){

if(message == \{

// Call the police ... } } ...

}

Sender 类声明了一个信号数据成员:

sigslot::signal2 SignalDanger;

语句中的“”声明了可以与此信号成员关联的接收函数的参数形式,必须是 void functionName( string,std::time_t )形式。

从Sender类的成员数void Panic()实现中可以看到,使用信号成员的形式就像是在调用一个与信号成员同名的函数SignalDanger(\,参数类型就是声明信号成员时指定的参数。

Receiver类继承自sigslot::has_slots<>,它的成员函数就具有了成为“接收函数”的“潜质”。

从Receiver的构造函数可以看出,当Receiver对象创建时,必须向它指定一个信号类(即声明了信号成员的类)对象作为构建造函数的参数,当然此信号类必须有Receiver定义的操作用到的信号成员的样式。

一旦Receiver类对象被创建,Sender类中的信号成员就与Receiver类中的OnDanger()函数关联起来了,只要Sender对象的Panic()被调用,Receiver类对象的OnDanger()就被调用,即接收到来自Sender对象的消息,从而进行处理。 如:

Sender sender;

Receiver receiver(sender);

如果 运行: sender.Panic(); 则

receiver.OnDanger();

被自动调用,在此函数的内部就可以处理来自sender的消息。 实现了信号类与接收类之间的松偶合性。

libjingle库中的一些类,发送信号给接收函数(即listeners 监听者,可理解为某个类的接收函数),用来传递一些重要事件。比如:当你发出或收到一个链接尝试时,Call::SignalSessionState就会发出通知信号。在应用程序中应该有接收函数与这些信号关联起来,并且做出适当的行为。

按照libjingle中的约定,在声明信号数据成员时,名字被冠以“Signal”字符,比如:SignalStateChange,SignalSessionState,SignalSessionCreate。

与这些信号关联的函数名被冠以“On”,比如:OnPortDestropyed(),OnOutgoingMessage(),OnSendPacket(); 关于 sigslot库的更多内容,请查看sigslot文档。

二、Thread

libjingle 考虑到使用到此库的应用程序的性能,libjingle内部支持多线程。其内组件使用1或2个全局线程:

● signaling thread 被用作创建底层(基础)组件,

例如:Session Management,Control,XMPP Messaging组件。

● worker thread ( 有时称作channel thread)用来集中处理p2p组件中的对象提交过来的大量资源,例如:数据流。之所以这样用另外的线程单独处理,是为了避免数据流阻塞或被XMPP/用户界面组件阻塞。使用 worker thread的类包括ChannelManage,SocketMonitor,P2PTransportChannel 和 属于Port类的对象。

若起用worker thread,使之工作,在应用中必须创建一个Thread类对象,并把此对象当作SessionManager的构造函数的参数。(如果SessionManager类对象在创建时,没有传递给它Thread对象,则SessionManager类将在内部创建一个线程,当作worker thread)。CallClient::InitPhone示范了如何为底层组件(low-level components)创建一个worker thread方法。

另外、libjingle提供了一个基类SignalThread。扩展此类可以让一个扩展类对象存在于它自身代表的线程,此扩展类对象可以被实例化,启动,单独离开,结束时自释放。更多信息请查看signalthread.h/cc。

注意:尽管libjingle支持多线程,但是只有几个函数通过呼叫方线程的验证来支持线程安全,并且极少函数做了线程锁定。下面的片断示范了在函数中如何安全地呼叫线程(或线程安全地被呼叫):

// Check that being called from the channel (e.g., worker) thread. ASSERT(talk_base::Thread::Current() == channel_thread_); channel_thread_->Clear(this);

libjingle中用到的所有线程,signaling thread,worker thread,其它的一些线程,都是talk_base::Thread的对象(或子类的对象)。所有的Thread对象都被ThreadManager管理,当被请求时,ThreadManager会返回这些Thread对象。SessionManager被创建时通过调用ThreadManager::CurrentThread得到一个signal thread(当无worker thread 传递给SessionManager构造函数时,同时得到一个work thread)。XmppPump类把当前线程当作它的signal thread来用(XmppPump uses the current thread for its signaling thread)。所以,应用程序必须为signal thread创建一个Thread 对象(或其子类对象),并在SessionManager对象创建之前或在XmppPump工作之前,把此对象放进ThreadManager的线程池里。(Signing In to a Server(登录服务器) 有示例)有两种方法创建一个Thread对象:

AutoThread 这种方式就是libjingle用Thread对象包装一个操作系统中的线程,并把它当作ThreadManager线程池里的当前线程(当然,Thread::CurrentThread()被调用时,此线程会被提取出来)。

Thread 这种方式将创建一个新线程并用Thread类包装,比较典型就是的创建worker thread。使此线程发生作用,应用程序必须新创建一个Thread对象,调用ThreadManager::Add()或ThreadManager::SetCurrent()把它丢进线程池里,并且调用Run()使之在阻塞状态下运行或调用Start()使之处于监听状态。

线程为对象间或对象内部的消息沟通提供了“管道”()。例如:SocketManager可以通过其它线程向自己发送销毁一个套接字的消息,或当链接候选被产生时向SessionManager发送消息。Thread继承自MessageQueue,所以Thread的对象具有了Send,Post,和一些同步或异步发送消息的函数。如果要使一个对象能够接收到MessageQueue送出的消息,那么此对象必须继承和实现MessageHandler。MessageHandler定义了一个OnMessage函数,此函数在MessageQueue送出消息时被调用,用来接收MessageQueue送出的消息。

你可以通过任何线程向继承自talk_base::MessageHandler的任何对象发送消息。尽管能够做到,如果你发出的消息是为了集中处理大量的数据,应用程序应该通过worker thread。调用SessionManager::worker_thread()可以得到worker thread的句柄。

调用Session::Manager::signaling_thread()可以得到 signaling thrread的句柄。

对象使用一个指定的线程有如下几种方式:

对象要求一个线程指针作输入参数,并储存这个指针。

对象在创建时取得当前线程(构造函数中调用ThreadManager::CurrentThread()

取得),把取得的线程存进对象内部成员变量引用它,一般应用于获取特定的线程。(it can assume that the current thread when it is created (accessed by ThreadManager::CurrentThread in its constructor) is a particular thread and cache a member pointer to it)

因为一个对象可以被任意线程使用,对象可能需要验证当前调用是来自哪个线程的方法。应用可以调用Thread::Current()得到当前线程的句柄,然后与对象内部保存线程的数据成员进行比较,此数据成员的值可以是从SessionManager中暴露在外面的线程,或是对象在创建时通过构造函数传进去的初始化值。

这是一个对象通过其它线程调用自身函数时而广范使用的范例: // Note that worker_thread_ is not initialized until someone // calls PseudoTcpChannel::Connect

// Also note that this method *is* thread-safe.

bool PseudoTcpChannel::Connect(const std::string& channel_name) { ASSERT(signal_thread_->IsCurrent()); CritScope lock(&cs_); if (channel_) return false;

ASSERT(session_ != NULL);

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

void PseudoTcpChannel::SomeFunction(){ ...

// Post a message to yourself over the worker thread. worker_thread_->Post(this, MSG_PING); // <- Goes in here.... ...

对象调用SessionManger::signal_thread() 或 SessionManager::worker_threa以上三种方法,libjingle均有用到。

d()获取线程。

}

// Handle queued requests.

void PseudoTcpChannel::OnMessage(Message *pmsg) { if (pmsg->message_id == MSG_SORT) OnSort();

else if (pmsg->message_id == MSG_PING) // -> And comes out here! // Check that we're in the worker thread before proceding. ASSERT(worker_thread_->IsCurrent()); OnPing();

else if (pmsg->message_id == MSG_ALLOCATE) OnAllocate(); else

assert(false); }

三、Naming Conventions(命名约定)

libjingle有一些命名约定,比较有用;

OnSomeMethod 凡是以“On”开头的函数,大多和一个信号成员关联起来了,不是在本身对象内就是在其它对象内实现了这种关联。如果此函数被所在对象调用,大有可能是在不同的线程内调用的(即对象通过另一个线程调用自身的函数)。

SomeMethod_w 在worker thread中(“worker thread”,加了引号),以“_w”结尾的函数,是被其它线程调用的。

SignalSomeName 是向回调函数(callbakc methods,即接收函数)发送消息的信号成员。

四、SSL

libjingle 支持两种类型的SSL: ● OpenSSL (for UNIX) ● SChannel (for Windows)

使用SSL,应用程序必须执行如下步骤:


libjingle开发(3).doc 将本文的Word文档下载到电脑 下载失败或者文档不完整,请联系客服人员解决!

下一篇:资产评估操作实施细则 - 图文

相关阅读
本类排行
× 注册会员免费下载(下载后可以自由复制和排版)

马上注册会员

注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信: QQ: