C# 实现获取及上传文件至服务器(远程控制开发一)

 使用C#开发一个类似向日葵的远程工具,想要远程生成及获取服务器的文件,就需要在服务器端运行一个执行程序,这个程序可以是桌面窗口类型、可以是控制台、也可以是Windows服务;现在我使用Windows服务的方式运行在服务器做为服务端执行命令的程序,而且服务运行可以做到自动重启。

一.创建服务

1.创建新项目>>Windows服务

C# 实现获取及上传文件至服务器(远程控制开发一)_第1张图片

2.下一步后可以自定义项目名称、项目生成位置、可以重命名,框架也可以选择最新的4.8,我这里先使用4.7.2,后期有需要也可以在项目属性里选择其他框架;

C# 实现获取及上传文件至服务器(远程控制开发一)_第2张图片

3.创建成功后会生成一个Service1.cs的类,可以修改名称,我将其改为“ManagerService.cs”,先添加服务安装程序,添加后会出现一个“serviceProcessInstaller1”的和一个“serviceInstaller1”,serviceProcessInstaller1的“Account”属性改为LocalSystem,这个表示服务以系统方式运行,serviceInstaller1的DelayedAutoStar属性改为True,这个让服务可以自动运行

C# 实现获取及上传文件至服务器(远程控制开发一)_第3张图片

4.以下是ManagerService.cs的完整代码:

using System.ServiceProcess;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.IO;
using System.Threading;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.Linq;
using System.Diagnostics;
using System;
using System.Threading.Tasks;
using System.IO.Compression;
namespace ManagerService
{
    public partial class ServiceMain : ServiceBase
    {
        private Thread listenerThread;
        private bool isRunning = true;
        private const int DiscoveryPort = 8888;
        private const int CommandPort = 8889;
        private string Serialize(object obj)
        {
            return JsonConvert.SerializeObject(obj);
        }

        private T Deserialize(string json)
        {
            return JsonConvert.DeserializeObject(json);
        }

        public ServiceMain()
        {
            ServiceLogger.Log($"系统字节序: {(BitConverter.IsLittleEndian ? "Little-Endian" : "Big-Endian")}");
            //InitializeComponent();
        }

        protected override void OnStart(string[] args)
        {
            EventLog.WriteEntry("ManagerService", "服务已启动,开始监听端口", EventLogEntryType.Information);
            listenerThread = new Thread(StartListening);
            listenerThread.IsBackground = true;
            listenerThread.Start();
        }

        private void StartListening()
        {
            // UDP发现监听
            new Thread(() =>
            {
                UdpClient udpServer = new UdpClient(DiscoveryPort);
                IPEndPoint remoteEp = new IPEndPoint(IPAddress.Any, 0);
                while (isRunning)
                {
                    byte[] data = udpServer.Receive(ref remoteEp);
                    if (Encoding.ASCII.GetString(data) == "DISCOVERY_REQUEST")
                    {
                        byte[] response = Encoding.ASCII.GetBytes("SERVICE_RESPONSE");
                        udpServer.Send(response, response.Length, remoteEp);
                    }
                }
            }).Start();

            // TCP命令监听
            TcpListener tcpListener = new TcpListener(IPAddress.Any, CommandPort);
            tcpListener.Start();
            while (isRunning)
            {
                TcpClient client = tcpListener.AcceptTcpClient();
                new Thread(() => HandleClient(client)).Start();
            }
        }

        private async void HandleClient(TcpClient client)
        {
            ServiceLogger.Log("=== 开始处理新客户端连接 ===");
            try
            {
                using (client)
                using (NetworkStream stream = client.GetStream())
                using (StreamReader reader = new StreamReader(stream, Encoding.UTF8, false, 1024, leaveOpen: true))
                using (StreamWriter writer = new StreamWriter(stream, Encoding.UTF8, 1024, leaveOpen: true))
                {
                    string command = await ReadCommandWithTimeout(reader, TimeSpan.FromSeconds(10));
                    if (string.IsNullOrEmpty(command)) return;

                    string[] commandParts = command.Split(new[] { '|' }, 2);
                    if (commandParts.Length != 2) return;

                    string operation = commandParts[0].Trim().ToUpper();
                    string path = commandParts[1].Trim();

                    switch (operation)
                    {
                        case "GET_DIR":
                            await HandleDirectoryRequest(writer, path);
                            break;
                        // 新增文件传输处理
                        case "UPLOAD":
                            await HandleFileUpload(stream, path);
                            break;
                        case "DOWNLOAD":
                            await HandleFileDownload(writer, path);
                            break;
                        default:
                            await SendErrorResponse(writer, $"不支持的操作: {operation}");
                            break;
                    }
                }
            }
            catch (Exception ex)
            {
                ServiceLogger.Log($"处理客户端异常: {ex.Message}");
            }
        }
        private async Task HandleFileUpload(NetworkStream stream, string savePath)
        {
            ServiceLogger.Log($"开始处理文件上传: {savePath}");
            try
            {
                if (!ValidatePath(savePath))
                {
                    ServiceLogger.Log($"非法路径:{savePath}");
                    return;
                }

                Directory.CreateDirectory(Path.GetDirectoryName(savePath));

                // 读取文件长度头
                byte[] lengthBytes = await ReadExactAsync(stream, 4);
                int fileLength = BitConverter.ToInt32(lengthBytes, 0);

                using (FileStream fs = File.Create(savePath))
                {
                    byte[] buffer = new byte[81920];
                    int totalRead = 0;

                    while (totalRead < fileLength)
                    {
                        int read = await stream.ReadAsync(buffer, 0,
                            Math.Min(buffer.Length, fileLength - totalRead));
                        await fs.WriteAsync(buffer, 0, read);
                        totalRead += read;

                        ServiceLogger.Log($"已接收 {totalRead}/{fileLength} 字节 ({(double)totalRead / fileLength:P0})");
                    }
                }
                // 在文件写入完成后添加成功响应
                byte[] successFlag = new byte[] { 0x01 };
                await stream.WriteAsync(successFlag, 0, 1);
                ServiceLogger.Log($"文件上传完成: {savePath} ({fileLength} 字节)");
            }
            catch (Exception ex)
            {
                ServiceLogger.Log($"文件上传失败: {ex.Message}");
                throw;
            }
        }

