协议处理类的实现


和上面一章一样,在开始编写实际的服务端客户端代码之前,我们首先要编写处理协议的类,它需要提供这样两个功能:1、方便地帮 我们获取完整的协议信 息,因为前面我们说过,服务端可能将客户端的多次独立请求拆分或合并。比如,客户端连续发送了两条控制 信息到服务端,而服务端将它们合并了,那么则需要先 拆开再分别处理。2、方便地获取我们所想要的属性信息,因为协议是 XML 格 式,所以还需要一个类专门对 XML 进行处理,获得字符串的属性值。

1. ProtocalHandler 辅助类

我们先看下 ProtocalHandler,它与上一篇中的 RequestHandler 作用相同。需要注意的是必须将它声明为实例的,而非静态 的,这是 因为每个 TcpClient 都需要对应一个 ProtocalHandler,因为它内部维护的 patialProtocal 不能共享,在协议发送 不完整的情况下,这个 变量用于临时保存被截断的字符串。

public class ProtocolHandler { 
 private string partialProtocal; // 保存不完整的协议
 
 public ProtocolHandler() { 
 partialProtocal = ""; 
 } 
 public string[] GetProtocol(string input) { 
 return GetProtocol(input, null); 
 } 
 
 // 获得协议
 private string[] GetProtocol(string input, List<string> outputList) { 
 if (outputList == null) 
 outputList = new List<string>(); 
 if (String.IsNullOrEmpty(input)) 
 return outputList.ToArray(); 
 if (!String.IsNullOrEmpty(partialProtocal)) 
 input = partialProtocal + input; 
 string pattern = "(^<protocol>.*?</protocol>)"; 
 // 如果有匹配,说明已经找到了,是完整的协议
 if (Regex.IsMatch(input, pattern)) { 
 // 获取匹配的值
 string match = Regex.Match(input, pattern).Groups[0].Value; 
 outputList.Add(match); 
 partialProtocal = ""; 
 // 缩短 input 的长度
 input = input.Substring(match.Length); 
 // 递归调用
 GetProtocol(input, outputList); 
 } else { 
 // 如果不匹配,说明协议的长度不够,
 // 那么先缓存,然后等待下一次请求
 partialProtocal = input; 
 } 
 return outputList.ToArray(); 
 } 
} 

因为现在它已经不是本文的重点了,所以我就不演示对于它的测试了,本文所附带的代码中含有它的测试代码(我在 ProtocolHandler 中添加了一个静态类 Test())。

2. FileRequestType 枚举和 FileProtocol 结构

因为 XML 是以字符串的形式在进行传输,为了方便使用,我们最好构建一个强类型来对它们进行操作,这样会方便很多。我们首先可 以定义 FileRequestMode 枚举,它代表是发送还是接收文件:

public enum FileRequestMode { 
 Send = 0, 
 Receive 
}

接下来我们再定义一个 FileProtocol 结构,用来为整个协议字符串提供强类型的访问,注意这里覆盖了基类的 ToString()方法,这样在 客户端我们就不需要再手工去编写 XML,只要在结构值上调用 ToString()就 OK 了,会方便很多。

public struct FileProtocol { 
 private readonly FileRequestMode mode; 
 private readonly int port; 
 private readonly string fileName; 
 public FileProtocol 
 (FileRequestMode mode, int port, string fileName) { 
 this.mode = mode; 
 this.port = port; 
 this.fileName = fileName; 
 } 
 public FileRequestMode Mode { 
 get { return mode; } 
 } 
 public int Port { 
 get { return port; } 
 } 
 public string FileName { 
 get { return fileName; } 
 } 
 public override string ToString() { 
 return String.Format("<protocol><file name=\"{0}\" mode=\"{1}\" port=\"{2}\" /></protocol>", fileName, mode, port); 
 } 
} 

3. ProtocolHelper 辅助类

这个类专用于将 XML 格式的协议映射为我们上面定义的强类型对象,这里我没有加入 try/catch 异常处理,因为协议对用户来说是不可 见的,而且客户端应该总是发送正确的协议,我觉得这样可以让代码更加清晰:

public class ProtocolHelper { 
 private XmlNode fileNode; 
 private XmlNode root; 
 
 public ProtocolHelper(string protocol) { 
 XmlDocument doc = new XmlDocument(); 
 doc.LoadXml(protocol); 
 root = doc.DocumentElement; 
 fileNode = root.SelectSingleNode("file"); 
 } 
 // 此时的 protocal 一定为单条完整 protocal 
 private FileRequestMode GetFileMode() { 
 string mode = fileNode.Attributes["mode"].Value; 
 mode = mode.ToLower(); 
 if (mode == "send") 
 return FileRequestMode.Send; 
 else
 return FileRequestMode.Receive; 
 } 
 // 获取单条协议包含的信息
 public FileProtocol GetProtocol() { 
 FileRequestMode mode = GetFileMode(); 
 string fileName = ""; 
 int port = 0; 
 fileName = fileNode.Attributes["name"].Value; 
 port = Convert.ToInt32(fileNode.Attributes["port"].Value); 
 return new FileProtocol(mode, port, fileName); 
 } 
}

OK,我们又耽误了点时间,下面就让我们进入正题吧。

 

 

版权声明:本文为YES开发框架网发布内容,转载请附上原文出处连接
张国生
上一篇:订立协议
评论列表

发表评论

评论内容
昵称:
关联文章

协议处理实现
C#图片处理:ImageLibrary
1.面向连接传输协议:TCP
订立协议
C#获得类型Type实现接口列表,支持排除基实现接口
使用.NET 6开发TodoList应用(8)——实现全局异常处理
在Winform框架多文档界面中实现双击子窗口单独弹出或拖出及拽回处理
ABP VNext框架中Winform终端开发和客户端授权信息处理
在ABP VNext框架中对HttpApi模块控制器进行基封装
Blazor Webassembly多标签页实现非iframe实现
客户端实现
01、收款播报机通用版本网络协议
[WPF] 实现 WPF Inner Shadow
服务端实现
基于欧姆龙PLC#FinsTcp协议上位机通讯(一)-PLC配置
使用.NET 6开发TodoList应用(26)——实现Configuration和Option强类型绑定
查询参数:SQLServer
使用.NET 6开发TodoList应用(24)——实现基于JWTIdentity功能
基于欧姆龙PLC#FinsTcp协议上位机通讯(二)-C#通讯模块开发
ManualResetEvent实现线程暂停与恢复