目录

一、定义消息格式

二、建立一个TCP客户端

三、SuperSocket作为服务端

1、新建控制台程序SuperSocketServer        ​

2、使用nuget工具安装SuperSocket和SuperSocket.Engine库

3、实现3个类: Filter、Session和Server

4、Main函数关键代码:


前几个月有个项目需要和其他设备通信,需要用到TCP和UDP通信.本来开始也是用的C#原生态socket通信库,但是后来发现了一个”我不想说他名字坑爹库”,经过测试,用起来还挺顺手,就直接把这个”我不想说他名字坑爹库”引入了项目中。还把使用方法写在了博客园,测试demo还上传了代码(通讯库并没有源码,只有dll文件)。

结果,大约三个月后,有人给我留言,说他下载了”我不想说他名字坑爹库”的demo源码,并且引入了项目中,但是要收费,已经过期,他们的项目已经挂了。开始我还不信(当时我在出差,其实我自己项目中的这个坑爹库也过期了),一直以为”我不想说他名字坑爹库”是免费的,是他们项目中的其他库出问题了,后来发现,这个库确实要收费的,并且还价格不菲,我简直*****了。

幸好我们的项目还没上线,不然真的要死翘翘了,丢人要丢到外国去了。不过下载我源码的兄弟就真的对不起了,我在这里真诚的为你们感到sorry。

后来嘛,就只能换噻,好在代码框架还行,通信和业务耦合度很低,换通信框架很容易。在这个开源大行其道的世界,遇到收费的库,我也是无语。再后来,就找到SuperSocket了,开源的,老板再也不担心软件过期了。

这篇文章就不介绍SuperSocket的其他东西了,只写FixedHeaderReceiveFilter通信例子。

需求:一个TCP服务端,多个TCP客户端,客户端可向服务端发送消息,服务端向连接的每个客户端广播消息。

一、定义消息格式

要发送的消息格式直接给出来:

Public class SuperSocketMessage{public byte[] Start;//4个字节public ushort Type;//2个字节, 1表示文字消息,2表示图片消息,其他表示未知,不能解析public int Len;//4个字节public string Message;//文本信息public byte[] Tail;//消息结尾public SuperSocketMessage(){Start = new byte[] { 0xFF, 0xFF, 0xFF, 0xFF };Tail = new byte[] { 0x1F, 0x1F, 0x1F, 0x1F };}public byte[] ToBytes(){List<byte> list = new List<byte>();list.AddRange(Start);var t = BitConverter.GetBytes(Type);list.AddRange(t);var t3 = System.Text.Encoding.UTF8.GetBytes(Message);var t2 = BitConverter.GetBytes(t3.Length);//注意,这里不是Message.Length,而是Message转化成字节数组后的Lenghtlist.AddRange(t2);list.AddRange(t3);return list.ToArray();}
}

请记住以下几个数字或信息:

  1. 消息头部包含三个元素:开始、类型和消息body的长度
  2. 从第六个字节开始表示长度
  3. 表示长度字节数是4个字节
  4. Body的长度不要搞混,不是Message的字符串长度,而是Message转换字节数组后的长度,调试的时候,开始用了Message的字符串长度,给我造成了几个小时的浪费。
  5. 以上信息请和下面的MyReceiveFilter类中的参数对照看。

二、建立一个TCP客户端

1、新建一个控制台程序TcpClientTest,这里为了测试的客观性,直接使用C#的TcpClient作为客户端。

2、添加Class: MyTcpClient.cs

class MyTcpClient{private System.Net.Sockets.TcpClient tcpClient;public MyTcpClient(string ip, int port){tcpClient = new System.Net.Sockets.TcpClient(ip, port);byte[] recData = new byte[1024];Action a = new Action(() =>{while (true){tcpClient.Client.Receive(recData);var msg = System.Text.Encoding.UTF8.GetString(recData);Console.WriteLine(msg);}});a.BeginInvoke(null, null);}public void Send(string message){var data = System.Text.Encoding.UTF8.GetBytes(message);tcpClient.Client.Send(data);}public void Send(byte[] message){tcpClient.Client.Send(message);}
}

3、Main函数:

static void Main(string[] args){MyTcpClient c = new MyTcpClient("127.0.0.1", 2020);SuperSocketMessage.SSMessage msg = new SuperSocketMessage.SSMessage();while (true){string m = Console.ReadLine();msg.Type = 1;msg.Message = m;c.Send(msg.ToBytes());}}

客户端实现控制台输入任意字符串后,封装成消息报文,发给服务端;同时,开启一个线程,接收服务端的消息,这里客服端就没有按照标准来解析了,直接定义缓冲区1024。

其实客户端最好用TCP/UDP测试工具软件SocketTool.exe模拟客户端。

三、SuperSocket作为服务端

