轻量级通信引擎StriveEngine —— C/S通信demo(附源码)

前段时间,有几个研究ESFramework的朋友对我说,ESFramework有点庞大,对于他们目前的项目来说有点“杀鸡用牛刀”的意思,因为他们的项目不需要文件传送、不需要P2P、不存在好友关系、也不存在组广播、不需要服务器均衡、不需要跨服务器通信、甚至都不需要使用UserID,只要客户端能与服务端进行简单的稳定高效的通信就可以了。于是,他们建议我,整一个轻量级的通信组件来满足类似他们这种项目的需求。我觉得这个建议是有道理的,于是,花了几天时间,我将ESFramework的内核抽离出来,经过修改封装后,形成了StriveEngine,其最大的特点就是稳定高效、易于使用。通过下面这个简单的demo,我们应该就能上手了。文末有demo源码下载,我们先上Demo截图:

  

1.Demo简介

该Demo总共包括三个项目:

1.StriveEngine.SimpleDemoServer:基于StriveEngine开发的服务端。

2.StriveEngine.SimpleDemoClient:基于StriveEngine开发的客户端。

3.StriveEngine.SimpleDemo:直接基于.NET的Socket开发的客户端,其目的是为了演示:在客户端不使用StriveEngine的情况下,如何与基于StriveEngine的服务端进行通信。

StriveEngine 内置支持TCP/UDP、文本协议/二进制协议,该Demo我们使用TCP、文本格式的消息协议,消息的结束符为"\0"。

2.Demo服务端

    private ITcpServerEngine tcpServerEngine;
    private void button1_Click(object sender, EventArgs e)
    {
        try
        {
            //初始化并启动服务端引擎(TCP、文本协议)
            this.tcpServerEngine = NetworkEngineFactory.CreateTextTcpServerEngine(int.Parse(this.textBox_port.Text), new DefaultTextContractHelper("\0"));         this.tcpServerEngine.ClientCountChanged += new CbDelegate<int>(tcpServerEngine_ClientCountChanged);
            this.tcpServerEngine.ClientConnected += new CbDelegate<System.Net.IPEndPoint>(tcpServerEngine_ClientConnected);
            this.tcpServerEngine.ClientDisconnected += new CbDelegate<System.Net.IPEndPoint>(tcpServerEngine_ClientDisconnected);
            this.tcpServerEngine.MessageReceived += new CbDelegate<IPEndPoint, byte[]>(tcpServerEngine_MessageReceived);
            this.tcpServerEngine.Initialize();

            this.button1.Enabled = false;
            this.textBox_port.ReadOnly = true;
            this.button2.Enabled = true;
        }
        catch (Exception ee)
        {
            MessageBox.Show(ee.Message);
        }
    }

    void tcpServerEngine_MessageReceived(IPEndPoint client, byte[] bMsg)
    {
        string msg = System.Text.Encoding.UTF8.GetString(bMsg); //消息使用UTF-8编码
        msg = msg.Substring(0, msg.Length - 1); //将结束标记"\0"剔除
        this.ShowClientMsg(client, msg);
    }

    void tcpServerEngine_ClientDisconnected(System.Net.IPEndPoint ipe)
    {
        string msg = string.Format("{0} 下线", ipe);
        this.ShowEvent(msg);
    }

    void tcpServerEngine_ClientConnected(System.Net.IPEndPoint ipe)
    {
        string msg = string.Format("{0} 上线" ,ipe);
        this.ShowEvent(msg);
    }        

    void tcpServerEngine_ClientCountChanged(int count)
    {
        this.ShowConnectionCount(count);
    }

    private void ShowEvent(string msg)
    {
        if (this.InvokeRequired)
        {
            this.BeginInvoke(new CbDelegate<string>(this.ShowEvent), msg);
        }
        else
        {
            this.toolStripLabel_event.Text = msg;
        }
    }

    private void ShowClientMsg(IPEndPoint client, string msg)
    {
        if (this.InvokeRequired)
        {
            this.BeginInvoke(new CbDelegate<IPEndPoint,string>(this.ShowClientMsg),client, msg);
        }
        else
        {
            ListViewItem item = new ListViewItem(new string[] { DateTime.Now.ToString(), client.ToString(), msg });
            this.listView1.Items.Insert(0, item);
        }
    }

    private void ShowConnectionCount(int clientCount)
    {
        if (this.InvokeRequired)
        {
            this.BeginInvoke(new CbDelegate<int>(this.ShowConnectionCount), clientCount);
        }
        else
        {
            this.toolStripLabel_clientCount.Text = "在线数量: " + clientCount.ToString();
        }
    }

    private void comboBox1_DropDown(object sender, EventArgs e)
    {
        List<IPEndPoint> list = this.tcpServerEngine.GetClientList();
        this.comboBox1.DataSource = list;
    }

    private void button2_Click(object sender, EventArgs e)
    {
        try
        {
            IPEndPoint client = (IPEndPoint)this.comboBox1.SelectedItem;
            if (client == null)
            {
                MessageBox.Show("没有选中任何在线客户端!");
                return;
            }

            if (!this.tcpServerEngine.IsClientOnline(client))
            {
                MessageBox.Show("目标客户端不在线!");
                return;
            }

            string msg = this.textBox_msg.Text + "\0";// "\0" 表示一个消息的结尾
            byte[] bMsg = System.Text.Encoding.UTF8.GetBytes(msg);//消息使用UTF-8编码
            this.tcpServerEngine.SendMessageToClient(client, bMsg);
        }
        catch (Exception ee)
        {
            MessageBox.Show(ee.Message);
        }
    }

