• 管理软件IM开发


    一、即时通讯介绍

    即时通讯(Instant Messenger,简称IM),是一种基于互联网的即时交流消息的业务,代表有:阿里旺旺、QQ、百度Hi等。

    企业内部应用即时通讯的特点和要求

    特点是沟通成本低,高效,方便,快捷,具备一定的用户黏度

    1.即时通讯,包括文字,图片,语音,视频,文件。

    2.群组功能,讨论组。

    3.重点考虑商务沟通过程中的特点,比如视频会议功能,PPT演示,无线连接投影仪,再比如重要聊天记录保存,还有方便快捷的转账业务。

    4.UI简洁高效,大方美观,特别是无广告。

    5.用户联系方式导入,支持手机通讯里,EXCEL,MSN通讯录等等。

    6.快捷键,常用功能,如截图,关闭。

    7.注重隐私保护,身份验证,各种状态,在线,隐身。

    8.设计要稳重,比如个人资料要设置为名片,企业形象等等。

    二、Openfire介绍

    服务端Openfire

    源码下载地址http://www.igniterealtime.org/downloads/source.jsp

    客户端Spark

    源码下载地址http://fisheye.igniterealtime.org/browse/spark/trunk

    主要功能

    1、支持多服务器集群;

    2、防火强穿透;

    3、在线、离线消息;

    4、文件,图片实时传输;

    5、自动升级;

    6、插件功能;

    7、群聊;

    8、好友添加。

    三、企业IM开发规划

    1、技术选型:采用DotNet平台 c#语言开发,数据库采用SQL Server 2008 R2 ,服务端  Socket App集成后台管理。

    2、客户端升级:采用智能客户端实现升级。

         a.创建一个升级程序,连接 webservice 来获取程序版本和升级程序的信息;

         b.将升级程序下载到本机的一个目录然后覆盖现有的程序;

         c.在配置文件中记录本次升级的信息。

    4、架构图:

    5、数据协议

    采用XMPP格式数据进行传输

    XMPP : The Extensible Messaging and Presence Protocol。

    中文全称:可扩展通讯和表示协议。

    XMPP是一种基于XML的协议,它继承了在XML环境中灵活的发展性。因此,基于XMPP的应用具有超强的可扩展性。

    而XMPP的核心部分就是一个在网络上分片段发送XML的流协议。

    XMPP节详解

    XML节通过XML流来发送,XMPP定义了三种顶级XML节

    <message />    --用户之间的信息发送

    <iq />                --服务器请求返回信息

    <presence />   --状态

    XMPP给这三种节定义了五种通用属性

    to         属性指定接收节的JID

    from    属性指定发送节的JID

    id         并且,在接收应用(通常是一个服务器)中是唯一的。注意:流ID可能是严格安全的,并且因此必须是即不能预测也不能重复的

    type    属性指定目的或消息上下文,出席或IQ节的详细信息。

    xml:lang

    <message />节定义了消息语义,<message />节可被看作“推”机制,一个实体推信息给其它实体,与EMAIL系统中发生的通信类似。所有消息节应该拥有‘to’属性,指定有意的消息接收者;根据接收到那样的一个节,服务器应该路由或传送它到有意的接收者。
    message用于“发送后即忘”的传输(发送后不验证消息是否接收成功,功能上并非技术上的),这样的传输主要应用与人类可读的文本、警告、通知等信息。

    <iq />节定义了请求语义,<iq />节可被看作一个请求-响应机制,与[HTTP]在某些方面相似。IQ语义让一个实体向其它实体请求或接收其它实体的响应成为可能。请求与响应的数据内容由IQ无素的直接子元素的命名空间声明定义,并且,交互由请求实体通过使用‘id’属性来跟踪。因此,IQ交互遵从结构化数据交换的一个通用模式,此交换例如得到/结果或设置/结果(虽然如果合适的话,对一个请求的响应可能会以错误返回)。

    <presence />节定义了出席语义,<presence />节可被看作基本广播或“出版-订阅”机制,多实体收到他们已订阅(在这种情况下,网络可利用信息)实体的信息。总的来说,出版实体应该发送一个不带‘to’属性的出席节,在这种情况下,与此实体相连的服务器应该广播给所有订阅实体。然而,一个出版实体也可能发送一个带有‘to’属性的出席节,此种情况下,服务器应该路由或传送节到有意的接收者。
    presence用于向那些订阅实体广播网络可用性。

    6、XMPP通信原理

    所有从一个client到另一个client的消息和数据都要通过xmpp server。

    1.client连接到server;

    2.server利用本地目录系统的证书对其认证;

    3.client制定目标地址,让server告知目标状态;

    4.server查找,连接并进行相互认证;

    5.client间进行交互。

    8、基于XMPP协议.net实现

     四、后台数据库集成

    集成主要的表结构

    五、Socket开发技术

          P2P技术(P2P打洞)

    一个异步Socket通信的源码

    using System;
    using System.Net;
    using System.Net.Sockets;
    using System.Text;
    
    namespace Chatting
    {
        public abstract class SocketFunc
        {
            //不管是服务端还是客户端, 建立连接后用这个Socket进行通信
            public Socket communicateSocket = null;
    
            //服务端和客户端建立连接的方式稍有不同, 子类会重载
            public abstract void Access(string IP, System.Action AccessAciton);
    
            //发送消息的函数
            public void Send(string message)
            {
                if (communicateSocket.Connected == false)
                {
                    throw new Exception("还没有建立连接, 不能发送消息");
                }
                Byte[] msg = Encoding.UTF8.GetBytes(message);
                communicateSocket.BeginSend(msg,0, msg.Length, SocketFlags.None,
                    ar => {
                    
                    }, null);
            }
    
            //接受消息的函数
            public void Receive(System.Action<string> ReceiveAction)
            {
                //如果消息超过1024个字节, 收到的消息会分为(总字节长度/1024 +1)条显示
                Byte[] msg = new byte[1024];
                //异步的接受消息
                communicateSocket.BeginReceive(msg, 0, msg.Length, SocketFlags.None,
                    ar => {
                        //对方断开连接时, 这里抛出Socket Exception
                        //An existing connection was forcibly closed by the remote host 
                            communicateSocket.EndReceive(ar); 
                        ReceiveAction(Encoding.UTF8.GetString(msg).Trim('\0',' '));
                        Receive(ReceiveAction);
                    }, null);
            }
        }
    
    
        public class ServerSocket:SocketFunc
        {
            //服务端重载Access函数
            public override void Access(string IP, System.Action AccessAciton)
            {
                Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                //本机预使用的IP和端口
                IPEndPoint serverIP = new IPEndPoint(IPAddress.Any, 9050);
                //绑定服务端设置的IP
                serverSocket.Bind(serverIP);
                //设置监听个数
                serverSocket.Listen(1);
                //异步接收连接请求
                serverSocket.BeginAccept(ar =>
                    {
                        base.communicateSocket = serverSocket.EndAccept(ar);
                        AccessAciton();
                    }, null);
            }
        }
    
        public class ClientSocket:SocketFunc
        {
            //客户端重载Access函数
            public override void Access(string IP, System.Action AccessAciton)
            {
                base.communicateSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                base.communicateSocket.Bind(new IPEndPoint(IPAddress.Any, 9051));
                
                //服务器的IP和端口
                IPEndPoint serverIP;
                try
                {
                    serverIP = new IPEndPoint(IPAddress.Parse(IP), 9050);
                }
                catch
                {
                    throw new Exception(String.Format("{0}不是一个有效的IP地址!", IP));
                }
                
                //客户端只用来向指定的服务器发送信息,不需要绑定本机的IP和端口,不需要监听
                try
                {
                    base.communicateSocket.BeginConnect(serverIP, ar =>
                    {
                        AccessAciton();
                    }, null);
                }
                catch
                {
                    throw new Exception(string.Format("尝试连接{0}不成功!", IP));
                }
            }
        }
    }
    using System;
    using System.Drawing;
    using System.Windows.Forms;
    using System.Net.Sockets;
    
    namespace Chatting
    {
        public partial class MainForm : Form
        {
    
            public MainForm()
            {
                InitializeComponent();
            }
    
            SocketFunc socket;
            System.Action<string> ReceiveAction;
            System.Action AccessAction;
    
            private void MainForm_Load(object sender, EventArgs e)
            {
                //异步建立连接回调
                AccessAction = () =>
                {
                    this.Invoke((MethodInvoker)delegate()
                    {
                        lblFriendIP.Visible = false;
                        txtIP.Visible = false;
                        btnConnect.Visible = false;
                        btnWaitAccess.Visible = false;
    
                        String friendIP = socket.communicateSocket.RemoteEndPoint.ToString();
                        lblState.Text = String.Format("连接成功. 对方IP:{0}", friendIP);
    
                        try
                        {
                            socket.Receive(ReceiveAction);
                        }
                        catch (Exception exp)
                        {
                            MessageBox.Show(exp.Message, "错误");
                        }
                    });
    
                };
                //异步接收消息回调
                ReceiveAction = msg =>
                {
                    txtGetMsg.Invoke((MethodInvoker)delegate()
                    {
                        UpdateGetMsgTextBox(false, msg, Color.Red);
                    });
                };
            }
    
            private void btnWaitAccess_Click(object sender, EventArgs e)
            {
                this.socket = new ServerSocket();
                try
                {
                    this.socket.Access("", this.AccessAction);
                }
                catch (Exception ecp)
                {
                    MessageBox.Show(ecp.Message, "错误");
                }
    
                lblState.Text = "等待对方连接...";
            }
    
            private void btnConnect_Click(object sender, EventArgs e)
            {
                this.socket = new ClientSocket();
                try
                {
                    this.socket.Access(txtIP.Text, this.AccessAction);
                }
                catch (Exception ecp)
                {
                    MessageBox.Show(ecp.Message, "错误");
                }
                lblState.Text = "正在连接对方...";
            }
    
            private void btnSendMsg_Click(object sender, EventArgs e)
            {
                string message = txtSendMsg.Text.Trim();
                if (string.IsNullOrEmpty(message))
                {
                    MessageBox.Show("消息内容不能为空!", "错误");
                    txtSendMsg.Focus();
                    return;
                }
    
                try
                {
                    socket.Send(message);
                }
                catch(Exception ecp)
                {
                    MessageBox.Show(ecp.Message, "错误");
                    return;
                }
    
                UpdateGetMsgTextBox(true, message, Color.Blue);
                txtSendMsg.Text = "";
            }
    
            private void UpdateGetMsgTextBox(bool sendMsg, string message, Color color)
            {
                string appendText;
                if (sendMsg == true)
                {
                    appendText = "Me:           " + System.DateTime.Now.ToString()
                        + Environment.NewLine
                        + message + Environment.NewLine;
                }
                else
                {
                    appendText = "Friend:           " + System.DateTime.Now.ToString()
                        + Environment.NewLine
                        + message + Environment.NewLine;
                }
                int txtGetMsgLength = txtGetMsg.Text.Length;
                txtGetMsg.AppendText(appendText);
                txtGetMsg.Select(txtGetMsgLength, appendText.Length - Environment.NewLine.Length*2 -message.Length);
                txtGetMsg.SelectionColor = color;
    
                txtGetMsg.ScrollToCaret();
            }
        }
    }
    namespace Chatting
    {
        partial class MainForm
        {
            /// <summary>
            /// 必需的设计器变量。
            /// </summary>
            private System.ComponentModel.IContainer components = null;
    
            /// <summary>
            /// 清理所有正在使用的资源。
            /// </summary>
            /// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
            protected override void Dispose(bool disposing)
            {
                if (disposing && (components != null))
                {
                    components.Dispose();
                }
                base.Dispose(disposing);
            }
    
            #region Windows 窗体设计器生成的代码
    
            /// <summary>
            /// 设计器支持所需的方法 - 不要
            /// 使用代码编辑器修改此方法的内容。
            /// </summary>
            private void InitializeComponent()
            {
                System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm));
                this.label1 = new System.Windows.Forms.Label();
                this.label2 = new System.Windows.Forms.Label();
                this.txtSendMsg = new System.Windows.Forms.TextBox();
                this.lblFriendIP = new System.Windows.Forms.Label();
                this.txtIP = new System.Windows.Forms.TextBox();
                this.btnConnect = new System.Windows.Forms.Button();
                this.btnSendMsg = new System.Windows.Forms.Button();
                this.btnWaitAccess = new System.Windows.Forms.Button();
                this.txtGetMsg = new System.Windows.Forms.RichTextBox();
                this.lblState = new System.Windows.Forms.Label();
                this.SuspendLayout();
                // 
                // label1
                // 
                resources.ApplyResources(this.label1, "label1");
                this.label1.BackColor = System.Drawing.Color.Transparent;
                this.label1.ForeColor = System.Drawing.SystemColors.Window;
                this.label1.Name = "label1";
                // 
                // label2
                // 
                resources.ApplyResources(this.label2, "label2");
                this.label2.BackColor = System.Drawing.Color.Transparent;
                this.label2.ForeColor = System.Drawing.SystemColors.Window;
                this.label2.Name = "label2";
                // 
                // txtSendMsg
                // 
                this.txtSendMsg.BorderStyle = System.Windows.Forms.BorderStyle.None;
                resources.ApplyResources(this.txtSendMsg, "txtSendMsg");
                this.txtSendMsg.Name = "txtSendMsg";
                // 
                // lblFriendIP
                // 
                resources.ApplyResources(this.lblFriendIP, "lblFriendIP");
                this.lblFriendIP.ForeColor = System.Drawing.SystemColors.Window;
                this.lblFriendIP.Name = "lblFriendIP";
                // 
                // txtIP
                // 
                resources.ApplyResources(this.txtIP, "txtIP");
                this.txtIP.Name = "txtIP";
                // 
                // btnConnect
                // 
                resources.ApplyResources(this.btnConnect, "btnConnect");
                this.btnConnect.Name = "btnConnect";
                this.btnConnect.UseVisualStyleBackColor = true;
                this.btnConnect.Click += new System.EventHandler(this.btnConnect_Click);
                // 
                // btnSendMsg
                // 
                resources.ApplyResources(this.btnSendMsg, "btnSendMsg");
                this.btnSendMsg.Name = "btnSendMsg";
                this.btnSendMsg.UseVisualStyleBackColor = true;
                this.btnSendMsg.Click += new System.EventHandler(this.btnSendMsg_Click);
                // 
                // btnWaitAccess
                // 
                resources.ApplyResources(this.btnWaitAccess, "btnWaitAccess");
                this.btnWaitAccess.Name = "btnWaitAccess";
                this.btnWaitAccess.UseVisualStyleBackColor = true;
                this.btnWaitAccess.Click += new System.EventHandler(this.btnWaitAccess_Click);
                // 
                // txtGetMsg
                // 
                this.txtGetMsg.BackColor = System.Drawing.SystemColors.Window;
                this.txtGetMsg.BorderStyle = System.Windows.Forms.BorderStyle.None;
                resources.ApplyResources(this.txtGetMsg, "txtGetMsg");
                this.txtGetMsg.Name = "txtGetMsg";
                this.txtGetMsg.ReadOnly = true;
                // 
                // lblState
                // 
                resources.ApplyResources(this.lblState, "lblState");
                this.lblState.ForeColor = System.Drawing.SystemColors.Window;
                this.lblState.Name = "lblState";
                // 
                // MainForm
                // 
                this.AcceptButton = this.btnSendMsg;
                resources.ApplyResources(this, "$this");
                this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
                this.BackColor = System.Drawing.Color.Navy;
                this.Controls.Add(this.lblState);
                this.Controls.Add(this.txtGetMsg);
                this.Controls.Add(this.btnWaitAccess);
                this.Controls.Add(this.btnSendMsg);
                this.Controls.Add(this.btnConnect);
                this.Controls.Add(this.txtIP);
                this.Controls.Add(this.lblFriendIP);
                this.Controls.Add(this.txtSendMsg);
                this.Controls.Add(this.label2);
                this.Controls.Add(this.label1);
                this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
                this.MaximizeBox = false;
                this.Name = "MainForm";
                this.Load += new System.EventHandler(this.MainForm_Load);
                this.ResumeLayout(false);
                this.PerformLayout();
    
            }
    
            #endregion
    
            private System.Windows.Forms.Label label1;
            private System.Windows.Forms.Label label2;
            private System.Windows.Forms.TextBox txtSendMsg;
            private System.Windows.Forms.Label lblFriendIP;
            private System.Windows.Forms.TextBox txtIP;
            private System.Windows.Forms.Button btnConnect;
            private System.Windows.Forms.Button btnSendMsg;
            private System.Windows.Forms.Button btnWaitAccess;
            private System.Windows.Forms.RichTextBox txtGetMsg;
            private System.Windows.Forms.Label lblState;
        }
    }
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Windows.Forms;
    
    namespace Chatting
    {
        static class Program
        {
            /// <summary>
            /// 应用程序的主入口点。
            /// </summary>
            [STAThread]
            static void Main()
            {
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
                Application.Run(new MainForm());
            }
        }
    }
  • 相关阅读:
    概率面试题
    机器学习概率题总结(转载)
    筛素数以及判断数是否是素数
    腾讯2019正式批春笔试题
    推荐系统架构
    文本表示与匹配
    CTR预估经典模型总结
    spark运行原理
    leetcode 字符串动态规划总结
    无向图的邻接矩阵创建代码以及深度遍历广度遍历
  • 原文地址:https://www.cnblogs.com/cbi360/p/3103041.html
Copyright © 2020-2023  润新知