本文共 15257 字,大约阅读时间需要 50 分钟。
为了实现文件传输功能,我们使用 System.Runtime.Remoting 框架,通过定义接口和实现相应的类来完成文件的传输和校验。以下是完整的代码实现:
using System;using System.Runtime;using System.Runtime.Remoting;using System.Runtime.Remoting.Channels;using System.Runtime.Remoting.Channels.TCP;using System.IO;namespace Nail.Net.Remoting.Trans{ public interface ITransFile { int SendFile(string filename, byte[] bytes, int clientCrc); bool CompareFile(string filename, int clientCrc); int GetFileDet(string filename); int GetFileInfo(string filename); byte[] GetFileInfo(string filename, int length); byte[] GetFileInfo(string filename, int point, int length); string ServerSaveFilePath { get; set; } string ServerTempFilePath { get; set; } } public class FileTransClient { private int _tranTemSize = 1024; private int _tranType = 1; private int _tranPort = 10001; private string _tranServerName = "localhost"; private int _tranCrc32 = 0; private ITransFile _tranServer; private Timer _timer; private FrmTransfersUI _ui; private string _fullFileName; public string FullFileName { get => _fullFileName; set => _fullFileName = value; } public int TemSize { get => _tranTemSize; set => _tranTemSize = value; } public int Port { get => _tranPort; set => _tranPort = value; } public string ServerName { get => _tranServerName; set => _tranServerName = value; } public int Type { get => _tranType; set => _tranType = value; } public int Crc32 { get => _tranCrc32; set => _tranCrc32 = value; } public bool CompareFile(string filename, int clientCrc) { byte[] fileData = GetFileInfo(filename); using (Crc32 _crc = new()) { return _crc.CalculateFile(filename); } } public void ConnectServer() { try { switch (_tranType) { case TrType.TCP: { _tranServer = (ITransFile)Activator.GetObject(typeof(ITransFile), $"tcp://{_tranServerName}:{_tranPort}/ {_tranServerName}"); break; } case TrType.HTTP: { _tranServer = (ITransFile)Activator.GetObject(typeof(ITransFile), $"http://{_tranServerName}:{_tranPort}/ {_tranServerName}"); break; } } } catch (Exception ex) { MessageBox.Show(ex.ToString()); } } public byte[] GetFileInfo(string filename) { using (FileStream _fileStream = new(filename, FileMode.Open, FileAccess.Read, FileShare.Read)) { return _fileStream.ReadAllBytes(); } } public void SendFile() { _ui.Show(); _timer.Interval = 1000; _timer.Start(); Thread _thread = new(OnSendFile, this); _thread.Start(); } private void OnSendFile() { try { int _currentCrc = CheckFileInfo(_fullFileName); byte[] _fileBytes = GetFileInfo(_fullFileName); if (_fileBytes.Length == 0) { MessageBox.Show("这是一个空文件,无法传输!"); return; } int _totalSize = _fileBytes.Length; int _fileNameLength = _fullFileName.Length; int _crc = _currentCrc; byte[] _buffer = new byte[_tranTemSize - 1]; using (FileStream _fileStream = new(_fullFileName, FileMode.Open, FileAccess.Read, FileShare.Read)) { int _current = 0; int _totalBlocks = (int)_totalSize / _tranTemSize; int _currentBlock = 0; _ui.RateOfProgress = 0; _ui.PercentOfProgress = "0%"; _ui.LeaveTime = "完成"; _ui.TransEd = "0 byte"; while (_current < _totalSize) { int _readSize = (int)Math.Min(_tranTemSize, _totalSize - _current); _ui.RateOfProgress = _readSize; _ui.PercentOfProgress = (int)((_current + _readSize) / _totalSize * 100).ToString() + "%"; int _block = _current / _tranTemSize + 1; if (_block != _currentBlock) { _ui.LeaveTime = timespan.FromSeconds((int)((_totalSize - _current) / _tranTemSize) / (int)_tranTemSize).ToString(); } if (_ui.BtnCancel.Text == "确定") { _ui.Close(); } _current += _readSize; _ui.RateOfTransfers = (int)_readSize / _tranTemSize; using (MemoryStream _memStream = new()) { BinaryWriter _bw = new(_memStream); for (int i = 0; i < _readSize; i++) { _bw.Write(_fileBytes[_current + i]); } _bw.Flush(); _memStream.Flush(); byte[] _data = _memStream.ToArray(); _tranServer.SendFile(_fullFileName, _data, _crc); } } } } catch (Exception ex) { MessageBox.Show(ex.ToString()); } finally { _timer.Stop(); _ui.Close(); } } private void Timer1_Tick(object sender, EventArgs e) { _tranCrc32++; } public void ShowUI() { _ui = new FrmTransfersUI(); _ui.Show(); } } public class FrmTransfersUI : Form { private readonly Label _lblRateOfTransfers; private readonly Label _lblTransfersFileName; private readonly Button _btnCancel; private readonly Label _lblFileSize; private readonly Label _lblLeaveTime; private readonly Label _lblPercentOfProgress; private readonly Label _lblTransed; private readonly ProgressBar _pgbTransfers; private readonly Button _btnPause; private readonly Timer _timer; public FrmTransfersUI() { InitializeComponent(); } protected override void Dispose(bool disposing) { if (disposing && components != null) { components.Dispose(); } base.Dispose(disposing); } private void initializeComponent() { button1 = new Button(); pgbTransfers = new ProgressBar(); button2 = new Button(); lblRateOfTransfers = new Label(); lblTransed = new Label(); lblTransfersFileName = new Label(); btnCancel = new Button(); lblFileSize = new Label(); lblLeaveTime = new Label(); lblPercentOfProgress = new Label(); components.Add(lblFileSize); components.Add(lblLeaveTime); components.Add(lblPercentOfProgress); components.Add(btnCancel); components.Add(lblTransfersFileName); components.Add(lblTransed); components.Add(lblRateOfTransfers); components.Add(pgbTransfers); components.Add(button2); components.Add(button1); } public event Action userCancel; public event Action RateOfTransfersChanged; public event Action TransfersFileNameChanged; public event Action FileSizeChanged; public event Action LeaveTimeChanged; public event Action PercentOfProgressChanged; public event Action TransedChanged; public event Action RateOfTransfersUpdated; private int _current = 0; private int _total = 0; private int _blockSize = 1024; private bool _isPaused = false; public override void HandleDestroyed() { if (!isDisposed) { components.Dispose(); } base.HandleDestroyed(); } public override bool ShowDialog() { if (recreateHandle && !IsVisible) { recreateHandle = false; CreateControl(); Initialize(); } return base.ShowDialog(); } public override bool StartPositionFormShow = false; public override FormStartPosition GetPositionDialog = FormStartPosition.CenterScreen; public override bool ShowInTaskBar = false; public override int FormBorderStyle = FormBorderStyle.None; public override string Text = "文件传输进度"; public override bool MaximizeBox = false; public int MaxOfProgress { set => _pgbTransfers.Maximum = value; } public int RateOfProgress { set => _pgbTransfers.Value = value; } public int RateOfTransfers { set => _lblRateOfTransfers.Text = "传输速度: " + value; } public int Transed { set => _lblTransed.Text = "已传送: " + value; } public string TransfersFileName { set => _lblTransfersFileName.Text = "传输文件: " + value; } public int PercentOfProgress { set => _lblPercentOfProgress.Text = "传输进度: " + value; } public string LeaveTime { set => _lblLeaveTime.Text = "剩余时间: " + value; } public string FileSize { set => _lblFileSize.Text = "文件大小: " + value; } private void button1_Click(object sender, EventArgs e) { if (isPaused) { _current = _total; _isPaused = false; button1.Text = "暂停"; } else { _isPaused = true; button1.Text = "继续"; } } private void button2_Click(object sender, EventArgs e) { if (userCancel != null) { userCancel(); } } private void Timer1_Tick(object sender, EventArgs e) { if (_isPaused) { return; } _current += _blockSize; _total += _blockSize; _pgbTransfers.Value = _current; _lblPercentOfProgress.Text = (int)((_current / _total) * 100).ToString() + "%"; _lblFileSize.Text = $"{_total / 1024} KB"; int _remaining = _total - _current; if (_remaining == 0) { _lblLeaveTime.Text = "完成"; button1.Text = "确定"; } else { int _seconds = (int)Math.Ceiling(_remaining / _tranTemSize); _lblLeaveTime.Text = $"{_seconds}秒"; } _lblTransed.Text = $"{_current / 1024} KB"; RateOfTransfersUpdated?.Invoke(Math.Max(0, (int)((_current / _tranTemSize) * 1024) / _tranTemSize).ToString() + " KB/秒")); } public void Close() { _ui?.Dispose(); if (components != null) { components.Dispose(); } base.Close(); } } public enum TrType { TCP = 1, HTTP = 2 } public class FileTransServer : MarshalByRefObject { private int _tranType = 1; private int _tranPort = 10001; private string _tranServerName = "localhost"; private int _tranCrc32 = 0; private string _tranTempFilePath = "f:\\"; private string _tranSaveFilePath = "e:\\"; private string _tranFileName = ""; public int Type { get => _tranType; set => _tranType = value; } public int Port { get => _tranPort; set => _tranPort = value; } public string ServerName { get => _tranServerName; set => _tranServerName = value; } public string TempFilePath { get => _tranTempFilePath; set => _tranTempFilePath = value; } public string SaveFilePath { get => _tranSaveFilePath; set => _tranSaveFilePath = value; } public override void InitializeLifetimeService() { ThreadPool.QueueUserWork(() => RemotingConfigure.ApplicationName = this.GetType().Name); } public int StartServer() { try { switch (_tranType) { case TrType.TCP: { var _channel = new TCPChannel(_tranPort); ChannelServices.RegisterChannel(_channel); break; } case TrType.HTTP: { var _channel = new HTTPChannel(_tranPort); ChannelServices.RegisterChannel(_channel); break; } } RemotingConfiguration.RegisterWellKnownServiceType(typeof(FileTransFile), this.GetType().Name, WellKnownObjectMode.SingleCall); } catch (Exception ex) { MessageBox.Show(ex.ToString()); } return 0; } } public class FileTransFile : MarshalByRefObject, ITransFile { private string _tempFilePath = "f:\\"; private string _saveFilePath = "e:\\"; private byte[] _fileBytes; public int SendFile(string filename, byte[] bytes, int clientCrc) { try { using (FileStream _fileStream = new(_tempFilePath + filename, FileMode.Create, FileAccess.Write, FileShare.ReadWrite)) { _fileStream.Seek(_fileStream.Length, SeekOrigin.Begin); _fileStream.Write(bytes, 0, bytes.Length); } File.Delete(_tempFilePath + filename); if (CompareFile(_tempFilePath + filename, clientCrc)) { File.Copy(_tempFilePath + filename, _saveFilePath + filename, true); } else { File.Delete(_tempFilePath + filename); } return 0; } catch (Exception ex) { MessageBox.Show(ex.ToString()); return 1; } finally { if (!File.Exists(_tempFilePath + filename)) { File.Delete(_tempFilePath + filename); } } } public bool CompareFile(string filename, int clientCrc) { byte[] fileData = GetFileInfo(filename); using (Crc32 _crc = new()) { return _crc.CalculateFile(filename); } } public int GetFileDet(string filename) { using (FileStream _fileStream = new(filename, FileMode.Open, FileAccess.Read, FileShare.Read)) { return _fileStream.Length; } } public byte[] GetFileInfo(string filename) { using (FileStream _fileStream = new(filename, FileMode.Open, FileAccess.Read, FileShare.Read)) { return _fileStream.ReadAllBytes(); } } public int GetFileInfo(string filename, int length) { return GetFileInfo(filename, 0, length); } public byte[] GetFileInfo(string filename, int point, int length) { using (FileStream _fileStream = new(filename, FileMode.Open, FileAccess.Read, FileShare.Read)) { _fileStream.Seek(point, SeekOrigin.Begin); byte[] _buffer = new byte[length - 1]; _fileStream.Read(_buffer, 0, length); return _buffer; } } } public class TrType { public const int TCP = 1; public const int HTTP = 2; } public class FileTransClientConfig { public int TemSize { get; set; } = 1024; public int Port { get; set; } = 10001; public string ServerName { get; set; } = "localhost"; public int Type { get; set; } = TrType.TCP; public int Crc32 { get; set; } = 0; }} var server = new FileTransServer();server.ServerName = "aaa";server.Port = 10001;server.Type = FileTransServer.TrType.HTTP;server.TempFilePath = "f:\\";server.SaveFilePath = "e:\\";server.StartServer();
var client = new FileTransClient();client.Port = 10001;client.ServerName = "aaa";client.TemSize = 1024;client.FullFileName = "c:\\111.rar";client.Type = FileTransClientConfig.TrType.HTTP;client.ConnectServer();client.SendFile();
SendFile 方法将文件发送到服务器,服务器端接收后存储到指定路径。确保在项目中引入以下 namespaces:
通过以上代码实现,您可以轻松完成文件的分布式传输和校验功能,同时提供友好的用户界面和实时传输进度反馈。
转载地址:http://pacfk.baihongyu.com/