        // 新增文件下载处理方法
        private async Task HandleFileDownload(StreamWriter writer, string filePath)
        {
            ServiceLogger.Log($"开始处理文件下载: {filePath}");
            try
            {
                if (!File.Exists(filePath))
                {
                    await SendErrorResponse(writer, "文件不存在");
                    return;
                }

                using (FileStream fs = File.OpenRead(filePath))
                {
                    // 发送文件长度头
                    byte[] lengthHeader = BitConverter.GetBytes(fs.Length);
                    await writer.BaseStream.WriteAsync(lengthHeader, 0, 4);

                    // 发送文件内容
                    byte[] buffer = new byte[81920];
                    int bytesRead;
                    while ((bytesRead = await fs.ReadAsync(buffer, 0, buffer.Length)) > 0)
                    {
                        await writer.BaseStream.WriteAsync(buffer, 0, bytesRead);
                    }
                }
                ServiceLogger.Log($"文件发送完成: {filePath} ({new FileInfo(filePath).Length} 字节)");
            }
            catch (Exception ex)
            {
                await SendErrorResponse(writer, ex.Message);
                ServiceLogger.Log($"文件下载失败: {ex.Message}");
            }
        }
        // 添加辅助读取方法
        private async Task ReadExactAsync(NetworkStream stream, int count)
        {
            byte[] buffer = new byte[count];
            int totalRead = 0;
            while (totalRead < count)
            {
                int read = await stream.ReadAsync(buffer, totalRead, count - totalRead);
                if (read == 0) throw new EndOfStreamException();
                totalRead += read;
            }
            return buffer;
        }
        // 新增辅助方法:带超时的命令读取
        private async Task ReadCommandWithTimeout(StreamReader reader, TimeSpan timeout)
        {
            var readTask = reader.ReadLineAsync();
            var timeoutTask = Task.Delay(timeout);

            var completedTask = await Task.WhenAny(readTask, timeoutTask);
            if (completedTask == timeoutTask)
            {
                throw new System.TimeoutException("读取命令超时");
            }

            return await readTask;
        }
        private async Task HandleDirectoryRequest(StreamWriter writer, string requestPath)
        {
            ServiceLogger.Log($"=== 开始处理目录请求: {requestPath} ===");
            List responseEntries = new List();
            NetworkStream netStream = (NetworkStream)writer.BaseStream;

            try
            {
                // 记录原始请求路径
                ServiceLogger.Log($"原始请求路径: {requestPath}");
                // 处理驱动器列表请求
                if (requestPath == "[DRIVES]")
                {
                    DriveInfo.GetDrives()
                        .Where(d => d.IsReady)
                        .ToList()
                        .ForEach(drive =>
                        {
                            responseEntries.Add(new DirectoryEntry
                            {
                                Name = $"{drive.Name} ({drive.VolumeLabel})",
                                FullPath = drive.Name,
                                IsDirectory = true,
                                Size = drive.TotalSize
                            });
                        });
                    ServiceLogger.Log($"目录过滤前数量: {responseEntries.Count}");
                    foreach (var entry in responseEntries.Take(5))
                    {
                        ServiceLogger.Log($"[调试] 目录过滤前返回条目: {entry.Name} (路径: {entry.FullPath})");
                    }
                }

                // 处理普通目录请求
                else
                {
                    // 仅去除末尾分隔符(保留C:\)
                    string sanitizedPath = Path.GetFullPath(requestPath).Replace('/', '\\').TrimEnd(Path.DirectorySeparatorChar);

                    // ServiceLogger.Log($"消毒后路径: {sanitizedPath}");
                    // 特殊处理根目录请求
                    if (sanitizedPath.EndsWith(":") || sanitizedPath == "")
                    {
                        sanitizedPath += Path.DirectorySeparatorChar;
                    }
                    ServiceLogger.Log($"请求路径: {requestPath} → 消毒后路径: {sanitizedPath}");
                    var dirInfo = new DirectoryInfo(sanitizedPath);

                    if (!dirInfo.Exists)
                    {
                        ServiceLogger.Log($"路径不存在: {sanitizedPath}");
                        throw new DirectoryNotFoundException(sanitizedPath);
                    }
                    else
                    {
                        // 修改后的目录处理逻辑
                        foreach (var dir in dirInfo.GetDirectories("*", SearchOption.TopDirectoryOnly)
                            .Where(d =>
                                (d.Attributes & FileAttributes.System) == 0 &&
                                (d.Attributes & FileAttributes.Hidden) == 0 &&
                                !d.Name.Equals("

你可能感兴趣的:(C#开发远程控制工具,tcp/ip,服务器,网络协议,c#)