基于.NET Socket API 通信的综合应用

时间:2023-03-10 01:25:38
基于.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流程图

基于.NET Socket API 通信的综合应用

2.首先请求方进行发送一段报文。

 <?xml version="1.0" encoding="GBK"?>
<Service>
<Service_Header>
<requester_id></requester_id>
<branch_id ></branch_id>
<service_time></service_time>
<version_id></version_id>
</Service_Header>
<Service_Body>
<request>
<channel_type></channel_type>
<cert_type></cert_type>
<cert_no></cert_no>
<query_type></query_type>
<fr_id></fr_id>
<pos_id></pos_id>
<shop_id></shop_id>
</request>
</Service_Body>
</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.响应的报文的序列化类

  [Serializable]
public class ScoreDetailResponse : ApiResponse
{
/// <summary>
/// 结果代码
/// </summary>
public string result_code { get;set; } /// <summary>
/// 结果说明
/// </summary>
public string result_info { get;set; } /// <summary>
/// 交易日期
/// </summary>
public string tran_date { get;set; } /// <summary>
/// 交易时间
/// </summary>
public string tran_timestamp { get;set; } /// <summary>
///交易积分数
/// </summary>
public string transfer_score { get;set; } /// <summary>
/// 剩余积分数
/// </summary>
public string surplus_score { get;set; } /// <summary>
/// 备注
/// </summary>
public string remark { get;set; } }
[Serializable]
[XmlRoot("Service")]
public class MyScoreDetailResponse
{
public List<ScoreDetailResponse> _ScoreDetailResponse = new List<ScoreDetailResponse>();
[XmlArray("Service_Body")]
[XmlArrayItem("response")]
public List<ScoreDetailResponse> ScoreDetailResponse { get;set; }
}

Serializable 类

2.序列化继承的接口和方法

 [XmlRoot("Service")]
