using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Net; using System.Net.Sockets; using System.IO; using System.Threading; namespace MECF.Framework.RT.Core.IoProviders.Siemens.Net { /******************************************************************************* * * 网络通信类的基础类,提供所有相关的基础方法和功能 * * Network communication base class of the class, provides the basis of all relevant methods and functions * *******************************************************************************/ #region Network Helper /// /// 静态的方法支持类,提供一些网络的静态支持,支持从套接字从同步接收指定长度的字节数据,并支持报告进度。 /// /// /// 在接收指定数量的字节数据的时候,如果一直接收不到,就会发生假死的状态。接收的数据时保存在内存里的,不适合大数据块的接收。 /// /// /// 一个接收的示例 /// /// public static class NetSupport { /// /// Socket传输中的缓冲池大小 /// internal const int SocketBufferSize = 4096; /// /// 检查是否超时的静态方法 /// /// 数据封送对象 /// 超时的时间 internal static void ThreadPoolCheckConnect( HslTimeOut timeout, int millisecond ) { while (!timeout.IsSuccessful) { if ((DateTime.Now - timeout.StartTime).TotalMilliseconds > millisecond) { // 连接超时或是验证超时 if (!timeout.IsSuccessful) timeout.WorkSocket?.Close( ); break; } Thread.Sleep( 100 ); } } /// /// 检查是否超时的方法信息 /// /// socket对象 internal static void ThreadPoolCheckTimeOut( object obj ) { if (obj is HslTimeOut timeout) { while (!timeout.IsSuccessful) { if ((DateTime.Now - timeout.StartTime).TotalMilliseconds > timeout.DelayTime) { // 连接超时或是验证超时 if (!timeout.IsSuccessful) { timeout.Operator?.Invoke( ); timeout.WorkSocket?.Close( ); } break; } } } } /// /// 读取socket数据的基础方法,只适合用来接收指令头,或是同步数据 /// /// 通信对象 /// 接收的长度 /// 接收到的字节数据 /// /// /// /// /// /// 接收数据的举例,简单的接收20个字节长度的数据。 /// /// 如何接收不定长度的数据呢?我们可以将一条数据拆分成2次接收,第一次是接收8个固定的字节,解析成长度,再接收真实的数据。 /// /// public static byte[] ReadBytesFromSocket( Socket socket, int receive ) { return ReadBytesFromSocket( socket, receive, null, false, false ); } /// /// 读取socket数据的基础方法,只适合用来接收指令头,或是同步数据 /// /// 通信对象 /// 接收的长度 /// 用于报告接收进度的对象 /// 是否按照百分比报告进度 /// 是否回发接收数据长度 /// 接收到的字节数据 /// /// /// /// /// /// 接收数据的举例,输出报告,不根据百分比来产生报告,不回复接收进度。 /// /// public static byte[] ReadBytesFromSocket( Socket socket, int receive, Action report, bool reportByPercent, bool response ) { byte[] bytes_receive = new byte[receive]; int count_receive = 0; long percent = 0; while (count_receive < receive) { // 分割成2KB来接收数据 int receive_length = (receive - count_receive) >= SocketBufferSize ? SocketBufferSize : (receive - count_receive); count_receive += socket.Receive( bytes_receive, count_receive, receive_length, SocketFlags.None ); if (reportByPercent) { long percentCurrent = (long)count_receive * 100 / receive; if (percent != percentCurrent) { percent = percentCurrent; // 报告进度 report?.Invoke( count_receive, receive ); } } else { // 报告进度 report?.Invoke( count_receive, receive ); } // 回发进度 if (response) socket.Send( BitConverter.GetBytes( (long)count_receive ) ); } return bytes_receive; } /// /// 接收一行命令数据,需要自己指定这个结束符 /// /// 网络套接字 /// 结束符信息 /// 带有结果对象的数据信息 public static OperateResult ReceiveCommandLineFromSocket( Socket socket, byte endCode ) { List bufferArray = new List( ); try { // 接收到endCode为止 while (true) { byte[] head = NetSupport.ReadBytesFromSocket( socket, 1 ); bufferArray.AddRange( head ); if (head[0] == endCode) break; } // 指令头已经接收完成 return OperateResult.CreateSuccessResult( bufferArray.ToArray( ) ); } catch (Exception ex) { socket?.Close( ); return new OperateResult( ex.Message ); } } /// /// 接收一行命令数据,需要自己指定这个结束符 /// /// 网络套接字 /// 结束符1信息 /// 结束符2信息 /// 带有结果对象的数据信息 public static OperateResult ReceiveCommandLineFromSocket( Socket socket, byte endCode1, byte endCode2 ) { List bufferArray = new List( ); try { // 接收到endCode为止 while (true) { byte[] head = NetSupport.ReadBytesFromSocket( socket, 1 ); bufferArray.AddRange( head ); if (head[0] == endCode2) { if(bufferArray.Count > 0 && bufferArray.Last( ) == endCode1) { break; } } } // 指令头已经接收完成 return OperateResult.CreateSuccessResult( bufferArray.ToArray( ) ); } catch (Exception ex) { socket?.Close( ); return new OperateResult( ex.Message ); } } /// /// 从socket套接字读取数据并写入流中,必然报告进度 /// /// 通信对象 /// stream /// 接收的长度 /// 用于报告接收进度的对象 /// 是否按照百分比报告进度 /// /// /// /// /// /// 举例从socket读取数据,然后写入到文件流中 /// /// public static void WriteStreamFromSocket( Socket socket, Stream stream, long receive, Action report, bool reportByPercent ) { byte[] buffer = new byte[SocketBufferSize]; long count_receive = 0; long percent = 0; while (count_receive < receive) { // 分割成4KB来接收数据 int current = socket.Receive( buffer, 0, SocketBufferSize, SocketFlags.None ); count_receive += current; stream.Write( buffer, 0, current ); if (reportByPercent) { long percentCurrent = count_receive * 100 / receive; if (percent != percentCurrent) { percent = percentCurrent; // 报告进度 report?.Invoke( count_receive, receive ); } } else { // 报告进度 report?.Invoke( count_receive, receive ); } // 回发进度 socket.Send( BitConverter.GetBytes( count_receive ) ); } } /// /// 读取流并将数据写入socket /// /// 文件流 /// 连接的套接字 /// 返回的文件长度 /// 发送的进度报告 /// 是否按照百分比报告进度 /// /// /// /// /// /// 举例从文件读取数据,然后写入到套接字中,相当于发送文件到socket /// /// public static void WriteSocketFromStream( Socket socket, Stream stream, long length, Action report, bool reportByPercent ) { byte[] buffer = new byte[SocketBufferSize]; long count_send = 0; stream.Position = 0; long percent = 0; while (count_send < length) { int count = stream.Read( buffer, 0, SocketBufferSize ); count_send += count; socket.Send( buffer, 0, count, SocketFlags.None ); while (count_send != BitConverter.ToInt64( ReadBytesFromSocket( socket, 8 ), 0 )) ; long received = count_send; if (reportByPercent) { long percentCurrent = received * 100 / length; if (percent != percentCurrent) { percent = percentCurrent; // 报告进度 report?.Invoke( received, length ); } } else { // 报告进度 report?.Invoke( received, length ); } // 双重接收验证 if (count == 0) { break; } } } } #endregion }