基于.NET Socket API 通信的综合应用
闲谈一下,最近和客户进行对接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 请求处理响应的流程图
以上内容全部原创,如需转载,请标明,谢谢!
再牛逼的梦想,也抵不住我傻逼似的坚持!别在该奋斗的年纪,贪图安逸。 今天多学一些知识,明天开发的速度就更快一下。后天你就会变得更好。