关于服务端引擎的使用,主要就以下几点:

(1)首先调用NetworkEngineFactory的CreateTextTcpServerEngine方法创建引擎(服务端、TCP、Text协议)。

(2)根据需要,预定引擎实例的某些事件(如MessageReceived事件)。

(3)调用引擎实例的Initialize方法启动通信引擎。

(4)调用服务端引擎的SendMessageToClient方法,发送消息给客户端。

3.Demo客户端

    private ITcpPassiveEngine tcpPassiveEngine;
    private void button3_Click(object sender, EventArgs e)
    {
        try
        {
            //初始化并启动客户端引擎(TCP、文本协议)
            this.tcpPassiveEngine = NetworkEngineFactory.CreateTextTcpPassiveEngine(this.textBox_IP.Text, int.Parse(this.textBox_port.Text), new DefaultTextContractHelper("\0"));
            this.tcpPassiveEngine.MessageReceived += new CbDelegate<System.Net.IPEndPoint, byte[]>(tcpPassiveEngine_MessageReceived);
            this.tcpPassiveEngine.AutoReconnect = true;//启动掉线自动重连
            this.tcpPassiveEngine.ConnectionInterrupted += new CbDelegate(tcpPassiveEngine_ConnectionInterrupted);
            this.tcpPassiveEngine.ConnectionRebuildSucceed += new CbDelegate(tcpPassiveEngine_ConnectionRebuildSucceed);
            this.tcpPassiveEngine.Initialize();

            this.button2.Enabled = true;
            this.button3.Enabled = false;
            MessageBox.Show("连接成功!");
        }
        catch (Exception ee)
        {
            MessageBox.Show(ee.Message);
        }
    }

    void tcpPassiveEngine_ConnectionRebuildSucceed()
    {
        if (this.InvokeRequired)
        {
            this.BeginInvoke(new CbDelegate(this.tcpPassiveEngine_ConnectionInterrupted));
        }
        else
        {
            this.button2.Enabled = true;
            MessageBox.Show("重连成功。");
        }
    }

    void tcpPassiveEngine_ConnectionInterrupted()
    {
        if (this.InvokeRequired)
        {
            this.BeginInvoke(new CbDelegate(this.tcpPassiveEngine_ConnectionInterrupted));
        }
        else
        {
            this.button2.Enabled = false;
            MessageBox.Show("您已经掉线。");
        }
    }

    void tcpPassiveEngine_MessageReceived(System.Net.IPEndPoint serverIPE, byte[] bMsg)
    {
        string msg = System.Text.Encoding.UTF8.GetString(bMsg); //消息使用UTF-8编码
        msg = msg.Substring(0, msg.Length - 1); //将结束标记"\0"剔除
        this.ShowMessage(msg);
    }       

    private void ShowMessage(string msg)
    {
        if (this.InvokeRequired)
        {
            this.BeginInvoke(new CbDelegate<string>(this.ShowMessage), msg);
        }
        else
        {
            ListViewItem item = new ListViewItem(new string[] { DateTime.Now.ToString(), msg });
            this.listView1.Items.Insert(0, item);
        }
    }

    private void button2_Click(object sender, EventArgs e)
    {
        string msg = this.textBox_msg.Text + "\0";// "\0" 表示一个消息的结尾
        byte[] bMsg = System.Text.Encoding.UTF8.GetBytes(msg);//消息使用UTF-8编码
        this.tcpPassiveEngine.SendMessageToServer(bMsg);
    }

