.net平台 基于 XMPP协议的即时消息服务端简单实现

昨天抽空学习了一下XMPP,在网上找了好久,中文的资料太少了所以做这个简单的例子,今天才完成。公司也正在准备开发基于XMPP协议的即时通讯工具所以也算是打一个基础吧!如果你还没有了解过XMPP请先阅读附录中链接的文章,本实例是基agsXMPP上开发的,agsXMPP是C#写的支持开源XMPP协议软件,我们可以在agsXMPP上快速构建自已的即时通讯平台,我的这个例子只是修改了服务器端,因为agsXMPP本身自带的服务器端没有实现聊天功能、签名和登录密码认证。

服务器端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节并通知其它用户.

项目解决方案和类图


附录:
推荐使用Pandion作为客户端
服务器端下载     客户端下载agsXMPP 源码下载 
XMPP RFC 3920 可扩展消息出席协议 
jabber官方网站

 
分类: XMPP实践

.net平台 基于 XMPP协议的即时消息服务端简单实现的更多相关文章

  1. 基于XMPP协议的手机多方多端即时通讯方案

    一.开发背景 1.国际背景 随着Internet技术的高速发展,即时通信已经成为一种广泛使用的通信方式.1996年Mirabilis公司推出了世界上第一个即时通信系统ICQ,不到10年间,即时通信(I ...

  2. MQTT的学习研究(八)基于HTTP DELETE MQTT 订阅消息服务端使用

    HTTP DELETE 订阅主题请求协议和响应协议http://publib.boulder.ibm.com/infocenter/wmqv7/v7r0/topic/com.ibm.mq.csqzau ...

  3. 基于XMPP协议的Android即时通信系

    以前做过一个基于XMPP协议的聊天社交软件,总结了一下.发出来. 设计基于开源的XMPP即时通信协议,采用C/S体系结构,通过GPRS无线网络用TCP协议连接到服务器,以架设开源的Openfn'e服务 ...

  4. 基于XMPP协议(openfire服务器)的消息推送实现

    转自:http://blog.csdn.net/nomousewch/article/details/8088277 最近好像有不少朋友关注Android客户端消息推送的实现,我在之前的项目中用到过J ...

  5. python测试基于websocket协议的即时通讯接口

    随着html5的广泛应用,基于websocket协议的即时通讯有了越来越多的使用场景,本文使用python中的websocket-client模块来做相关的接口测试 import webclient ...

  6. IOS基于XMPP协议开发--XMPPFramewok框架(一):基础知识

    最近蘑菇街团队的TT的开源,使我对im产生了兴趣,然后在网上找到了XMPPFramework进行学习研究, 并写了以下系列教程供大家参考,有写的不对的地方,请大家多多包涵指正. 目录索引 IOS基于X ...

  7. 通过集群的方式解决基于MQTT协议的RabbitMQ消息收发

    在完成了基于AMQP协议的RabbitMQ消息收发后,我们要继续实现基于MQTT协议的RabbitMQ消息收发. 由于C#的RabbitMQ.Client包中只实现了基于AMQP协议的消息收发功能的封 ...

  8. 开源jabber(XMPP)架设内部即时通讯服务的解决方案

    Jabber 是著名的即时通讯服务服务器,它是一个自由开源软件,能让用户自己架即时通讯服务器,可以在Internet上应用,也可以在局域网中应用.    XMPP(可扩展消息处理现场协议)是基于可扩展 ...

  9. “一切都是消息”--iMSF(即时消息服务框架)入门简介

    “一切都是消息”--这是iMSF(即时消息服务框架)的设计哲学. MSF的名字是 Message Service Framework 的简称,由于目前框架主要功能在于处理即时(immediately) ...

随机推荐

  1. OpenNI2安装

    1.Openni2:从官网下载linux用zip压缩包,解压再解压2.终端转到解压目录下,找到install.sh文件,执行$sudo ./install.sh 3.执行后,生成OpenNIDevEn ...

  2. ajax获取数据的处理和实例

    HTML: <!DOCTYPE HTML><html><head><meta http-equiv="Content-Type" cont ...

  3. Android横竖屏总结(转)

    Android横竖屏总结(转) 横竖屏切换后Activity会重新执行onCreat函数,但是在Android工程的Mainfest.xml中加入android:screenOrientation=& ...

  4. 51Nod 1048 整数分解为2的幂 V2

    题目链接 分析: $O(N)$和$O(NlogN)$的做法很简单就不写了...%了一发神奇的$O(log^3n*$高精度$)$的做法... 考虑我们只能用$2$的整次幂来划分$n$,所以我们从二进制的 ...

  5. 我们曾经心碎的数据库之 用SQL语句操作数据

    第八章   用SQL语句操作数据 1.SQL简介 SQL语言是能够识别指令,执行相应的操作并为程序提供数据的一套指令集 SQL的全称: 结构化查询语言(Structured Query Languag ...

  6. [摸鱼] 配置的vim的使用攻略!

    vim使用攻略 <>=f 折叠与缩进 开:<>[^fuck]cc 关:<>cu 缩进一块使用V选中,按>> [Ctrl]V 以列为单位选 za,打开或关 ...

  7. UVALIVE 2955 Vivian's Problem

    参考: http://blog.csdn.net/acm_cxlove/article/details/7860735 感觉这里需要记录一下 #include <map> #include ...

  8. V4L2 camera 驱动 capture测试程序【转】

    转自:http://blog.csdn.net/kickxxx/article/details/6336346 在网上找了一个测试程序, 看了看,是根据capture.c修改的.测试步骤如下 . gc ...

  9. hdu 5105(数学题)

    Math Problem Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Tota ...

  10. J.U.C并发框架源码阅读(九)LinkedBlockingQueue

    基于版本jdk1.7.0_80 java.util.concurrent.LinkedBlockingQueue 代码如下 /* * ORACLE PROPRIETARY/CONFIDENTIAL. ...