public class ApiResponse
{
[XmlElement("errCode")]
public string ErrCode; [XmlElement("errMsg")]
public string ErrMsg; public string Body { get; set; }
} [XmlRoot("IFReturn")]
public class IApiRequest { }
[XmlRoot("IFReturn")]
public class ApiRequest<T> : IApiRequest where T : ApiResponse
{
[XmlElement("channel_type")]
public string channel_type { get; set; } [XmlElement("shop_id")]
public string shop_id { get; set; } [XmlElement("post_id")]
public string post_id { get; set; }
} public interface IParser
{
/// <summary>
/// 把响应字符串解释成相应的领域对象。
/// </summary>
/// <typeparam name="T">领域对象</typeparam>
/// <param name="body">响应字符串</param>
/// <returns>领域对象</returns>
T XMLParse<T>(string body) where T : ApiResponse; /// <summary>
/// 将对象转换为XML
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="body"></param>
/// <returns></returns>
string Parse<T>(T body) where T : IApiRequest;
} public class XmlParse:IParser
{
#region Field
private static readonly Regex regex = new Regex("<(\\w+?)[ >]", RegexOptions.Compiled);
private static readonly ReaderWriterLock rwLock = new ReaderWriterLock();
private static readonly Dictionary<string, XmlSerializer> parsers = new Dictionary<string, XmlSerializer>();
#endregion #region Members
/// <summary>
/// 将XML转换为对象
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="body"></param>
/// <returns></returns>
public T ParseDeserialize<T>(string body) where T : ApiResponse
{
Type type = typeof(T);
string rootTagName = GetRootElement(body); string key = type.FullName;
if (Constants.ERROR_RESPONSE.Equals(rootTagName))
{
key += ("_" + Constants.ERROR_RESPONSE);
} XmlSerializer serializer = null;
bool incl = false; rwLock.AcquireReaderLock();
try
{
if (rwLock.IsReaderLockHeld)
{
incl = parsers.TryGetValue(key, out serializer);
}
}
finally
{
if (rwLock.IsReaderLockHeld)
{
rwLock.ReleaseReaderLock();
}
} if (!incl || serializer == null)
{
XmlAttributes rootAttrs = new XmlAttributes();
rootAttrs.XmlRoot = new XmlRootAttribute(rootTagName); XmlAttributeOverrides attrOvrs = new XmlAttributeOverrides();
attrOvrs.Add(type, rootAttrs); serializer = new XmlSerializer(type, attrOvrs); rwLock.AcquireWriterLock();
try
{
if (rwLock.IsWriterLockHeld)
{
parsers[key] = serializer;
}
}
finally
{
if (rwLock.IsWriterLockHeld)
{
rwLock.ReleaseWriterLock();
}
}
}
object obj = null;
using (System.IO.Stream stream = new MemoryStream(Encoding.UTF8.GetBytes(body)))
{
obj = serializer.Deserialize(stream);
} T rsp = (T)obj;
if (rsp != null)
{
rsp.Body = body;
}
return rsp;
} /// <summary>
/// 将对象转换为XML
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="obj"></param>
/// <returns></returns>
public string Parse<T>(T obj) where T : IApiRequest
{
XmlSerializer serializer = null; serializer = new XmlSerializer(obj.GetType());
XmlSerializerNamespaces xmlns = new XmlSerializerNamespaces();
xmlns.Add("", ""); string xml = null;
using (MemoryStream stream = new MemoryStream())
{
serializer.Serialize(stream, obj, xmlns);
xml = Encoding.UTF8.GetString(stream.ToArray());
} return xml;
}
#endregion /// <summary>
/// 获取XML响应的根节点名称
/// </summary>
private string GetRootElement(string body)
{
Match match = regex.Match(body);
if (match.Success)
{
return match.Groups[].ToString();
}
else
{
throw new Exception("Invalid XML response format!");
}
} public T XMLParse<T>(string body) where T : ApiResponse
{
throw new NotImplementedException();
} /// <summary>
/// 将XML文件进行反序列话进行对象
/// </summary>
/// <typeparam name="T">结果对象类型</typeparam>
/// <param name="s">包含对象的XML字符串</param>
/// <param name="encoding">编码方式</param>
/// <returns>反序列化得到的对象</returns>
public T XmlDeserialize<T>(string s)
{
if (string.IsNullOrEmpty(s))
{
throw new ArgumentNullException("s");
}
XmlSerializer mySerializer = new XmlSerializer(typeof(T));
using (MemoryStream ms = new MemoryStream(Encoding.GetEncoding("utf-8").GetBytes(s)))
{
using (StreamReader sr = new StreamReader(ms, Encoding.GetEncoding("utf-8")))
{
return (T)mySerializer.Deserialize(sr);
}
}
} } public sealed class Constants
{
public const string DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss"; public const string SIGN_METHOD_MD5 = "md5"; public const string ACCEPT_ENCODING = "Accept-Encoding";
public const string CONTENT_ENCODING = "Content-Encoding";
public const string CONTENT_ENCODING_GZIP = "gzip"; public const string ERROR_RESPONSE = "error_response";
public const string ERROR_CODE = "code";
public const string ERROR_MSG = "msg";
}

反序列化进行解析代码

3.通过控制台应用进行调用

  #region 获取TCPClient 返回的结果
/// <summary>
/// 获取TCPClient 返回的结果
/// </summary>
/// <param name="s"></param>
/// <param name="trans_id">服务器交易码</param>
/// <returns></returns>
private string GetTcpClientResult(MemoryStream s, string trans_id)
{
byte[] bufTemp = s.ToArray();
string xmlContent = bufTemp.Length.ToString().PadLeft(, '') + "xxxx" + trans_id + Encoding.GetEncoding("GBK").GetString(bufTemp);
byte[] buf = Encoding.GetEncoding("GBK").GetBytes(xmlContent);
string svrAddr = Properties.Settings.Default.TCP_IP;//对方服务器的IP
int svrPort = Properties.Settings.Default.TCP_PORT;//请求的服务器的端口 using (TcpClient tcpClient = new TcpClient(svrAddr, svrPort))
{
var tcpStream = tcpClient.GetStream();
tcpStream.Write(buf, , buf.Length);
byte[] recv = new byte[];
int recvLen = tcpStream.Read(recv, , recv.Length);
string result = Encoding.GetEncoding("GBK").GetString(recv, , recvLen);
tcpClient.Close();
return result;
}
}
#endregion

TcpClient 应用Scoket进行发送请求

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

基于.NET Socket API 通信的综合应用

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