| |
Jabber即时通讯客户端(五) |
|
时间: 2006-05-10 来自:huwell |
 |
|
考虑到面向对象的特性,WellJabber程序采用了类的定义,以方便脚本调用,支持类是PHP中很有用的特点,特别是数据库操作,如果能把一般SQL行为用类来封装,那么在修改数据库类型时将会很方便,做到以做少的改动支持最大的兼容性。
WellJabber中的类定义放在jabber.inc中,一共有6个行为,分别是: jabber->connect (server[, port]) jabber->Login (username, password, resource,server[, port]) jabber->messages (recipient, subject, body, type) jabber->register(username, password, email, resource, server[, port]) jabber->GetRoster() jabber->_display_error_message() 在定义好这几个类以后,脚本就可以很方便的实现jabber的通讯功能,而不必重复代码。配合模版的设计,使得PHP版的Jabber更为方便灵活。 根据jabber文档中的描述,WellJabber类中定义了以下的成员变量,其值与特定含义分别是: name——用户的真实姓名; email——用户的电子邮件; password——用户选用的密码; username——用户登录名称; resource——用户的Location辨识名; sid——本次session的唯一标识 server——登录服务器名称; port——登录服务器端口名称; error_code——发送错误的代码; error——发送的错误(描述) connect——本次连接的文件指针 roster——好友资料数组
首先,看一看内部的出错处理函数:_display_error_message(): 这里error的错误描述实际上就是[JPO]的附录所指明的错误描述代码,这是标准的,由服务器发回的。 Jabber类中要处理的错误列表为: Bad Request
这个表明jabber客户端发送的数据不能为server端理解,通 常是由于数据流不符合jabber协议而引起的。(譬如,jabber客户端发送了一个subscriptioj给自己,或者是发送了一个不含to属性的数据流。
Unauthorized
这个表明客户端的身份请求验证失败,当客户端发出错误的密 码或者是不存在的用户名时会发生这种情况。
Service Unavailable
这个错误主要发生在服务器无法处理客户端的请求时,譬如, 当我们要发送一个消息给离线好友,但接收者的服务器不支持离线信息存储的机制,就会返回这个错误。
Remote Server Timeout
当试图连接一个服务器而超时时就会发生这个错误。比如说一 个不正确的服务器名称被指定时。
Payment Required
这个错误是为未来使用制定的,现在不会发生。
Forbidden
这个错误发生时表明,服务器理解客户端的请求,但拒绝处理 它。现在主要发生在当注册时密码存储错误时。
Not Found
这个主要是在服务器无法找到与这个客户端送来的数据包匹 配的JabberID时发生的。
Not Allowed
本错误主要是当服务器根据该数据包中的JabberID判定本次
Jabber行为无效时产生的,譬如当非管理员用户向服务器发送一个管理员数据命令时。
Registration Required
这个错误现在尚未开始使用。
Internal Server Error
当服务器发生了未知错误时,就会返回这个error,要防止这 种情况发生主要是从客户端入手,要保证发送的数据包的正确性。
Invalid Parameter
无效的参数错误。
在发生上述错误时,_display_error_message()都会做出正确的处理,实在有未知的错误发生时,也会提示与管理员联系。
下面一一分析成员函数,先看用户登录时所用的:
function connect ($server, $port = "5222") 注意这里默认的端口为5222。如果你使用了SSL登录也可以改为5223。函数里首先是验证传递过来的参数的合法性。也就是server,username,password及resource不能为空,否则就报告错误。
接着是与server端的5222端口相连接,这里使用了fsockopen函数,这个函数功能很强大,它与服务器做了一个TCP连接,并且它返回了一个文件指针,可用于其他的文件函数(如fgets、fgetss、fputs、fclose或feof等)。可以说没有它,jabber的功能就实现不了,因为jabber主要是依靠与server的连接,交互数据流来实现的,用其他语言如C/C++可以很方便的调用connect函数(以及之后的send、receive函数),同样PHP有fsockopen()也很不错。
登录时使用Login ($username, $password, $resource, $server, $port = "5222"),当jabber->connect()打开连接后,开始向server端发送数据,譬如登录时发送的XML数据包,随后要读入返回的流,这时会产生一个错误,因为使用fread或fgets等PHP文件操作函数,都要求读入一定的量字符数(按照参数),或者是读到行尾或文件尾,但是由服务器返回的数据是一个完整XML流的一部分,没有所谓的行分隔,我们预先也无法知道此次返回多少字节,如果写成fgets($fp, 1024)这样的,就会使该脚本陷入延时,因为fgets行为就是想读入1024个字节或者是到行尾/文件尾,等如果本次数据量小于1024字节,就会陷入这个函数,不能正确返回值。
在查阅了php.net的最新函数后发现,我们可以依靠socket_get_status()函数的unread_bytes特性来间接处理,说实话,这个方法有点勉强,但由于PHP语言的限制,实在没有其他方法来很好的处理它,如果是C/C++,那就很方便了,recv()函数自己知道收回多少数据,再不然配合Peek参数也可以预知本次数据量。
而使用socket_get_status()方法,就要分两步做,首先使用fgets()类型的函数读取一次数据(可以读一个字节),然后再用unread_bytes得知本次未读数据,依据这个准确的字节数,再调用fgets()一次就可以全部读取了。由于要分两步做,所以效率不是很高的。然后拼接两次得到的字符串,就有了本次回应的数据流了。
收到XML数据后就要来解析它,PHP有很强大的XML解析函数,因为它是依靠expat做后台模块的。首先要创建一个XML解析器,就好象与MySql数据库做连接一样,都是准备工作:
xml_parser_create();//使用缺省编码ISO=8859-1
在下面的函数中都要用到这个解析器,然后调用xml_set_element_handler()来设置起始及结束元素的处理,第一个参数就是上面说到的解析器,第二个和第三个是XML特有规定的函数处理格式的名称,主要是:
StartElementHandler(int parser, string name, string attr)
第一个参数也是解析器,第二个用于保存XML元素名称,缺省情况下,它们会以大写形式出现。第三个是数组,用以保存当前元素的属性及对应值。有了它,可以利用PHP特有的each逐个读出来。
我们在StartElementHandler中将本次要用到的元素属性赋值,以便下面的调用判断,如登录中就是要对$jabber_type值是否为result进行判断,如果是表明登录成功,如果不是那就是登录失败了。
接下来是GetRoster()行为,使用它可以获得当前用户的好友列表,我们发送:
<iq type="get"><query xmlns="jabber:iq:roster"/></iq>
给服务器,即索要当前会话用户的好友列表,然后服务器会返回一系列数据流,里面包括了好友的名称,JID(jabber唯一标识,就好象是QQ中的数字号码)以及认证状态,如果还没有通过好友的认证,那subscription属性就会为none,WellJabber中采用了$jabber->roster成员变量来接收这一系列的值。需要注意的是每次成员函数调用时都使用同一个连接,i.e.$jabber->connect,所以单个行为不要调用fclose来关闭它,可以在类的析构函数中调用。
SenMessage()发送消息给好友,这里比较简单,当获取好友的JID时,发送相应的数据流即可,这里要注意的是,发送人不需要自己填写,在经过服务器处理后,会由服务器来添加“from”属性,这个是为了防止发送垃圾信息,前面已经说过了。
最后是登记新的用户帐号,这里分四步: 首先,要向服务器发送一个连接请求,就如同登录时所发送的一样;
接着,客户端会收到回应的数据流,这里包含了重要的id,是标识本次会话的唯一值;这时,我们要发送本次想注册的用户名,resource名及密码,注意这里的<iq>请求要包含上面得到的id,而且密码应该采用加密的形式,但WellJabber只是一个演示程序,所以采用了明文发送的形式;
最后,服务器返回<iq di=’sesseion id’type=’result’> 代表本次登记注册成功。这样就完成了一个新用户的注册。
然后就可以使用该帐号进行登录了。注意,这里要重新与服务器打开一个连接,原先的连接已经不能用来登录了。
PHP版的WellJabber所拥有的功能已经描述完了。当然,从它来看Jabber工程只能是管中窥豹,Jabber中许多有用的思想和特点它都没有体现,譬如说实时接收、文件交换、邮件转发、聊天室系统甚至是跨平台交流(如mobile)。但由于Jabber开放和易用的特性,我们看到,任何人都可以用自己喜欢的语言去处理jabber、去理解jabber,这么博大包容的特性也许就是它最吸引人的地方,Jabber的前途将无可限量。
|
|
|
|
|
|
|
|