关于客户端引擎的使用,与服务端类似:

(1)首先调用NetworkEngineFactory的CreateTextTcpPassiveEngine方法创建引擎(客户端、TCP、Text协议)。

(2)根据需要,预定引擎实例的某些事件(如MessageReceived、ConnectionInterrupted 事件)。

(3)根据需要,设置引擎实例的某些属性(如AutoReconnect属性)。

(4)调用引擎实例的Initialize方法启动通信引擎。

(5)调用客户端引擎的SendMessageToServer方法,发送消息给服务端。

4.基于Socket的客户端

这个客户端直接基于.NET的Socket进行开发,其目演示了:在客户端不使用StriveEngine的情况下(比如客户端是异构系统),如何与基于StriveEngine的服务端进行通信。该客户端只是粗糙地实现了基本目的,很多细节问题都被忽略,像粘包问题、消息重组、掉线检测等等。而这些问题在实际的应用中,是必需要处理的。(StriveEngine中的客户端和服务端引擎都内置解决了这些问题)。
该客户端的代码就不贴了,大家可以在源码中看到。

5.源码下载

   文本协议通信demo源码

 附相关系列: 二进制通信demo源码及说明文档

                        打通B/S与C/S通信demo源码与说明文档

另附:简单即时通讯Demo源码及说明

时间: 2024-10-27 19:58:03

轻量级通信引擎StriveEngine —— C/S通信demo(附源码)的相关文章

轻量级通信引擎StriveEngine —— C/S通信demo(2) —— 使用二进制协议 (附源码)

在网络上,交互的双方基于TCP或UDP进行通信,通信协议的格式通常分为两类:文本消息.二进制消息. 文本协议相对简单,通常使用一个特殊的标记符作为一个消息的结束. 二进制协议,通常是由消息头(Header)和消息体(Body)构成的,消息头的长度固定,而且,通过解析消息头,可以知道消息体的长度.如此,我们便可以从网络流中解析出一个个完整的二进制消息. 两种类型的协议格式各有优劣:文本协议直观.容易理解,但是在文本消息中很难嵌入二进制数据,比如嵌入一张图片:而二进制协议的优缺点刚刚相反. 在 轻量

【网站国际化必备】Asp.Net MVC 集成Paypal(贝宝)快速结账 支付接口 ,附源码demo

开篇先给大家讲段历史故事,博主是湖北襄阳人.襄阳物华天宝,人杰地灵,曾用名襄樊.在2800多年的历史文化中出现了一代名相诸葛亮(卧龙),三国名士庞统(凤雏),魏晋隐士司马徽(水镜先生),唐代大诗人孟浩然(孟襄阳),张继.杜审言,文学家皮日休,北宋著名书画家米芾(米襄阳),“允冠百王”的光武帝刘秀,东方圣人释道安等一大批历史文化名人.小说<三国演义>120回故事中有30多回提到襄阳. 相传诸葛亮的老婆黄月英黄头发黑皮肤,但知识广博.诸葛亮发明木牛流马,就是从黄月英的传授的技巧上发展出来.不仅如此

Android 高仿 频道管理----网易、今日头条、腾讯视频 (可以拖动的GridView)附源码DEMO

