闲谈一下,最近和客户进行对接Scoket 本地的程序作为请求方以及接受方,对接Scoket 的难度实在比较大,因为涉及到响应方返回的报文的不一致性,对于返回的报文的格式我需要做反序列化的难度增大了不少,下面我就谈谈如果基于进行对接Scoket API 的接口的。方便大家,节省时间,少走弯路。大大的提高自己的开发的效率,当然我介绍的只是基于.NET Scoket API 的应用。
一.Scoket 的简介以及和WebServices WCF的区别
1.网络上经常通过程序进行双方的通信,但是在这个过程中,需要进行数据的交换。那么在这个过程中,需要进行建立网络的通讯。
2.通过请求方发出一段报文,给响应方,进行接收,并返回请求报文的结果。
3.所以基于Socket本质是编程接口(API),对TCP/IP的封装,TCP/IP也要提供可供程序员做网络开发所用的接口(经过3次握手),这个就是所谓的Socket编程接口。
4.基于Scoket API 的编程的接口 与WebServices 以及 WebAPI不同的后者都是基于HTTP请求的,但是WCF整合了原有的windows通讯的 .NET Remoting,WebService,Socket的机制,并融合有HTTP 和FTP 的相关技术。进行面向数据通信的程序框架。
5.Socket是面向客户以及服务器模型而设计。
二:Scoket 的综合的应用
1.Scoket流程图
2.首先请求方进行发送一段报文。

1 <?xml version="1.0" encoding="GBK"?>
2 <Service>
3 <Service_Header>
4 <requester_id></requester_id>
5 <branch_id ></branch_id>
6 <service_time></service_time>
7 <version_id></version_id>
8 </Service_Header>
9 <Service_Body>
10 <request>
11 <channel_type></channel_type>
12 <cert_type></cert_type>
13 <cert_no></cert_no>
14 <query_type></query_type>
15 <fr_id></fr_id>
16 <pos_id></pos_id>
17 <shop_id></shop_id>
18 </request>
19 </Service_Body>
20 </Service>
3.响应方返回的报文的格式

<?xml version=\"1.0\" encoding=\"UTF-8\"?>
<Service>
<Service_Header>
<reply_qmgr>FT1_IN01</reply_qmgr>
<service_response>
<code>0000</code>
<desc>成功</desc>
<status>COMPLETE</status>
</service_response>
<msglog></msglog>
<timeout>150</timeout>
<name>积分查询</name>
<start_time>1466155364977</start_time>
<start_timestamp>2016-06-17 17:22:44.976</start_timestamp>
<service_id>05170000000001</service_id>
<requester_id>0324</requester_id>
<branch_id>1</branch_id>
<service_time>20160617</service_time>
<version_id>001</version_id>
<trace_msg>Reply to responseQ - IBM.SERVICE.RESPONSE.OUT.AFA: FT1_IN01</trace_msg>
<end_timestamp>2016-06-17 09:22:45.327</end_timestamp>
</Service_Header>
<Service_Body>
<request>
<channel_type>01</channel_type>
<card_num>6224520110000004232</card_num>
<mobie_phone></mobie_phone>
<pos_id></pos_id>
<shop_id></shop_id>
</request>
<response>
<result_code>0000</result_code>
<result_info>成功</result_info>
<ims_serial_no/>
<total_num>101.0</total_num>
<score_num>101.0</score_num>
<freeze_num>0.0</freeze_num>
</response>
</Service_Body>
</Service>
三.通过序列化以及反序列化进行解析报文
1.响应的报文的序列化类

1 [Serializable] 2 public class ScoreDetailResponse : ApiResponse 3 { 4 /// <summary>
5 /// 结果代码 6 /// </summary>
7 public string result_code { get;set; } 8
9 /// <summary>
10 /// 结果说明 11 /// </summary>
12 public string result_info { get;set; } 13
14 /// <summary>
15 /// 交易日期 16 /// </summary>
17 public string tran_date { get;set; } 18
19 /// <summary>
20 /// 交易时间 21 /// </summary>
22 public string tran_timestamp { get;set; } 23
24 /// <summary>
25 ///交易积分数 26 /// </summary>
27 public string transfer_score { get;set; } 28
29 /// <summary>
30 /// 剩余积分数 31 /// </summary>
32 public string surplus_score { get;set; } 33
34 /// <summary>
35 /// 备注 36 /// </summary>
37 public string remark { get;set; } 38
39
40 } 41 [Serializable] 42 [XmlRoot("Service")] 43 public class MyScoreDetailResponse 44 { 45 public List<ScoreDetailResponse> _ScoreDetailResponse = new List<ScoreDetailResponse>(); 46 [XmlArray("Service_Body")] 47 [XmlArrayItem("response")] 48 public List<ScoreDetailResponse> ScoreDetailResponse { get;set; } 49 }
2.序列化继承的接口和方法

