From dcf52cead730ceb456945ba7ea48b5c5c4d47d78 Mon Sep 17 00:00:00 2001 From: ZGGSONG Date: Mon, 29 Nov 2021 15:25:09 +0800 Subject: [PATCH] add project --- .gitignore | 388 ++++++++++++++++++ README.md | 9 + TRI_TCP_Client/TRI_TCP_Client.sln | 25 ++ TRI_TCP_Client/TRI_TCP_Client/App.config | 6 + TRI_TCP_Client/TRI_TCP_Client/FileChange.cs | 82 ++++ TRI_TCP_Client/TRI_TCP_Client/Net.cs | 193 +++++++++ .../TRI_TCP_Client/Properties/AssemblyInfo.cs | 36 ++ TRI_TCP_Client/TRI_TCP_Client/Run.cs | 290 +++++++++++++ .../TRI_TCP_Client/TRI_TCP_Client.csproj | 59 +++ TRI_TCP_Server/TRI_TCP_Server.sln | 25 ++ TRI_TCP_Server/TRI_TCP_Server/App.config | 6 + TRI_TCP_Server/TRI_TCP_Server/Net.cs | 277 +++++++++++++ .../TRI_TCP_Server/Properties/AssemblyInfo.cs | 36 ++ TRI_TCP_Server/TRI_TCP_Server/Run.cs | 199 +++++++++ .../TRI_TCP_Server/TRI_TCP_Server.csproj | 53 +++ 15 files changed, 1684 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 TRI_TCP_Client/TRI_TCP_Client.sln create mode 100644 TRI_TCP_Client/TRI_TCP_Client/App.config create mode 100644 TRI_TCP_Client/TRI_TCP_Client/FileChange.cs create mode 100644 TRI_TCP_Client/TRI_TCP_Client/Net.cs create mode 100644 TRI_TCP_Client/TRI_TCP_Client/Properties/AssemblyInfo.cs create mode 100644 TRI_TCP_Client/TRI_TCP_Client/Run.cs create mode 100644 TRI_TCP_Client/TRI_TCP_Client/TRI_TCP_Client.csproj create mode 100644 TRI_TCP_Server/TRI_TCP_Server.sln create mode 100644 TRI_TCP_Server/TRI_TCP_Server/App.config create mode 100644 TRI_TCP_Server/TRI_TCP_Server/Net.cs create mode 100644 TRI_TCP_Server/TRI_TCP_Server/Properties/AssemblyInfo.cs create mode 100644 TRI_TCP_Server/TRI_TCP_Server/Run.cs create mode 100644 TRI_TCP_Server/TRI_TCP_Server/TRI_TCP_Server.csproj diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..34c8dee --- /dev/null +++ b/.gitignore @@ -0,0 +1,388 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.tlog +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Nuget personal access tokens and Credentials +nuget.config + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd + +# VS Code files for those working on multiple tools +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +*.code-workspace + +# Local History for Visual Studio Code +.history/ + +# Windows Installer files from build outputs +*.cab +*.msi +*.msix +*.msm +*.msp + +# JetBrains Rider +.idea/ +*.sln.iml diff --git a/README.md b/README.md new file mode 100644 index 0000000..8d4f675 --- /dev/null +++ b/README.md @@ -0,0 +1,9 @@ +# Introduction + +``` +. +├── TCPServer +│   +└── TCPClient + +``` diff --git a/TRI_TCP_Client/TRI_TCP_Client.sln b/TRI_TCP_Client/TRI_TCP_Client.sln new file mode 100644 index 0000000..c907ad8 --- /dev/null +++ b/TRI_TCP_Client/TRI_TCP_Client.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.31702.278 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TRI_TCP_Client", "TRI_TCP_Client\TRI_TCP_Client.csproj", "{BCDB912C-2008-4FA5-A959-0C8FC863C2EB}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {BCDB912C-2008-4FA5-A959-0C8FC863C2EB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BCDB912C-2008-4FA5-A959-0C8FC863C2EB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BCDB912C-2008-4FA5-A959-0C8FC863C2EB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BCDB912C-2008-4FA5-A959-0C8FC863C2EB}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {4632BEDB-AE68-46BB-9701-B8EC34BB48E2} + EndGlobalSection +EndGlobal diff --git a/TRI_TCP_Client/TRI_TCP_Client/App.config b/TRI_TCP_Client/TRI_TCP_Client/App.config new file mode 100644 index 0000000..8e15646 --- /dev/null +++ b/TRI_TCP_Client/TRI_TCP_Client/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/TRI_TCP_Client/TRI_TCP_Client/FileChange.cs b/TRI_TCP_Client/TRI_TCP_Client/FileChange.cs new file mode 100644 index 0000000..f05484c --- /dev/null +++ b/TRI_TCP_Client/TRI_TCP_Client/FileChange.cs @@ -0,0 +1,82 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Net.Sockets; +using System.Threading; +using TRI_TCP_Client.Log; + +namespace TRI_TCP_Client +{ + #region 文件系统监控 + public class FileChange + { + private static Socket socketClient = Client.conn(); + public static void onFileChange(string path) + { + using var watcher = new FileSystemWatcher(path); + + watcher.NotifyFilter = NotifyFilters.Attributes + | NotifyFilters.CreationTime + | NotifyFilters.DirectoryName + | NotifyFilters.FileName + | NotifyFilters.LastAccess + | NotifyFilters.LastWrite + | NotifyFilters.Security + | NotifyFilters.Size; + + watcher.Changed += OnChanged; + watcher.Created += OnCreated; + watcher.Deleted += OnDeleted; + watcher.Renamed += OnRenamed; + watcher.Error += OnError; + + watcher.Filter = "*.*"; + watcher.IncludeSubdirectories = true; + watcher.EnableRaisingEvents = true; + + Console.WriteLine("Press enter to exit."); + Console.ReadLine(); + } + + private static void OnChanged(object sender, FileSystemEventArgs e) + { + if (e.ChangeType != WatcherChangeTypes.Changed) + { + return; + } + Console.WriteLine($"Changed: {e.FullPath}"); + } + + private static void OnCreated(object sender, FileSystemEventArgs e) + { + string res = Net.TCPSend(socketClient, e.FullPath, 512, 1); + Console.WriteLine($"Created: {e.FullPath}" + res + Path.GetFileName(e.FullPath)); + } + + private static void OnDeleted(object sender, FileSystemEventArgs e) => + Console.WriteLine($"Deleted: {e.FullPath}"); + + private static void OnRenamed(object sender, RenamedEventArgs e) + { + Console.WriteLine($"Renamed:"); + Console.WriteLine($" Old: {e.OldFullPath}"); + Console.WriteLine($" New: {e.FullPath}"); + } + + private static void OnError(object sender, ErrorEventArgs e) => + PrintException(e.GetException()); + + private static void PrintException(Exception? ex) + { + if (ex != null) + { + Console.WriteLine($"Message: {ex.Message}"); + Console.WriteLine("Stacktrace:"); + Console.WriteLine(ex.StackTrace); + Console.WriteLine(); + PrintException(ex.InnerException); + } + } + } + #endregion +} diff --git a/TRI_TCP_Client/TRI_TCP_Client/Net.cs b/TRI_TCP_Client/TRI_TCP_Client/Net.cs new file mode 100644 index 0000000..bae7a11 --- /dev/null +++ b/TRI_TCP_Client/TRI_TCP_Client/Net.cs @@ -0,0 +1,193 @@ +using System; +using System.Net; +using System.Net.Sockets; +using System.IO; +using System.Text; + +namespace TRI_TCP_Client +{ + /// + /// Net : 提供静态方法,对常用的网络操作进行封装 + /// + public sealed class Net + { + private Net() { } + + /// + /// 向远程主机发送数据 + /// + /// 要发送数据且已经连接到远程主机的 Socket + /// 待发送的数据 + /// 发送数据的超时时间,以秒为单位,可以精确到微秒 + /// 0:发送数据成功;-1:超时;-2:发送数据出现错误;-3:发送数据时出现异常 + /// + /// 当 outTime 指定为-1时,将一直等待直到有数据需要发送 + /// + public static int SendData(Socket socket, byte[] buffer, int outTime) + { + if (socket == null || socket.Connected == false) + { + throw new ArgumentException("参数socket 为null,或者未连接到远程计算机"); + } + if (buffer == null || buffer.Length == 0) + { + throw new ArgumentException("参数buffer 为null ,或者长度为 0"); + } + + int flag = 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; + } + + + /// + /// 向远程主机发送文件 + /// + /// 要发送数据且已经连接到远程主机的 socket + /// 待发送的文件 + /// 文件发送时的缓冲区大小 + /// 发送缓冲区中的数据的超时时间 + /// 0:发送文件成功;-1:超时;-2:发送文件出现错误;-3:发送文件出现异常;-4:读取待发送文件发生错误 + /// + /// 当 outTime 指定为-1时,将一直等待直到有数据需要发送 + /// + 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; + } + + /// + /// 使用TCP发送文件 + /// + /// + /// + /// + /// + public static string TCPSend(Socket socket, string path, int maxBufferLength, int outTime) + { + string res = null; + int _flag; + //先发送一个标记:"1000"标记为传文件 + //D:\KSATProjects\2021-10-ASM\settings\SPI\Lanto_HTTP.INI + string eqpName = System.Text.RegularExpressions.Regex.IsMatch(path, "AOI") ? "AOI" : "SPI"; + 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; + } + } +} \ No newline at end of file diff --git a/TRI_TCP_Client/TRI_TCP_Client/Properties/AssemblyInfo.cs b/TRI_TCP_Client/TRI_TCP_Client/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..b9a8c91 --- /dev/null +++ b/TRI_TCP_Client/TRI_TCP_Client/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// 有关程序集的一般信息由以下 +// 控制。更改这些特性值可修改 +// 与程序集关联的信息。 +[assembly: AssemblyTitle("TRI_TCP_Client")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("TRI_TCP_Client")] +[assembly: AssemblyCopyright("Copyright © 2021")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// 将 ComVisible 设置为 false 会使此程序集中的类型 +//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型 +//请将此类型的 ComVisible 特性设置为 true。 +[assembly: ComVisible(false)] + +// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID +[assembly: Guid("bcdb912c-2008-4fa5-a959-0c8fc863c2eb")] + +// 程序集的版本信息由下列四个值组成: +// +// 主版本 +// 次版本 +// 生成号 +// 修订号 +// +//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值 +//通过使用 "*",如下所示: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/TRI_TCP_Client/TRI_TCP_Client/Run.cs b/TRI_TCP_Client/TRI_TCP_Client/Run.cs new file mode 100644 index 0000000..c45165b --- /dev/null +++ b/TRI_TCP_Client/TRI_TCP_Client/Run.cs @@ -0,0 +1,290 @@ +using System; +using System.IO; +using System.Net; +using System.Net.Sockets; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading; +using TRI_TCP_Client.Log; + +namespace TRI_TCP_Client +{ + #region 心跳包 + public class Ping + { + private int flag; + private Socket pingsocket; + public Ping(Socket so) + { + pingsocket = so; + } + public void PingProc() + { + byte[] _buf = new byte[4]; + //发送心跳包 + while (true) + { + try + { + Thread.Sleep(3000); + flag = Net.SendData(pingsocket, Encoding.Default.GetBytes("1001"), 1); + Console.WriteLine(flag + " 心跳信号 " + DateTime.Now.ToString("yyyy:MM:dd HH:mm:ss:fff")); + //接受心跳放置在接受文件线程 + //if (pingsocket.Receive(_buf, 0, 4, SocketFlags.None) > 0) + //{ + // string recv = Encoding.Default.GetString(_buf); + // Console.WriteLine(recv + " 接收消息 " + DateTime.Now.ToString("yyyy:MM:dd HH:mm:ss:fff")); + //} + } + catch + { + Console.WriteLine("服务端: " + pingsocket.RemoteEndPoint + "掉线了"); + break; + } + } + } + } + #endregion + public class Client + { + //服务端IP + private static string Ip = "172.17.208.203"; + //TCP端口 + private static string Port = "5001"; + #region TCP连接 + /// + /// 创建TCP客户端连接 + /// + /// 返回TCP套接字 + /// + /// 创建连接的同时发送心跳包 + /// + public static Socket conn() + { + IPAddress ipaddress = IPAddress.Parse(Ip); + IPEndPoint endpoint = new IPEndPoint(ipaddress, int.Parse(Port)); + //创建服务端负责监听的套接字,参数(使用IPV4协议,使用流式连接,使用TCO协议传输数据) + Socket socketClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + socketClient.Connect(endpoint); + if (socketClient.Connected) + { + //创建通信线程 + ParameterizedThreadStart pts = new ParameterizedThreadStart(RecMsg); + Thread thradRecMsg = new Thread(pts); + thradRecMsg.IsBackground = true; + thradRecMsg.Start(socketClient); + Console.WriteLine(socketClient.RemoteEndPoint.ToString() + "连接成功"); + } + // 开启心跳线程 + Ping ping = new Ping(socketClient); + Thread t = new Thread(new ThreadStart(ping.PingProc)); + t.IsBackground = true; + t.Start(); + return socketClient; + } + #endregion + + /// + /// 接收消息 + /// + /// + private static void RecMsg(object socketClientPara) + { + Socket socketClient = socketClientPara as Socket; + + while (true) + { + //定义一个接受用的缓存区(100M字节数组) + //byte[] arrMsgRec = new byte[1024 * 1024 * 100]; + //将接收到的数据存入arrMsgRec数组,并返回真正接受到的数据的长度 + if (socketClient.Connected) + { + try + { + //因为终端每次发送文件的最大缓冲区是512字节,所以每次接收也是定义为512字节 + byte[] _buf = new byte[25]; + byte[] buffer = new byte[512]; + int size = 0; + long len = 0; + string fileSavePath = @"D:\ClientDir";//获得用户保存文件的路径 + if (!Directory.Exists(fileSavePath)) + { + Directory.CreateDirectory(fileSavePath); + } + //有文件发送才创建新文件 + if (socketClient.Receive(_buf, 0, 25, SocketFlags.None) > 0) + { + //string recv = Encoding.Default.GetString(_buf); + Console.WriteLine(socketClient.RemoteEndPoint + " 接收消息: " + DateTime.Now.ToString("yyyy:MM:dd HH:mm:ss:fff")); + string res = Encoding.Default.GetString(_buf); + string[] str = Regex.Split(res, "(&)"); + if (str[0] == "1000") + { + string fileName = fileSavePath + "\\" + str[2] + "\\" + str[4].TrimEnd('\0'); + //创建文件流,然后让文件流来根据路径创建一个文件 + FileStream fs = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.Write); + //从终端不停的接受数据,然后写入文件里面,只到接受到的数据为0为止,则中断连接 + + DateTime oTimeBegin = DateTime.Now; + + while ((size = socketClient.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; + Console.WriteLine("文件保存成功:" + fileName); + string store = (len / 1024.0) > 1.0 ? (len / 1024.0) + "kb" : len + "字节"; + Console.WriteLine("接收文件用时:" + oTime.ToString() + ",文件大小:" + store); + } + } + } + catch + { + break; + } + } + } + } + + public static void Main() + { + try + { + //连接 + conn(); + //FileChange.onFileChange(Path); + } + catch (Exception ex) + { + Console.WriteLine("连接服务器出错: " + ex.Message.ToString()); + } + Console.ReadKey(); + } + } + #region 弃用 + public class Run + { + private static Socket socketClient = Client.conn(); + public static void test() + { + using var watcher = new FileSystemWatcher(@"D:\ClientDir"); + + watcher.NotifyFilter = NotifyFilters.Attributes + | NotifyFilters.CreationTime + | NotifyFilters.DirectoryName + | NotifyFilters.FileName + | NotifyFilters.LastAccess + | NotifyFilters.LastWrite + | NotifyFilters.Security + | NotifyFilters.Size; + + watcher.Changed += OnChanged; + watcher.Created += OnCreated; + watcher.Deleted += OnDeleted; + watcher.Renamed += OnRenamed; + watcher.Error += OnError; + + watcher.Filter = "*.ini"; + watcher.IncludeSubdirectories = true; + watcher.EnableRaisingEvents = true; + + Console.WriteLine("Press enter to exit."); + Console.ReadLine(); + } + + private static void OnChanged(object sender, FileSystemEventArgs e) + { + if (e.ChangeType != WatcherChangeTypes.Changed) + { + return; + } + Console.WriteLine($"Changed: {e.FullPath}"); + } + + private static void OnCreated(object sender, FileSystemEventArgs e) + { + int _flag; + //先发送一个标记:"1000"标记为传文件 + _flag = Net.SendData(socketClient, System.Text.Encoding.Default.GetBytes("1000"), 1); + Console.WriteLine(_flag + " 文件发送 " + DateTime.Now.ToString("yyyy:MM:dd HH:mm:ss:ff")); + string value = $"Created: {e.FullPath}"; + Logger.Instance.WriteLog(value, LogType.Information); + //Socket socketClient = _socket.conn(); + try + { + int flag = Net.SendFile(socketClient, e.FullPath, 512, 1); + if (flag == 0) + { + Console.WriteLine("文件发送成功"); + } + else + { + Console.WriteLine("文件发送失败, flag=" + flag); + int flag2 = Net.SendFile(socketClient, e.FullPath, 512, 1); + if (flag2 == 0) + { + Console.WriteLine("文件重传成功"); + } + else + { + Console.WriteLine("文件重传失败, flag=" + flag); + } + } + } + catch (Exception ex) + { + Console.WriteLine("[ERR]" + ex.Message.ToString()); + Logger.Instance.WriteException(ex); + } + finally + { + //socketClient.Close(); + //Console.WriteLine("连接关闭"); + //Logger.Instance.WriteLog("关闭连接", LogType.All); + } + Console.WriteLine(value); + Logger.Instance.WriteLog("end", LogType.Information); + } + + private static void OnDeleted(object sender, FileSystemEventArgs e) => + Console.WriteLine($"Deleted: {e.FullPath}"); + + private static void OnRenamed(object sender, RenamedEventArgs e) + { + Console.WriteLine($"Renamed:"); + Console.WriteLine($" Old: {e.OldFullPath}"); + Console.WriteLine($" New: {e.FullPath}"); + } + + private static void OnError(object sender, ErrorEventArgs e) => + PrintException(e.GetException()); + + private static void PrintException(Exception? ex) + { + if (ex != null) + { + Console.WriteLine($"Message: {ex.Message}"); + Console.WriteLine("Stacktrace:"); + Console.WriteLine(ex.StackTrace); + Console.WriteLine(); + PrintException(ex.InnerException); + } + } + } + #endregion +} \ No newline at end of file diff --git a/TRI_TCP_Client/TRI_TCP_Client/TRI_TCP_Client.csproj b/TRI_TCP_Client/TRI_TCP_Client/TRI_TCP_Client.csproj new file mode 100644 index 0000000..c19c5e6 --- /dev/null +++ b/TRI_TCP_Client/TRI_TCP_Client/TRI_TCP_Client.csproj @@ -0,0 +1,59 @@ + + + + + Debug + AnyCPU + {BCDB912C-2008-4FA5-A959-0C8FC863C2EB} + Exe + TRI_TCP_Client + TRI_TCP_Client + v4.5 + 512 + true + + + latest + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/TRI_TCP_Server/TRI_TCP_Server.sln b/TRI_TCP_Server/TRI_TCP_Server.sln new file mode 100644 index 0000000..fd0734f --- /dev/null +++ b/TRI_TCP_Server/TRI_TCP_Server.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.31702.278 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TRI_TCP_Server", "TRI_TCP_Server\TRI_TCP_Server.csproj", "{7E709BF8-6665-405A-ABFC-CB5B49C62DB0}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {7E709BF8-6665-405A-ABFC-CB5B49C62DB0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7E709BF8-6665-405A-ABFC-CB5B49C62DB0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7E709BF8-6665-405A-ABFC-CB5B49C62DB0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7E709BF8-6665-405A-ABFC-CB5B49C62DB0}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {D16315A8-E4EB-4CEB-BEA1-2EB0BE06AE18} + EndGlobalSection +EndGlobal diff --git a/TRI_TCP_Server/TRI_TCP_Server/App.config b/TRI_TCP_Server/TRI_TCP_Server/App.config new file mode 100644 index 0000000..8e15646 --- /dev/null +++ b/TRI_TCP_Server/TRI_TCP_Server/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/TRI_TCP_Server/TRI_TCP_Server/Net.cs b/TRI_TCP_Server/TRI_TCP_Server/Net.cs new file mode 100644 index 0000000..61652ea --- /dev/null +++ b/TRI_TCP_Server/TRI_TCP_Server/Net.cs @@ -0,0 +1,277 @@ +using System; +using System.Net; +using System.Net.Sockets; +using System.IO; +using System.Text; +using System.Text.RegularExpressions; + +namespace TRI_TCP_Server +{ + /// + /// Net : 提供静态方法,对常用的网络操作进行封装 + /// + public sealed class Net + { + private Net() { } + + /// + /// 向远程主机发送数据 + /// + /// 要发送数据且已经连接到远程主机的 Socket + /// 待发送的数据 + /// 发送数据的超时时间,以秒为单位,可以精确到微秒 + /// 0:发送数据成功;-1:超时;-2:发送数据出现错误;-3:发送数据时出现异常 + /// + /// 当 outTime 指定为-1时,将一直等待直到有数据需要发送 + /// + public static int SendData(Socket socket, byte[] buffer, int outTime) + { + if (socket == null || socket.Connected == false) + { + throw new ArgumentException("参数socket 为null,或者未连接到远程计算机"); + } + if (buffer == null || buffer.Length == 0) + { + throw new ArgumentException("参数buffer 为null ,或者长度为 0"); + } + + int flag = 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; + } + + + /// + /// 向远程主机发送文件 + /// + /// 要发送数据且已经连接到远程主机的 socket + /// 待发送的文件名称 + /// 文件发送时的缓冲区大小 + /// 发送缓冲区中的数据的超时时间 + /// 0:发送文件成功;-1:超时;-2:发送文件出现错误;-3:发送文件出现异常;-4:读取待发送文件发生错误 + /// + /// 当 outTime 指定为-1时,将一直等待直到有数据需要发送 + /// + public static int SendFile(Socket socket, string fileName, int maxBufferLength, int outTime) + { + if (fileName == null || maxBufferLength <= 0) + { + throw new ArgumentException("待发送的文件名称为空或发送缓冲区的大小设置不正确."); + } + int flag = 0; + try + { + FileStream fs = new FileStream(fileName, 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; + } + + /// + /// 使用TCP发送文件 + /// + /// + /// + /// + /// + public static string TCPSend(Socket socket, string path, int maxBufferLength, int outTime) + { + string res = null; + int _flag; + //先发送一个标记:"1000"标记为传文件 + //D:\KSATProjects\2021-10-ASM\settings\SPI\Lanto_HTTP.INI + string eqpName = System.Text.RegularExpressions.Regex.IsMatch(path, "AOI") ? "AOI" : "SPI"; + 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; + } + /// + /// 接收消息 + /// + /// + private static void RecMsg(object socketClientPara) + { + Socket socketClient = socketClientPara as Socket; + while (true) + { + //定义一个接受用的缓存区(100M字节数组) + //byte[] arrMsgRec = new byte[1024 * 1024 * 100]; + //将接收到的数据存入arrMsgRec数组,并返回真正接受到的数据的长度 + if (socketClient.Connected) + { + try + { + //因为终端每次发送文件的最大缓冲区是512字节,所以每次接收也是定义为512字节 + byte[] _buf = new byte[25]; + byte[] buffer = new byte[512]; + int size = 0; + long len = 0; + string fileSavePath = @"D:\ServerDir";//获得用户保存文件的路径 + if (!Directory.Exists(fileSavePath)) + { + Directory.CreateDirectory(fileSavePath); + } + //有文件发送才创建新文件 + if (socketClient.Receive(_buf, 0, 25, SocketFlags.None) > 0) + { + //string recv = Encoding.Default.GetString(_buf); + //Console.WriteLine(socketClient.RemoteEndPoint + " 接收消息: " + DateTime.Now.ToString("yyyy:MM:dd HH:mm:ss:fff")); + string res = Encoding.Default.GetString(_buf); + string[] str = Regex.Split(res, "(&)"); + if (str[0] == "1000") + { + string fileName = fileSavePath + "\\" + str[2] + "\\" + str[4].TrimEnd('\0'); + //创建文件流,然后让文件流来根据路径创建一个文件 + FileStream fs = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.Write); + //从终端不停的接受数据,然后写入文件里面,只到接受到的数据为0为止,则中断连接 + + DateTime oTimeBegin = DateTime.Now; + + while ((size = socketClient.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; + Console.WriteLine("文件保存成功:" + fileName); + string store = (len / 1024.0) > 1.0 ? (len / 1024.0) + "kb" : len + "字节"; + Console.WriteLine("接收文件用时:" + oTime.ToString() + ",文件大小:" + store); + //Console.WriteLine(socketClient.RemoteEndPoint + "断开连接"); + //dict.Remove(socketClient.RemoteEndPoint.ToString()); + //socketClient.Close(); + } + else if (str[0].TrimEnd('\0') == "1001") + { + Net.SendData(socketClient, Encoding.Default.GetBytes("1001"), 1); + } + } + } + catch + { + + } + } + } + } + + } +} \ No newline at end of file diff --git a/TRI_TCP_Server/TRI_TCP_Server/Properties/AssemblyInfo.cs b/TRI_TCP_Server/TRI_TCP_Server/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..d9e187c --- /dev/null +++ b/TRI_TCP_Server/TRI_TCP_Server/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// 有关程序集的一般信息由以下 +// 控制。更改这些特性值可修改 +// 与程序集关联的信息。 +[assembly: AssemblyTitle("TRI_TCP_Server")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("TRI_TCP_Server")] +[assembly: AssemblyCopyright("Copyright © 2021")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// 将 ComVisible 设置为 false 会使此程序集中的类型 +//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型 +//请将此类型的 ComVisible 特性设置为 true。 +[assembly: ComVisible(false)] + +// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID +[assembly: Guid("7e709bf8-6665-405a-abfc-cb5b49c62db0")] + +// 程序集的版本信息由下列四个值组成: +// +// 主版本 +// 次版本 +// 生成号 +// 修订号 +// +//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值 +//通过使用 "*",如下所示: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/TRI_TCP_Server/TRI_TCP_Server/Run.cs b/TRI_TCP_Server/TRI_TCP_Server/Run.cs new file mode 100644 index 0000000..67cee31 --- /dev/null +++ b/TRI_TCP_Server/TRI_TCP_Server/Run.cs @@ -0,0 +1,199 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Net.Sockets; +using System.Net; +using System.IO; +using System.Text.RegularExpressions; + +namespace TRI_TCP_Server +{ + public class Run + { + //绑定本地IP + private static string Ip = "172.17.208.203"; + //绑定端口 + private static string Port = "5001"; + public static void Main(string[] args) + { + try + { + BeginListening(Ip, Port); + } + catch (Exception ex) + { + Console.WriteLine("监听服务器出错: " + ex.Message.ToString()); + } + + Console.ReadKey(); + } + + + private static Dictionary dict = new Dictionary(); + private static Thread threadWatch = null; + private static Socket socketWatch = null; + /// + /// 开始监听 + /// + /// + /// + public static void BeginListening(string localIp, string localPort) + { + + //创建服务端负责监听的套接字,参数(使用IPV4协议,使用流式连接,使用Tcp协议传输数据) + socketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + //获取Ip地址对象 + IPAddress address = IPAddress.Parse(localIp); + //创建包含Ip和port的网络节点对象 + IPEndPoint endpoint = new IPEndPoint(address, int.Parse(localPort)); + //将负责监听的套接字绑定到唯一的Ip和端口上 + socketWatch.Bind(endpoint); + //设置监听队列的长度 + socketWatch.Listen(10); + //创建负责监听的线程,并传入监听方法 + threadWatch = new Thread(WatchConnecting); + threadWatch.IsBackground = true;//设置为后台线程 + threadWatch.Start();//开始线程 + //ShowMgs("服务器启动监听成功"); + Console.WriteLine("服务器启动监听成功"); + } + + /// + /// 连接客户端 + /// + private static void WatchConnecting() + { + while (true) + { + //开始监听 客户端连接请求,注意:Accept方法,会阻断当前的线程 + Socket connection = socketWatch.Accept(); + if (connection.Connected) + { + //将与客户端通信的套接字对象connection添加到键值对集合中,并以客户端Ip做为健 + dict.Add(connection.RemoteEndPoint.ToString(), connection); + + //创建通信线程 + ParameterizedThreadStart pts = new ParameterizedThreadStart(RecMsg); + Thread thradRecMsg = new Thread(pts); + thradRecMsg.IsBackground = true; + thradRecMsg.Start(connection); + Console.WriteLine("客户端连接成功" + connection.RemoteEndPoint.ToString()); + + ParameterizedThreadStart pts1 = new ParameterizedThreadStart(test); + Thread thread1 = new Thread(pts1); + thread1.Start(connection); + } + } + } + + private static void test(object socketPara) + { + Socket socket = socketPara as Socket; + while (true) + { + Console.WriteLine("请输入回车"); + Console.ReadLine(); + Net.TCPSend(socket, @"D:\KSATProjects\2021-10-ASM\settings\SPI\Lanto_HTTP.INI", 512, 1); + Console.WriteLine("发送成功"); + } + } + + /// + /// 接收消息 + /// + /// + private static void RecMsg(object socketClientPara) + { + Socket socketClient = socketClientPara as Socket; + while (true) + { + //定义一个接受用的缓存区(100M字节数组) + //byte[] arrMsgRec = new byte[1024 * 1024 * 100]; + //将接收到的数据存入arrMsgRec数组,并返回真正接受到的数据的长度 + if (socketClient.Connected) + { + try + { + //因为终端每次发送文件的最大缓冲区是512字节,所以每次接收也是定义为512字节 + byte[] _buf = new byte[25]; + byte[] buffer = new byte[512]; + int size = 0; + long len = 0; + string fileSavePath = @"D:\ServerDir";//获得用户保存文件的路径 + if (!Directory.Exists(fileSavePath)) + { + Directory.CreateDirectory(fileSavePath); + } + //有文件发送才创建新文件 + if (socketClient.Receive(_buf, 0, 25, SocketFlags.None) > 0) + { + //string recv = Encoding.Default.GetString(_buf); + //Console.WriteLine(socketClient.RemoteEndPoint + " 接收消息: " + DateTime.Now.ToString("yyyy:MM:dd HH:mm:ss:fff")); + string res = Encoding.Default.GetString(_buf); + string[] str = Regex.Split(res, "(&)"); + if (str[0] == "1000") + { + string fileName = fileSavePath + "\\" + str[2] + "\\" + str[4].TrimEnd('\0'); + //创建文件流,然后让文件流来根据路径创建一个文件 + FileStream fs = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.Write); + //从终端不停的接受数据,然后写入文件里面,只到接受到的数据为0为止,则中断连接 + + DateTime oTimeBegin = DateTime.Now; + + while ((size = socketClient.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; + Console.WriteLine("文件保存成功:" + fileName); + string store = (len / 1024.0) > 1.0 ? (len / 1024.0) + "kb" : len + "字节"; + Console.WriteLine("接收文件用时:" + oTime.ToString() + ",文件大小:" + store); + //Console.WriteLine(socketClient.RemoteEndPoint + "断开连接"); + //dict.Remove(socketClient.RemoteEndPoint.ToString()); + //socketClient.Close(); + } + else if (str[0].TrimEnd('\0') == "1001") + { + Net.SendData(socketClient, Encoding.Default.GetBytes("1001"), 1); + } + } + } + catch + { + Console.WriteLine(socketClient.RemoteEndPoint + "下线了"); + dict.Remove(socketClient.RemoteEndPoint.ToString()); + break; + } + } + } + } + + /// + /// 关闭连接 + /// + public static void CloseTcpSocket() + { + dict.Clear(); + threadWatch.Abort(); + socketWatch.Close(); + Console.WriteLine("服务器关闭监听"); + } + } +} \ No newline at end of file diff --git a/TRI_TCP_Server/TRI_TCP_Server/TRI_TCP_Server.csproj b/TRI_TCP_Server/TRI_TCP_Server/TRI_TCP_Server.csproj new file mode 100644 index 0000000..ce2f46c --- /dev/null +++ b/TRI_TCP_Server/TRI_TCP_Server/TRI_TCP_Server.csproj @@ -0,0 +1,53 @@ + + + + + Debug + AnyCPU + {7E709BF8-6665-405A-ABFC-CB5B49C62DB0} + Exe + TRI_TCP_Server + TRI_TCP_Server + v4.5 + 512 + true + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file