文章分类:JavaEye
服务器端XmppSeverConnection类事件
//在流开始时触发,一般是最初的响应流 streamParser.OnStreamStart += new StreamHandler(streamParser_OnStreamStart); //在流结束时触发,一般是发送</stream:stream>并关闭套接字连接streamParser.OnStreamEnd += new StreamHandler(streamParser_OnStreamEnd); //在接收到流结点时触发,这是用得最多的,常用的<message>消息,<Presence>出席消息,< IQ>请求应答消息都在这里处理 streamParser.OnStreamElement += new StreamHandler(streamParser_OnStreamElement);
//此处处理大部份的消息,包括消息路由 private void streamParser_OnStreamElement(object sender, Node e) { Console.WriteLine("OnStreamElement: " + e.ToString()); if (e.GetType() == typeof(Presence)) { // 路由presences节 } else if (e.GetType() == typeof(Message)) { // 路由messages节 } else if (e.GetType() == typeof(IQ)) { //处理IQ节 } }
/// <summary> /// IQ节处理函数 /// </summary> /// <param name="iq">.</param> private void ProcessIQ(IQ iq) { if (iq.Query.GetType() == typeof(Auth)) { Auth auth = iq.Query as Auth; this.Username = auth.Username.ToString(); switch (iq.Type) { case IqType.get: iq.SwitchDirection(); iq.Type = IqType.result; auth.AddChild(new Element("password")); auth.AddChild(new Element("digest")); Send(iq); break; case IqType.set: // 进行登录认证 if (AccountBus.CheckLogin(auth.Username, auth.Digest, this.SessionId)) { iq.SwitchDirection(); iq.Type = IqType.result; iq.Query = null; Send(iq); Console.WriteLine(auth.Username + "登录了" + " 登录时间:" + System.DateTime.Now.ToString()); } else { //登录失败返回错误信息 iq.SwitchDirection(); iq.Type = IqType.error; iq.Query = null; Send(iq); } break; } } else if (iq.Query.GetType() == typeof(Roster)) { ProcessRosterIQ(iq); } }
/// <summary> /// 处理IQ节的杂项数据. /// </summary> /// <param name="iq">The iq.</param> private void ProcessRosterIQ(IQ iq) { if (iq.Type == IqType.get) { // 发送IQ节的杂项数据 //这里我用来下载好友列表 iq.SwitchDirection(); iq.Type = IqType.result; List<string> friendList = new List<string>(); friendList = AccountBus.GetFriendName(this.username); foreach (string str in friendList) { RosterItem ri = new RosterItem(); ri.Name = str.Trim(); ri.Subscription = SubscriptionType.both; ri.Jid = new agsXMPP.Jid(str.Trim() + "@localhost"); ri.AddGroup("localhost"); iq.Query.AddChild(ri); } Send(iq); } }
服务器端开启监听5222 端口
while (running) { //// allDone.Reset(); // Start an asynchronous socket to listen for connections. Console.WriteLine("等待连接"); listener.BeginAccept(new AsyncCallback(AcceptCallback), null); //// 等待客户端连接 allDone.WaitOne(); }
如果收到客户端请求就异步调用AcceptCallback初始化套接字连接
,并为客户端建立一个通信线程,新建初始化套接字连接采用异步调
用读取套接字信息
public XmppSeverConnection(Socket sock) : this() { m_Sock = sock; m_Sock.BeginReceive(buffer, 0, BUFFERSIZE, 0, new AsyncCallback(ReadCallback), null); m_Sock.SendTimeout = 100; }
客户端与服务器端的交互过程
1客户端异步向服务器端发送连接请求
<stream:stream to='localhost' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0' xml:lang='en'>
2服务器端收到请求,初始化回应流,并随机生成一相SessionID
<stream:stream xmlns:stream="http://etherx.jabber.org/streams " from="localhost" id="30e3b8c0" >
3等待服务器返回消息后客户端发送用户名(由于在客户端采用了异步调用
方式,所以UI界面感觉不到等待)
<iq xmlns="jabber:client" id="agsXMPP_1" type="get" to="localhost">
<query xmlns="jabber:iq:auth"><username>test</username></query></iq>
4服务器端收到用户名等待用户提供密码
<iq xmlns="jabber:client" from="localhost" type="result" id="agsXMPP_1">
<query xmlns="jabber:iq:auth"><username>test</username><password />
<digest /></query></iq>
5客户端提供加密后的密码
<iq xmlns="jabber:client" id="agsXMPP_2" to="localhost" type="set">
<query xmlns="jabber:iq:auth"><username>test</username>
<digest>e66557d2b67256bf7e9b317a51b6101674a56b5e</digest>
<resource>MiniClient</resource></query></iq>
6服务器端从数据库验证用户名和密码,并返回结果
iq xmlns="jabber:client" from="localhost" type="result" id="agsXMPP_2" />
7如果返回错误,客户端提示并终断连接,否则客户端发送响应数据
8 服务器端返回数据
9 客户端发送状态,
10服务器收到状态,发送IQ节并通知其它用户.