StriveEngine-TCP
文章中的StriveEngine.dll版本为V3.9.0.0,源码下载请到 https://download.csdn.net/download/hanghangz/10966335
先上代码,建立2个控制台程序,分别为SEClient,SEServer,其中SEClient中增加一个类
class Client { private ITcpPassiveEngine tcpPassiveEngine; public Client(string ip,string port) { this.tcpPassiveEngine = NetworkEngineFactory.CreateTextTcpPassiveEngine(ip, int.Parse(port), new TextContractHelper()); } public void Start() { this.tcpPassiveEngine.MessageReceived += new CbDelegate<System.Net.IPEndPoint, byte[]>(tcpPassiveEngine_MessageReceived); this.tcpPassiveEngine.AutoReconnect = true;//启动掉线自动重连 this.tcpPassiveEngine.ConnectionInterrupted += () => { Console.WriteLine("Offline"); }; this.tcpPassiveEngine.ConnectionRebuildSucceed += () => { Console.WriteLine("Re-Collect OK"); }; this.tcpPassiveEngine.Initialize(); } public void Send(string message) { byte[] bytes = System.Text.Encoding.UTF8.GetBytes(message); this.tcpPassiveEngine.SendMessageToServer(bytes); } private void tcpPassiveEngine_MessageReceived(System.Net.IPEndPoint obj1, byte[] obj2) { string message = System.Text.Encoding.UTF8.GetString(obj2); Console.WriteLine("get message from [{0}]:{1}", obj1.ToString(), message); } }
Main函数如下
static void Main(string[] args) { Client c = "); c.Start(); while (true) { string m = Console.ReadLine(); c.Send(m); } }
在SEServer添加类
class Server { private ITcpServerEngine tcpServerEngine; public Server(int port) { this.tcpServerEngine = NetworkEngineFactory.CreateTextTcpServerEngine(port, new TextContractHelper()); } public void Start() { this.tcpServerEngine.ClientCountChanged += (a) => { Console.WriteLine("Client count: " + a.ToString()); }; this.tcpServerEngine.ClientConnected += (a) => { Console.WriteLine("Online " + a.ToString()); }; this.tcpServerEngine.ClientDisconnected += (a) => { Console.WriteLine("Offline " + a.ToString()); }; this.tcpServerEngine.MessageReceived += new CbDelegate<IPEndPoint, byte[]>(tcpServerEngine_MessageReceived); this.tcpServerEngine.Initialize(); } private void tcpServerEngine_MessageReceived(IPEndPoint obj1, byte[] obj2) { string message = System.Text.Encoding.UTF8.GetString(obj2); Console.WriteLine("get message from [{0}]:{1}", obj1.ToString(), message); this.tcpServerEngine.SendMessageToClient(obj1, obj2); } }
Main函数如下:
static void Main(string[] args) { Server s = ); s.Start(); Console.ReadKey(); }
将下面的类增加到客户端和服务端中,也可直接添加链接(不知道怎么弄?那就都添加吧):
public class TextContractHelper : ITextContractHelper { public List<byte[]> EndTokens { get { return null; } } }
然后先启动服务端,再启动客户端.在客户端输入任意字符回车,服务端将会收到,并直接将其返回客户端. 所有的连接,断线,重连,收发消息,显示客户端数量,全部搞定,惊喜不?
然后,我们来捣乱,把TextContractHelper修改了
public class TextContractHelper : ITextContractHelper { public List<byte[]> EndTokens { get { , ( } };//表示字符串"NO" return token.ToList(); } } }
然后再运行程序,在客户端输入,发现服务端收不到数据了.喔喝.怎么肥事?
查看EndTokens的解释
消息结束标识符(经过编码后得到的字节数组)的集合。 比如一般应用使用"\0"作为消息结束标志,那么,集合中只有一个元素("\0"的二进制)。 有的应用可能有多个标识符(如"\0"、"\n"及其它)都可以作为消息的结束标志,则集合中就有多个元素。 如果设置为null,引擎则不进行消息完整性识别及构造,每次接收到数据,就直接触发MessageReceived事件。
所以,在客户端输入结尾输入NO,在回车,就能收到信息了.还可以输入多行,在最后才输入NO,所有的输入将会作为一条消息.
上面的代码中用的CreateTextTcpPassiveEngine和CreateTextTcpServerEngine来获得tcpServerEngine,它还有另外一组方法CreateStreamTcpServerEngine和CreateStreamTcpPassivEngine,而后面的参数是IStreamContractHelper.
区别:
- Text:创建使用文本协议的TCP服务端和客户端
- Stream: 创建使用二进制协议的TCP服务端和客户端
还是来试一下.这里先定义一个报文的格式
- Head:长度4,第一位表示头(0xFF),其中第二个表示报文body的长度,第三位表示功能(0x01=功能1,0x02=功能2),第四位备用
- Body:一个字符串
报文构造类:
class Message { public byte[] Head; public byte[] Body; public Message(byte func, string body) { Body = System.Text.Encoding.UTF8.GetBytes(body); Head = ]; Head[] = 0xff; Head[] = (byte)Body.Length; Head[] = func; Head[] = 0x00; } public byte[] ToBytes() { List<byte> list = new List<byte>(); list.AddRange(Head); list.AddRange(Body); return list.ToArray(); } }
报文解析类:
ublic class StreamContractHelper : IStreamContractHelper { public int MessageHeaderLength//长度为4 { ; } } public int ParseMessageBodyLength(byte[] head)// { ] ,,,};//head中第二位表示body的长度,添加3个字节,转换为int ); } }
服务端中:
this.tcpServerEngine = NetworkEngineFactory.CreateStreamTcpServerEngine(port, new StreamContractHelper());
客户端中:
this.tcpPassiveEngine = NetworkEngineFactory.CreateStreamTcpPassivEngine(ip, int.Parse(port), new StreamContractHelper());
客户端的Send方法修改
public void Send(string message) { Message msg = new Message((byte)0x01, message); this.tcpPassiveEngine.SendMessageToServer(msg.ToBytes()); }
服务端中收到消息处理的解析:
private void tcpServerEngine_MessageReceived(IPEndPoint obj1, byte[] obj2) { //string message = System.Text.Encoding.UTF8.GetString(obj2); //Console.WriteLine("get message from [{0}]:{1}", obj1.ToString(), message); //this.tcpServerEngine.SendMessageToClient(obj1, obj2); , obj2.Length - ); Console.WriteLine(message); }
运行后,又可以收服务端的消息了.非常NICE.
需要注意的问题:
- 以上测试都是发送比较短的消息,在发送很长的文本或二进制的时候,可能会自动分开,或者接收到不完整的消息的情况出现.
- 可以设置MaxMessageSize的值来发送较长的消息,但是我在用CreateStreamTcpServerEngine的时候,太长的消息始终收不完整,并且发送过来的消息是一段一段的,具体问题,没有研究出来,不知是庫的bug,还是我的bug,望高人指点.
- 长的消息需要重新定义报文格式,分开发送,接收后,根据报文信息重新组装.
- 总之,发送短小消息,可以用.
需要注意的问题2:
- 上面说到收到消息不完整,是我在定义报文的时候,将表示body长度只用了一个字节来表示,所以造成解析不对
- 自己的bug,还是要自己搞定
Message的构造函数修改为如下,就是长度用int,4个字节来表示
public Message(byte func, string body) { Body = System.Text.Encoding.UTF8.GetBytes(body); Head = ]; Head[] = 0xff; byte[] len = BitConverter.GetBytes(body.Length); Head[] = len[]; Head[] = len[]; Head[] = len[]; Head[] = len[]; Head[] = func; Head[] = 0x00; }
同时,StreamContractHelper修改为如下
public class StreamContractHelper : IStreamContractHelper { public int MessageHeaderLength { ; }//head长度为7了 } public int ParseMessageBodyLength(byte[] head) { );//head[1,2,3,4]4个字节表示body的LEN,由于是TOINT32,方法自己从1开始,取4个字节来转换 return l; } }
StriveEngine-TCP的更多相关文章
- 轻量级通信引擎StriveEngine —— C/S通信demo(附源码)
前段时间,有几个研究ESFramework的朋友对我说,ESFramework有点庞大,对于他们目前的项目来说有点“杀鸡用牛刀”的意思,因为他们的项目不需要文件传送.不需要P2P.不存在好友关系.也不 ...
- 轻量级通信引擎StriveEngine —— C/S通信demo(2) —— 使用二进制协议 (附源码)
在网络上,交互的双方基于TCP或UDP进行通信,通信协议的格式通常分为两类:文本消息.二进制消息. 文本协议相对简单,通常使用一个特殊的标记符作为一个消息的结束. 二进制协议,通常是由消息头(Head ...
- 轻量级C#网络通信组件StriveEngine —— C/S通信开源demo(附源码)
前段时间,有几个研究ESFramework网络通讯框架的朋友对我说,ESFramework有点庞大,对于他们目前的项目来说有点“杀鸡用牛刀”的意思,因为他们的项目不需要文件传送.不需要P2P.不存在好 ...
- C#轻量级通通讯组件StriveEngine —— C/S通信开源demo(2) —— 使用二进制协议 (附源码)
前段时间,有几个研究ESFramework通信框架的朋友对我说,ESFramework有点庞大,对于他们目前的项目来说有点“杀鸡用牛刀”的意思,因为他们的项目不需要文件传送.不需要P2P.不存在好友关 ...
- Tcp/ip 报文解析
在编写网络程序时,常使用TCP协议.那么一个tcp包到底由哪些东西构成的呢?其实一个TCP包,首先需要通过IP协议承载,而IP报文,又需要通过以太网传送.下面我们来看看几种协议头的构成 一 .Ethe ...
- C#高性能TCP服务的多种实现方式
哎~~ 想想大部分园友应该对 "高性能" 字样更感兴趣,为了吸引眼球所以标题中一定要突出,其实我更喜欢的标题是<猴赛雷,C#编写TCP服务的花样姿势!>. 本篇文章的主 ...
- Android实现TCP断点上传,后台C#服务实现接收
终端实现大文件上传一直都是比较难的技术,其中涉及到后端与前端的交互,稳定性和流量大小,而且实现原理每个人都有自己的想法,后端主流用的比较多的是Http来实现,因为大多实现过断点下载.但稳定性不能保证, ...
- 漫谈TCP
不得不承认,tcp是一个非常复杂的协议.它包含了RFC793及之后的一些协议.能把tcp的所有方面面面具到地说清楚,本身就是个很复杂的事情.如果再讲得枯燥,那么就会更让人昏昏欲睡了.本文希望能尽量用稍 ...
- 高性能 TCP/UDP/HTTP 通信框架 HP-Socket v4.1.1
HP-Socket 是一套通用的高性能 TCP/UDP/HTTP 通信框架,包含服务端组件.客户端组件和 Agent 组件,广泛适用于各种不同应用场景的 TCP/UDP/HTTP 通信系统,提供 C/ ...
- TCP/IP基础
TCP/IP 是用于因特网 (Internet) 的通信协议. 计算机通信协议是对那些计算机必须遵守以便彼此通信的规则的描述. 什么是 TCP/IP? TCP/IP 是供已连接因特网的计算机进行通信的 ...
随机推荐
- sqlalchemy根据数据库结构生成映射的实体
# !/usr/bin/python # -*- coding: UTF-8 -*- from sqlalchemy import * from sqlalchemy.orm import sessi ...
- JS Async Callback
AsyncCallback 意义: 异步操作完成时调用的方法 语法1: 构造异步回调对象 AsyncCallback 异步回调对象名asyncCallback = new AsyncCallback( ...
- The Django Book(自定义ModelAdmi类)
默认的,管理界面下显示的东西只是 python2:def __unicode__(self): 和 python3:def __str__(self): 中返回的字段内容 想要让它更加的多元化的话 c ...
- 2019.01.22 bzoj2874: 训练士兵(主席树)
传送门 题意简述:给出一个n∗mn*mn∗m的矩阵n,m≤1e8n,m\le1e8n,m≤1e8,支持矩形加,矩形求和,强制在线. 思路:第一眼二维动态开点线段树,上网去搜有没有这种做法发现会被卡时空 ...
- android studio友盟分享demo运行报错Gradle's dependency cache may be corrupt解决方法
gradle-wrapper.properties里修改了gradle的版本,与之前没有报错的项目gradle版本一致.
- etf基金和lof基金区别
①,含义不同.etf即交易指数开放基金,是跟踪某一指数的可以在交易所上市的开放式基金.lof基金是上市向开放基金,是中国首创的一种基金类型,也是etf基金的中国化.②,申购赎回的场所不同.etf和lo ...
- 二级缓存EhCache在几种应用技术的配置方法和步骤总结
一:Spring和Ehcache缓存集成 业务问题:如果仓库不经常变动,大量进出库,总是需要查询仓库列表 (列表重复) ,使用缓存优化 ! 阅读spring规范29章节 第一步: 导入ehcache的 ...
- 【慕课网实战】Spark Streaming实时流处理项目实战笔记一之铭文升级版
第一章:课程介绍 铭文一级: VMware Fusion Mac上搭建:为了给大家演示如何使用我们的OOTB环境 Hadoop环境:虚拟机,我是远程登录 Mac 那么就不需要使用我们的OOTB环境 V ...
- 利用nginx打造个人简历网页
1.下载nginx nginx官方网址:http://nginx.org/ 2.下载和解压 #下载:[root@iZwz9cl4i8oy1reej7o8pmZ soft]# wget http://n ...
- Java案例:随机点名器
案例介绍: 随机点名器,即在全班同学中随机的找出一名同学,打印这名同学的个人信息.需具备以下3个内容:1)存储所有同学姓名2)总览全班同学姓名3)随机点名其中一人,打印到控制台 案例需求分析: 全班同 ...