学习目的:通过阅读源程序,了解如何使用JAVA的JAIN包来制作SIP客户端程序(IM).
学习笔记:
Class | 说明 |
InstantMessagingGUI | 启动类,负责显示主画面,读如初始化文件,初始化个变量,启动和停止SIPListener. |
IMUserAgent | 实现SIPListener.借口,负责SIPStack和SIPProvider等SIP通信类的生成和初始化,SIPListener的登记和注销,响应各种到达的事件(SIP消息). |
ListenerInstantMessaging | 负责响应主画面的各种UI操作,如Sign in,OFFLINE,IM... |
IMMessageProcessing | 负责IM聊天中的消息发送和接受,其中有DIALOG概念 |
AuthenticationDialog | 让用户输入ID和密码 |
AuthenticationProcess | 负责提供从认证文件来的ID和密码信息,产生认证要求SIP消息的回映SIP消息的头 |
BuddyList | 负责主画面中BuddyList的操作(加,减,信息...)和所对应的认证文件相关操作(读如,保存) |
BuddyTag | BuddyList中的一项 |
ChatFrame | IM画面 |
ChatSession | 负责一个IM画面的操作,各种IM信息管理,收发操作(信息显示,SIP发信...),IM的SIP对话管理 |
ChatSessionManager | 多个ChatSession管理 |
AlertInstantMessaging | 显示错误信息 |
ConfigurationFrame | 初始化信息管理画面 |
RemoteSipURLFrame | 让用户输入IM的对方地址 |
presence下*Processing | 负责各种SIP消息的接受分析和回应 |
IMRegisterProcessing | 负责REGISTER和UNREGISTER消息,成功后会调用IMSubscribeProcessing和IMNotifyProcessing发送附加消息 |
注:gov.nist.javax.sip.Utils被使用,但它在API文档中不存在.
1.REGISTER(sign in)消息
消息行 | 说明 |
REGISTER sip:nist.gov:4000 SIP/2.0 | 请求方法 URI SIP版本号 |
Call-ID: nist-sip-im-register-callId1 | 主机本地表示 |
CSeq: 1 REGISTER | 同一CALLID中的序数 请求方法 |
From: <sip:deruelle@nist.gov>;tag=924 | FROM(用户) 标记(区别共享同一IP地址相同CALLID的请求) |
To: <sip:deruelle@nist.gov> | TO(用户) |
Via: SIP/2.0/UDP 127.0.0.1:4010;branch=z9hG4bK973d37d8ff9de1a0e2a50e5ff70f82e7 | 发送协议 发送方分支参数(用于代理服务器并行分发请求时标记个分支) |
Max-Forwards: 10 | |
Contact: <sip:127.0.0.1:4010;transport=udp> | 给出以后需要时的直接通讯地址 |
Allow: INVITE, SUBSCRIBE, NOTIFY, MESSAGE, INFO, PUBLISH | |
Content-Length: 0 | |
2.REGISTER(sign in)消息的响应
消息行 | 说明 |
SIP/2.0 200 OK | SIP版本号 状态码状态说明 |
Call-ID: nist-sip-im-register-callId1 | (同请求) |
CSeq: 1 REGISTER | (同请求) |
From: <sip:deruelle@nist.gov>;tag=924 | FROM(用户) 标记(区别共享同一IP地址相同CALLID的请求) |
To: <sip:deruelle@nist.gov> | TO(用户) |
Via: SIP/2.0/UDP 127.0.0.1:4010;branch=z9hG4bK973d37d8ff9de1a0e2a50e5ff70f82e7 | 发送协议 发送方分支参数(用于代理服务器并行分发请求时标记个分支) |
Max-Forwards: 10 | |
Contact: <sip:127.0.0.1:4010;transport=udp>;expires=3600 | 直接通讯地址(同请求) REGISTER有效时间 |
Content-Length: 0 | |
3.REGISTER(sign out)消息
基本和REGISTER(sign in)消息一样,只是在以下两个方面不同:
3.1<TO>头部字段和<FROM>头部字段一样加了个标记项.
3.2<Allow>头部字段没有了,被一个<Expires: 0>头部字段所代替了.
4.REGISTER(sign out)消息的响应
和REGISTER(sign out)消息一样有了相应的变化(标记项和<Expires: 0>头部字段).
5.Subscribe和Unsubscribe消息(IM的消息)
在增加一个Contact(联系人)后要向该联系人发送Subscribe消息,该联系人收到该消息后可以认证发送者后作出不同响应.
在删除一个Contact(联系人)后要向该联系人发送Unsubscribe消息,该消息后和Subscribe基本相同,expiresHeader为0或空的是Unsubscribe消息,有大于0数据的是Subscribe消息.
这两个消息和其他SIP消息一样都靠SIPProxy转送.如果消息的接受一方没有Register(在线),SIPProxy会代理没有在线一方响应.
在用户SignIn(发送REGISTER消息)后会自动向所有BUDDYLIST中的用户(联系人)发送SUBSCRIBE消息.同样在用户SIGNOUT(发送UNREGISTER消息)后也应该向所有BUDDYLIST中的用户(联系人)发送UNSUBSCRIBE消息.
Subscribe消息的发送和响应如下:
发送者先检查看和联系人是否已经有DIALOG了,如果已经有了那么fromHeader和toHeader等参数就从DIALOG中取并用DIALOG发送消息,不然就自己产生参数(fromHeader中有新TAG数据而toHeader中没有TAG数据)并用新的TRANSACTION发送.
联系人方收到该消息后,立即返回OK响应消息.随后认证发送者,如果可以接受发送者,就向presenceManager中追加或更新发送者所代表的Subscriber(包括名字,响应消息和DIALOG),并把自己状态通过Notify消息发给发送者(通过SIPPROXY);如果认证结果为不可接受,就通过Notify消息(状态为NULL)通知发送者.
发送者收到响应消息后,就从消息中取得新的DIALOG并往presenceManager中追加或更新发送者所代表的Presentity(包括名字,响应消息和DIALOG).再往buddyList中追加该联系人的情报.
Unsubscribe消息的发送和响应如下:
消息的发送和Subscribe消息的发送一样只是expiresHeader为0.
联系人方收到该消息后,就检查DIALOG情报,如果消息发自以前发送过Subscribe消息的用户(有DIALOG),就返回OK响应,并向发送方发送状态为NULL的NODIFY消息;如果消息发自以前没有发送过Subscribe消息的用户(没有DIALOG),就返回CALL_OR_TRANSACTION_DOES_NOT_EXIST响应.
发送者收到响应消息后,不做任何处理.