1、新建控制台程序SuperSocketServer       

2、使用nuget工具安装SuperSocket和SuperSocket.Engine库

3、实现3个类: Filter、Session和Server

Filter类如下:

public class MyReceiveFilter : FixedHeaderReceiveFilter<BinaryRequestInfo>{public MyReceiveFilter(): base(10)//消息头部长度{        }/// <summary>////// </summary>/// <param name="header">*byte[] header * 缓存的数据,这个并不是单纯只包含协议头的数据,有时候tcp协议长度为409600,很多</param>/// <param name="offset">头部数据从 缓存的数据 中开始的索引,一般为0.(tcp协议有可能从405504之类的一个很大数据开始)</param>/// <param name="length">这个length和base(10)中的参数相等</param>/// <returns></returns>protected override int GetBodyLengthFromHeader(byte[] header, int offset, int length){return GetBodyLengthFromHeader(header, offset, length, 6, 4);//6表示第几个字节开始表示长度.4:由于是int来表示长度,int占用4个字节}protected override BinaryRequestInfo ResolveRequestInfo(ArraySegment<byte> header, byte[] bodyBuffer, int offset, int length){byte[] body = new byte[length];Array.Copy(bodyBuffer, offset, body, 0, length);Int16 type = BitConverter.ToInt16(header.ToArray(), 4);BinaryRequestInfo r = new BinaryRequestInfo(type.ToString(), body);return r;//以下的代码,不解析body,全部返给上一层//byte[] h = header.ToArray();//byte[] full = new byte[h.Count()+length];//Array.Copy(h, full, h.Count());//Array.Copy(body, 0, full, h.Count(), body.Length );//BinaryRequestInfo r = new BinaryRequestInfo("",full);//return r;}/// <summary>////// </summary>/// <param name="header">需要解析的数据</param>/// <param name="offset">头部数据从header中开始的索引,一般为0,也可能不是0</param>/// <param name="length">这个length和base(10)中的参数相等</param>/// <param name="lenStartIndex">表示长度的字节从第几个开始</param>/// <param name="lenBytesCount">几个字节来表示长度:4个字节=int,2个字节=int16,1个字节=byte</param>/// <returns></returns>private int GetBodyLengthFromHeader(byte[] header, int offset, int length, int lenStartIndex, int lenBytesCount){var headerData = new byte[lenBytesCount];Array.Copy(header, offset + lenStartIndex, headerData, 0, lenBytesCount);//if (lenBytesCount == 1){int i = headerData[0];return i;}else if (lenBytesCount == 2){int i = BitConverter.ToInt16(headerData, 0);return i;}else //  if (lenBytesCount == 4){int i = BitConverter.ToInt32(headerData, 0);return i;}}
}

Server和Session类如下:

public class MyServer : AppServer<MySession, BinaryRequestInfo>{public MyServer(): base(new DefaultReceiveFilterFactory<MyReceiveFilter, BinaryRequestInfo>()) //使用默认的接受过滤器工厂 (DefaultReceiveFilterFactory){}}public class MySession : AppSession<MySession, BinaryRequestInfo>{}

BinaryRequestInfo实现了 IRequestInfo接口,这个接口就一个key,貌似SuperSocket的所有数据都是实现这个接口

4、Main函数关键代码:

配置:

MyServer appServer = new MyServer();var se = new SuperSocket.SocketBase.Config.ServerConfig();se.TextEncoding = "Unicode";// System.Text.Encoding.se.TextEncoding = "gbk";// System.Text.Encoding.se.Ip = "127.0.0.1";se.Port = 2020;se.Mode = SocketMode.Tcp;

注册,启动:

if (!appServer.Setup(se)) //Setup with listening port{Console.WriteLine("Failed to setup!");Console.ReadKey();return;}Console.WriteLine();//Try to start the appServerif (!appServer.Start()){Console.WriteLine("Failed to start!");Console.ReadKey();return;}

注册事件:

appServer.NewSessionConnected += appServer_NewSessionConnected;
appServer.SessionClosed += appServer_SessionClosed;
appServer.NewRequestReceived += XXXXXXXXXXXXXXXXXXX

解析方法:

static void appServer_NewRequestReceived(MySession session, BinaryRequestInfo requestInfo){string key = requestInfo.Key;switch (key){case "1":Console.WriteLine("Get message from " + session.RemoteEndPoint.ToString() + ":" + System.Text.Encoding.UTF8.GetString(requestInfo.Body));break;case "2":Console.WriteLine("Get image");break;default:Console.WriteLine("Get unknown message.");break;}}

好,完成.截图如下:

附源码下载地址:https://download.csdn.net/download/hanghangz/11236794

项目中用nuget下载packages中的内容没有上传,文件太大了,自己去nuget吧.

使用SuperSocket的FixedHeaderReceiveFilter进行通信 - 瘦馬 - 博客园 (cnblogs.com)

SuperSocket实战---使用SuperSocket的FixedHeaderReceiveFilter进行通信相关推荐

