基于.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     }
Serializable 类

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
TcpClient 应用Scoket进行发送请求

 

四:整个Scoket 请求处理响应的流程图

 

以上内容全部原创,如需转载,请标明,谢谢!

 

 

posted @ 2016-12-03 15:39  LowKeyC  阅读(1748)  评论(2编辑  收藏  举报
有志者事竟成破釜沉舟百二秦关终属楚苦心人,天不负,卧薪尝胆,三千越甲可吞吴