需求:1) 從可能合併/拆分的資料流中擷取完整協議;2) 從 XML 協議解析屬性值。
與上一篇 RequestHandler 同理。必須為實例欄位,因每個 TcpClient 需獨立 partialProtocol 緩存不完整片段:
public class ProtocolHandler {
private string partialProtocol = "";
public ProtocolHandler() { partialProtocol = ""; }
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(partialProtocol)) input = partialProtocol + input;
string pattern = "(^<protocol>.*?</protocol>)";
if (Regex.IsMatch(input, pattern)) {
string match = Regex.Match(input, pattern).Groups[0].Value;
outputList.Add(match);
partialProtocol = "";
input = input.Substring(match.Length);
GetProtocol(input, outputList); // 遞迴處理剩餘
} else {
partialProtocol = input; // 協議不完整,緩存等待下次
}
return outputList.ToArray();
}
}
測試程式碼包含於附件原始碼中(ProtocolHandler 內含靜態 Test())。
專責將 XML 協議映射為 FileProtocol 物件。協議對用戶不可見且客戶端應保證正確,故省略 try/catch 以保持程式碼清晰:
public class ProtocolHelper {
private XmlNode fileNode, root;
public ProtocolHelper(string protocol) {
XmlDocument doc = new XmlDocument();
doc.LoadXml(protocol);
root = doc.DocumentElement;
fileNode = root.SelectSingleNode("file");
}
private FileRequestMode GetFileMode() {
string mode = fileNode.Attributes["mode"].Value.ToLower();
return (mode == "send") ? FileRequestMode.Send : FileRequestMode.Receive;
}
public FileProtocol GetProtocol() {
FileRequestMode mode = GetFileMode();
string fileName = fileNode.Attributes["name"].Value;
int port = Convert.ToInt32(fileNode.Attributes["port"].Value);
return new FileProtocol(mode, port, fileName);
}
}