You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

266 lines
10 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

using System;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Text;
using System.Collections.Generic;
using System.Text.RegularExpressions;
namespace TRI_TCP_Client
{
/// <summary>
/// Net : 提供静态方法,对常用的网络操作进行封装
/// </summary>
public sealed class Net
{
private Net() { }
/// <summary>
/// 向远程主机发送数据
/// </summary>
/// <param name="socket">要发送数据且已经连接到远程主机的 Socket</param>
/// <param name="buffer">待发送的数据</param>
/// <param name="outTime">发送数据的超时时间,以秒为单位,可以精确到微秒</param>
/// <returns>0:发送数据成功;-1:超时;-2:发送数据出现错误;-3:发送数据时出现异常</returns>
/// <remarks >
/// 当 outTime 指定为-1时将一直等待直到有数据需要发送
/// </remarks>
public static int SendData(Socket socket, byte[] buffer, int outTime)
{
int flag = 0;
if (socket == null || socket.Connected == false)
{
throw new ArgumentException("参数socket 为null或者未连接到远程计算机");
}
if (buffer == null || buffer.Length == 0)
{
throw new ArgumentException("参数buffer 为null ,或者长度为 0");
}
try
{
int left = buffer.Length;
int sndLen = 0;
while (true)
{
if (socket.Poll(outTime * 100, SelectMode.SelectWrite) == true)
{ // 收集了足够多的传出数据后开始发送
sndLen = socket.Send(buffer, sndLen, left, SocketFlags.None);
left -= sndLen;
if (left == 0)
{ // 数据已经全部发送
flag = 0;
break;
}
else
{
if (sndLen > 0)
{ // 数据部分已经被发送
continue;
}
else
{ // 发送数据发生错误
flag = -2;
break;
}
}
}
else
{ // 超时退出
flag = -1;
break;
}
}
}
catch (SocketException)
{
flag = -3;
}
return flag;
}
/// <summary>
/// 向远程主机发送文件
/// </summary>
/// <param name="socket" >要发送数据且已经连接到远程主机的 socket</param>
/// <param name="filePath">待发送的文件</param>
/// <param name="maxBufferLength">文件发送时的缓冲区大小</param>
/// <param name="outTime">发送缓冲区中的数据的超时时间</param>
/// <returns>0:发送文件成功;-1:超时;-2:发送文件出现错误;-3:发送文件出现异常;-4:读取待发送文件发生错误</returns>
/// <remarks >
/// 当 outTime 指定为-1时将一直等待直到有数据需要发送
/// </remarks>
public static int SendFile(Socket socket, string filePath, int maxBufferLength, int outTime)
{
if (filePath == null || maxBufferLength <= 0)
{
throw new ArgumentException("待发送的文件名称为空或发送缓冲区的大小设置不正确.");
}
int flag = 0;
try
{
FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read);
long fileLen = fs.Length; // 文件长度
long leftLen = fileLen; // 未读取部分
int readLen = 0; // 已读取部分
byte[] buffer = null;
if (fileLen <= maxBufferLength)
{ //文件可以一次读取(+1指代结束标识符)
buffer = new byte[fileLen + 1];
readLen = fs.Read(buffer, 0, (int)(fileLen + 1));
buffer[fileLen] = (byte)'`';
flag = SendData(socket, buffer, outTime);
}
else
{
//循环读取文件,并发送
while (leftLen != 0)
{
if (leftLen < maxBufferLength)
{
buffer = new byte[leftLen];
readLen = fs.Read(buffer, 0, Convert.ToInt32(leftLen));
}
else
{
buffer = new byte[maxBufferLength];
readLen = fs.Read(buffer, 0, maxBufferLength);
}
if ((flag = SendData(socket, buffer, outTime)) < 0)
{
break;
}
leftLen -= readLen;
}
//在结尾带上结束标识符: "`"
SendData(socket, System.Text.Encoding.Default.GetBytes("`"), outTime);
}
fs.Flush();
fs.Close();
}
catch (IOException)
{
//读取待发送文件发生错误
flag = -4;
}
return flag;
}
/// <summary>
/// 使用TCP发送文件
/// </summary>
/// <param name="socket"></param>
/// <param name="path"></param>
/// <param name="bufsize"></param>
/// <param name="outTime"></param>
public static string TCPSend(Socket socket, string path, int maxBufferLength, int outTime)
{
string res = "";
string eqpName = "";
int _flag;
List<string> eqpNames = new List<string>();
//TODO: 根据需求修改具体的设备名
eqpNames.Add("2DAOI");
eqpNames.Add("3DAOI");
eqpNames.Add("SPI");
foreach (string item in eqpNames)
{
if (System.Text.RegularExpressions.Regex.IsMatch(path, item))
{
eqpName = item; break;
}
}
string _filename = Path.GetFileName(path);
_flag = Net.SendData(socket, Encoding.Default.GetBytes("1000&" + eqpName + "&" + _filename), outTime);
Console.WriteLine(_flag + " 文件发送 " + DateTime.Now.ToString("yyyy:MM:dd HH:mm:ss:ff"));
try
{
if (Net.SendFile(socket, path, maxBufferLength, outTime) != 0)
{
if (Net.SendFile(socket, path, maxBufferLength, outTime) != 0)
{
res = "发送失败";
}
else
{
res = "重发成功";
}
}
else
{
res = "发送成功";
}
}
catch (Exception ex)
{
res = "[ERR]" + ex.Message.ToString();
}
return res;
}
/// <summary>
/// 接收数据
/// </summary>
/// <param name="socket"></param>
/// <param name="buffer">size=25</param>
/// <returns>数据 or null</returns>
public static string[] RecvData(Socket socket, byte[] buffer)
{
if (socket == null || socket.Connected == false)
{
throw new ArgumentException("参数socket 为null或者未连接到远程计算机");
}
if (buffer == null || buffer.Length == 0)
{
throw new ArgumentException("参数buffer 为null ,或者长度为 0");
}
if (socket.Receive(buffer, 0, buffer.Length, SocketFlags.None) > 0)
{
string recv = Encoding.Default.GetString(buffer);
string[] array = Regex.Split(recv, "(&)");
return array;
}
return null;
}
/// <summary>
/// 接收并在本地创建文件
/// </summary>
/// <param name="socket"></param>
/// <param name="buffer"></param>
/// <param name="path"></param>
/// <returns>返回文件接收时间和大小</returns>
public static string RecvFile(Socket socket, byte[] buffer, string path)
{
int size = 0;
long len = 0;
DateTime oTimeBegin = DateTime.Now;
//创建文件流,然后让文件流来根据路径创建一个文件
FileStream fs = new FileStream(path, FileMode.Create, FileAccess.Write);
//从终端不停的接受数据然后写入文件里面只到接受到的数据为0为止则中断连接
while ((size = socket.Receive(buffer, 0, buffer.Length, SocketFlags.None)) > 0)
{
string flag = Encoding.Default.GetString(buffer, size - 1, 1);
if (flag.Equals("`"))
{
fs.Write(buffer, 0, size - 1);
len += size;
break;
}
else
{
fs.Write(buffer, 0, size);
len += size;
}
}
DateTime oTimeEnd = DateTime.Now;
TimeSpan oTime = oTimeEnd.Subtract(oTimeBegin);
fs.Flush();
fs.Close();
len -= 1;//去除文件尾标记占据空间
string store = (len / 1024.0) > 1.0 ? (len / 1024.0) + "kb" : len + "字节";
return $"接收文件{path}用时: {oTime}, 文件大小:{store}";
}
}
}