距离上次发布(android高仿系列)今日头条 --新闻阅读器 (二) 相关的内容已经半个月了,最近利用空闲时间,把今日头条客户端完善了下.完善的功能一个一个全部实现后,就放整个源码.开发的进度就是按照一个一个功能的思路走的,所以开发一个小的功能,如果有用,就写一个专门的博客以便有人用到独立的功能可以方便使用. 这次实现的功能是很多新闻阅读器(网易,今日头条,360新闻等)以及腾讯视频等里面都会出现的频道管理功能. 下面先上这次实现功能的效果图:(注:这个效果图没有拖拽的时候移动动画,DEMO里

Firefly——dbentrust 示例DEMO (源码+教程)

原地址:http://www.9miao.com/question-15-54002.html Firefly——dbentrust示例说明一.数据库准备本篇示例演示的是firefly与MySQL和memcached之间的数据处理,所以要先准备好数据库.(数据库工具使用的是SQLyogEnt)1.创建数据库 <ignore_js_op> 2.建表下面是一个简单的角色表(player) <ignore_js_op> 二.firefly与MySQL之间的交互(test_dbpool.p

通信服务器群集——跨服务器通信Demo(源码)

对于一些基于TCP Socket的大型C/S应用来说,能进行跨服务器通信可能是一个绕不开的功能性需求.出现这种需求的场景类似于下面描述的这种情况. 假设,我们一台TCP应用服务器能同时承载10000人同时在线,而同时在线用户数量通常为5万多,那可想而知,我们需要部署6台TCP应用服务器来分担这些负载.再假设,我们的应用中,任意的两个客户端都有可能需要互发消息(比如,传送文件),这时问题就来了 -- 因为要互发消息的这两个客户端连接的可能是不同的服务器. 如何解决了?这就需要引入群集平台的概念.群

Android中AIDL实现进程通信(附源码下载)

AIDL概述 之前的博客<Android中通过Messenger与Service实现进程间双向通信>演示了如何通过Messenger实现与Service进行跨进程通信,即IPC.但用Messenger实现的IPC存在一点不足:Service内部维护着一个Messenger,Messenger内部又维护着一个Hanlder,当多个client向该Service发送Message时,这些Message需要依次进入Hanlder的消息队列中,Hanlder只能处理完一个Message之后,再从消息队

开源数据引擎-介绍(附源码)

NetUML.DataEngine 数据引擎支持多数据库,数据访问引擎采用配置方式,类似ibatis.net底层原理,支持多数据库连接方式.将来可支持数据库读写分离,读写分离配置采用MVC路由机制. 源码结构 一.配置介绍 providers.config 配置文件名称,只需把它放在程序的根目录下即可. 1 <provider name="oracleManagedDataAccess" 2 description="Oracle, Microsoft provider

使用duilib开发半透明异形窗体程序(附源码和demo)

转载请说明原出处,谢谢~~:http://blog.csdn.net/zhuhongshu/article/details/43532791 半透明异形窗体的功能在之前维护的老版本的duilib里面已经有了基本的功能,但是因为一直存在较多的缺陷,所以我一直建议少用,就连我自己写仿酷狗项目也只是在几个小地方用了半透明异形窗体.不过今天在群里和其他几位朋友讨论后,发现了之前的许多问题以及解决方法.所以我立马修复了当前的库,并且写了一个半透明异形窗体的demo来测试效果.这里的半透明窗体是用Updat

单独编译和使用webrtc音频降噪模块(附源码+测试demo)

webrtc的音频处理模块分为降噪ns,回音消除aec,回声控制acem,音频增益agc,静音检测部分.另外webrtc已经封装好了一套音频处理模块APM,如果不是有特殊必要,使用者如果要用到回声消除,音频增益等较为复杂的模块时,最好使用全部的音频处理模块二不要单独编译其中一部分以免浪费宝贵的时间. 但是音频降噪部分较为简单,用起来也就几个函数,除了需要传入的音频数据以外,需要调整的参数也就是音频采样率和降噪等级.另外这部分代码采用纯C语言语法编写,可以跨平台编译.整个算法也不算特别复杂,运行起