1 [XmlRoot("Service")] 2 public class ApiResponse 3 { 4 [XmlElement("errCode")] 5 public string ErrCode; 6
7 [XmlElement("errMsg")] 8 public string ErrMsg; 9
10 public string Body { get; set; } 11 } 12
13
14 [XmlRoot("IFReturn")] 15 public class IApiRequest { } 16 [XmlRoot("IFReturn")] 17 public class ApiRequest<T> : IApiRequest where T : ApiResponse 18 { 19 [XmlElement("channel_type")] 20 public string channel_type { get; set; } 21
22 [XmlElement("shop_id")] 23 public string shop_id { get; set; } 24
25 [XmlElement("post_id")] 26 public string post_id { get; set; } 27 } 28
29
30 public interface IParser 31 { 32 /// <summary>
33 /// 把响应字符串解释成相应的领域对象。 34 /// </summary>
35 /// <typeparam name="T">领域对象</typeparam>
36 /// <param name="body">响应字符串</param>
37 /// <returns>领域对象</returns>
38 T XMLParse<T>(string body) where T : ApiResponse; 39
40 /// <summary>
41 /// 将对象转换为XML 42 /// </summary>
43 /// <typeparam name="T"></typeparam>
44 /// <param name="body"></param>
45 /// <returns></returns>
46 string Parse<T>(T body) where T : IApiRequest; 47 } 48
49
50
51 public class XmlParse:IParser 52 { 53 #region Field
54 private static readonly Regex regex = new Regex("<(\\w+?)[ >]", RegexOptions.Compiled); 55 private static readonly ReaderWriterLock rwLock = new ReaderWriterLock(); 56 private static readonly Dictionary<string, XmlSerializer> parsers = new Dictionary<string, XmlSerializer>(); 57 #endregion
58
59 #region Members
60 /// <summary>
61 /// 将XML转换为对象 62 /// </summary>
63 /// <typeparam name="T"></typeparam>
64 /// <param name="body"></param>
65 /// <returns></returns>
66 public T ParseDeserialize<T>(string body) where T : ApiResponse 67 { 68 Type type = typeof(T); 69 string rootTagName = GetRootElement(body); 70
71 string key = type.FullName; 72 if (Constants.ERROR_RESPONSE.Equals(rootTagName)) 73 { 74 key += ("_" + Constants.ERROR_RESPONSE); 75 } 76
77 XmlSerializer serializer = null; 78 bool incl = false; 79
80 rwLock.AcquireReaderLock(50); 81 try
82 { 83 if (rwLock.IsReaderLockHeld) 84 { 85 incl = parsers.TryGetValue(key, out serializer); 86 } 87 } 88 finally
89 { 90 if (rwLock.IsReaderLockHeld) 91 { 92 rwLock.ReleaseReaderLock(); 93 } 94 } 95
96 if (!incl || serializer == null) 97 { 98 XmlAttributes rootAttrs = new XmlAttributes(); 99 rootAttrs.XmlRoot = new XmlRootAttribute(rootTagName); 100
101 XmlAttributeOverrides attrOvrs = new XmlAttributeOverrides(); 102 attrOvrs.Add(type, rootAttrs); 103
104 serializer = new XmlSerializer(type, attrOvrs); 105
106 rwLock.AcquireWriterLock(50); 107 try
108 { 109 if (rwLock.IsWriterLockHeld) 110 { 111 parsers[key] = serializer; 112 } 113 } 114 finally
115 { 116 if (rwLock.IsWriterLockHeld) 117 { 118 rwLock.ReleaseWriterLock(); 119 } 120 } 121 } 122 object obj = null; 123 using (System.IO.Stream stream = new MemoryStream(Encoding.UTF8.GetBytes(body))) 124 { 125 obj = serializer.Deserialize(stream); 126 } 127
128 T rsp = (T)obj; 129 if (rsp != null) 130 { 131 rsp.Body = body; 132 } 133 return rsp; 134 } 135
136 /// <summary>
137 /// 将对象转换为XML 138 /// </summary>
139 /// <typeparam name="T"></typeparam>
140 /// <param name="obj"></param>
141 /// <returns></returns>
142 public string Parse<T>(T obj) where T : IApiRequest 143 { 144 XmlSerializer serializer = null; 145
146 serializer = new XmlSerializer(obj.GetType()); 147 XmlSerializerNamespaces xmlns = new XmlSerializerNamespaces(); 148 xmlns.Add("", ""); 149
150 string xml = null; 151 using (MemoryStream stream = new MemoryStream()) 152 { 153 serializer.Serialize(stream, obj, xmlns); 154 xml = Encoding.UTF8.GetString(stream.ToArray()); 155 } 156
157 return xml; 158 } 159 #endregion
160
161 /// <summary>
162 /// 获取XML响应的根节点名称 163 /// </summary>
164 private string GetRootElement(string body) 165 { 166 Match match = regex.Match(body); 167 if (match.Success) 168 { 169 return match.Groups[1].ToString(); 170 } 171 else
172 { 173 throw new Exception("Invalid XML response format!"); 174 } 175 } 176
177 public T XMLParse<T>(string body) where T : ApiResponse 178 { 179 throw new NotImplementedException(); 180 } 181
182
183 /// <summary>
184 /// 将XML文件进行反序列话进行对象 185 /// </summary>
186 /// <typeparam name="T">结果对象类型</typeparam>
187 /// <param name="s">包含对象的XML字符串</param>
188 /// <param name="encoding">编码方式</param>
189 /// <returns>反序列化得到的对象</returns>
190 public T XmlDeserialize<T>(string s) 191 { 192 if (string.IsNullOrEmpty(s)) 193 { 194 throw new ArgumentNullException("s"); 195 } 196 XmlSerializer mySerializer = new XmlSerializer(typeof(T)); 197 using (MemoryStream ms = new MemoryStream(Encoding.GetEncoding("utf-8").GetBytes(s))) 198 { 199 using (StreamReader sr = new StreamReader(ms, Encoding.GetEncoding("utf-8"))) 200 { 201 return (T)mySerializer.Deserialize(sr); 202 } 203 } 204 } 205
206 } 207
208
209 public sealed class Constants 210 { 211 public const string DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss"; 212
213 public const string SIGN_METHOD_MD5 = "md5"; 214
215 public const string ACCEPT_ENCODING = "Accept-Encoding"; 216 public const string CONTENT_ENCODING = "Content-Encoding"; 217 public const string CONTENT_ENCODING_GZIP = "gzip"; 218
219 public const string ERROR_RESPONSE = "error_response"; 220 public const string ERROR_CODE = "code"; 221 public const string ERROR_MSG = "msg"; 222 }
3.通过控制台应用进行调用