  1. Android开发实战《手机安全卫士》——8.“通信卫士”模块实现 JUnit测试 ListView优化

    文章目录 1.高级工具--去电归属地显示 2.通信卫士--黑名单布局编写 3.通信卫士--黑名单数据库 4.通信卫士--黑名单CRUD功能实现 5.通信卫士--JUnit测试 6.通信卫士--黑名单号 ...

  2. SpringBoot实战(十一)之与JMS简单通信

    什么是JMS? 引用百度百科上的说明: JMS即Java消息服务(Java Message Service)应用程序接口,是一个Java平台中关于面向消息中间件(MOM)的API,用于在两个应用程序之 ...

  3. C# SuperSocket 手把手教你入门 傻瓜教程---1(服务器单向接收客户端发送数据)

    C# SuperSocket 手把手教你入门 傻瓜教程系列教程 C# SuperSocket 手把手教你入门 傻瓜教程---1(服务器单向接收客户端发送数据) C# SuperSocket 手把手教你 ...

  4. SuperSocket 服务管理器 (ServerManager)

    SuperSocket SuperSocket 服务管理器 (ServerManager) 中文(中国)Toggle Dropdown 关键字: ServerManager, 服务管理器, 管理, 管 ...

  5. [SSCore] 开源dotnet core 版本 SuperSocket

    前言碎语 最近一直在做旧版本dotnet 程序迁移至dotnet core的工作, 非常欣慰dotnet社区的蓬勃发展, 目前大部分的第三方类库或开源代码都有了dotnet core版本 或者可以方便 ...

  6. 基于SuperSocket的IIS主动推送消息给android客户端

    在上一篇文章<基于mina框架的GPS设备与服务器之间的交互>中,提到之前一直使用superwebsocket框架做为IIS和APP通信的媒介,经常出现无法通信的问题,必须一天几次的手动回 ...

  7. supersocket中quickstart文件夹下的MultipleCommandAssembly的配置文件分析

    首先确认下配置文件中的内容 第一部分configSections[需要注意的是name=superSocket] <configSections><section name=&quo ...

  8. SuperSocket入门(二)- 探索AppServer、AppSession,Conmmand和App.config

    在上一篇文章中,我们已经了解到了如何在SuperSocket处理客户端请求. 同时我们可能会发现一个问题,如果我们的服务器端包含有很多复杂的业务逻辑,这样的switch/case代码将会很长而且非常难 ...

  9. SuperSocket 1.5 Documentation译文 ------- 目录索引

    1:一个Telnet示例 2:实现你的AppServer和AppSession 3:通过配置启动SuperSocket 4:SuperSocket的基本配置 5:内置的命令行协议 6:使用IReque ...

最新文章

  1. [机器学习] 训练集(train set) 验证集(validation set) 测试集(test set)
  2. java web 耗时请求_javaweb应用中出现了一个耗时异常长的数据查询,寻求帮助
  3. LeetCode MySQL 1179. 重新格式化部门表
  4. 支付宝和微信的JSSDK发起支付
  5. 【转】Elasticsearch+Django搜索引擎(一)
  6. python文件传输模块_Python socket模块ftp传输文件过程解析
  7. windows7:“创建系统修复光盘”
  8. wpsa3版面怎么变成a4、排版不变_worda3变a4排版打印 word如何将a3排版成a4
  9. 制作钓鱼网站(克隆网站)
  10. git服务器ip变更后的配置
  11. ReiBoot(iOS系统修复工具)v6.9.5.0官方版
  12. js发布订阅原理,代码解析
  13. J版 OpenStack动态加载菜单图片详解
  14. Retinanet网络与focal loss损失
  15. 获取树结构JAVA代码设计
  16. Vitis 加速环境简介
  17. Spring Integration
  18. matlab函数:度分秒转换为度、度分秒转弧度、弧度转度
  19. android仿简书编辑器,类似zine,简书的app移动编辑器-Light Seven
  20. chrome extension 普通网页与插件直接通信

热门文章

  1. React hooks - Ref 使用实例
  2. Linux:共享内存
  3. Mac Xnip 截图软件快捷键设置
  4. 京东2017年4月7日笔试编程原题解析(站队、终结者C)
  5. CHARINDEX函数
  6. html/css--flex布局
  7. 复选框 html 操作,HTML页面中复选框的操作方法
  8. c数组(结构体数组)定义与初始化
  9. Mysql主从复制的三种同步方式和半同步复制配置
  10. MySQL 基础 -- MySQL 数据类型说明(数值类型、字符串类型、日期时间类型)、SQL通用语法和SQL分类