1 #region 获取TCPClient 返回的结果
2 /// <summary>
3 /// 获取TCPClient 返回的结果 4 /// </summary>
5 /// <param name="s"></param>
6 /// <param name="trans_id">服务器交易码</param>
7 /// <returns></returns>
8 private string GetTcpClientResult(MemoryStream s, string trans_id) 9 { 10 byte[] bufTemp = s.ToArray(); 11 string xmlContent = bufTemp.Length.ToString().PadLeft(10, '0') + "xxxx" + trans_id + Encoding.GetEncoding("GBK").GetString(bufTemp); 12 byte[] buf = Encoding.GetEncoding("GBK").GetBytes(xmlContent); 13 string svrAddr = Properties.Settings.Default.TCP_IP;//对方服务器的IP
14 int svrPort = Properties.Settings.Default.TCP_PORT;//请求的服务器的端口
15
16 using (TcpClient tcpClient = new TcpClient(svrAddr, svrPort)) 17 { 18 var tcpStream = tcpClient.GetStream(); 19 tcpStream.Write(buf, 0, buf.Length); 20 byte[] recv = new byte[4096]; 21 int recvLen = tcpStream.Read(recv, 0, recv.Length); 22 string result = Encoding.GetEncoding("GBK").GetString(recv, 0, recvLen); 23 tcpClient.Close(); 24 return result; 25 } 26 } 27 #endregion
四:整个Scoket 请求处理响应的流程图
以上内容全部原创,如需转载,请标明,谢谢!