文件加密断点传输

文件加密传输,进度条,断点

客户端:
using System;
using System.Collections;
using System.Net;
using System.Net.Security;
using System.Net.Sockets;
using System.Security.Authentication;
using System.Text;
using System.Security.Cryptography.X509Certificates;
using System.Reflection;
using System.Threading;
using Newtonsoft.Json;
using System.IO;
using System.Windows.Forms;

namespace Client
{
public class SslTcpClient
{
private string caCertificate, serverName; //定义字符串
private int port;
private Client.UpdateMenuHandle updateMenuCallback; //声明委托方法
private Client.UpdateUI connectSuccessCallback, logCallback, disconnectCallback, downloadSuccessCallback;//声明委托方法
private Client.ExceptionHandle exceptionCallback;//声明委托方法
private Client.UpdateProcessBarHandle updateProcessBarHandle;//声明委托方法
private Thread clientThread; //声明多线程
private Mutex socketMutex; //声明线程锁
private bool is_downloading; //布尔类型

    private Semaphore semaphoreWaitFile; //限制线程数量
    private class DownloadCommand
    {
        public string filename;
        public int filestart;
        public bool is_download;
    }
    private DownloadCommand downloadCommand; 
    private string savaPath;
    public SslTcpClient(string caCertificate,
        string serverName, int port,
        Client.UpdateMenuHandle updateMenuCallback,
        Client.UpdateUI connectSuccessCallback,
        Client.UpdateUI disconnectCallback,
        Client.UpdateUI logCallback,
        Client.UpdateUI downloadSuccessCallback,
        Client.UpdateProcessBarHandle updateProcessBarHandle,
        Client.ExceptionHandle exceptionCallback)
    {
        this.caCertificate = caCertificate;
        this.serverName = serverName;
        this.port = port;
        this.updateMenuCallback = updateMenuCallback;
        this.connectSuccessCallback = connectSuccessCallback;
        this.disconnectCallback = disconnectCallback;
        this.logCallback = logCallback;
        this.downloadSuccessCallback = downloadSuccessCallback;
        this.updateProcessBarHandle = updateProcessBarHandle;
        this.exceptionCallback = exceptionCallback; //赋值
        this.clientThread = new Thread(new ThreadStart(RunClientFun)); //新开一个线程

        semaphoreWaitFile = new Semaphore(0, 1); //限制只能一个线程 最大并发数为1
    }
    private bool ValidateServerCertificate( //验证证书的函数
        object sender,                 //证书的调用
        X509Certificate certificate, //证书数据
        X509Chain chain, //证书链
        SslPolicyErrors sslPolicyErrors) //验证套接字
    {
        if (sslPolicyErrors == SslPolicyErrors.None)//没有套接字错误
            return true;

        Console.WriteLine("Certificate error: {0}", sslPolicyErrors);
        return false;
    }
    private X509Certificate LocalCertificateSelection(//加载证书的函数
        object sender,    //证书的调用者
        string targetHost, //目标主机
        X509CertificateCollection localCertificates, //加载证书数据
        X509Certificate remoteCertificate, //远程证书数据
        string[] acceptableIssuers)
    {
        return X509Certificate.CreateFromCertFile(caCertificate);//从文件加载证书数据
    }
    private void RunClientFun()//新的线程运行的函数
    {
        TcpClient client; //TCP连接

        try  
        {
            client = new TcpClient(serverName, port);//配置连接的属性
            connectSuccessCallback?.Invoke();//判断是否连接成功
            Console.WriteLine("Client connected.");
            SslStream sslStream = new SslStream(//证书流
                client.GetStream(),
                false,
                new RemoteCertificateValidationCallback(ValidateServerCertificate),//验证证书
                new LocalCertificateSelectionCallback(LocalCertificateSelection)//调用证书
                );
            try
            {
                sslStream.AuthenticateAsClient("localhost");//验证本地服务
            }
            catch (AuthenticationException e)//捕获错误信息的 网络连接出错的话 说明验证失败
            {
                Console.WriteLine("Exception: {0}", e.Message);
                if (e.InnerException != null)
                {
                    Console.WriteLine("Inner exception: {0}", e.InnerException.Message);
                }
                Console.WriteLine("Authentication failed - closing the connection.");
               
                client.Close();//关闭连接
                return;
            }
            string serverMessage = ReadMessage(sslStream);//从服务读取数据
            string[] fileList = JsonConvert.DeserializeObject<string[]>(serverMessage);//反序列化字符串json
            updateMenuCallback?.Invoke(fileList);//把fileList的数据传过去处理
            semaphoreWaitFile.WaitOne();//阻塞线程,等上面的执行完
            string jsonstr = JsonConvert.SerializeObject(downloadCommand);//序列化数据成json数据
            byte[] message = Encoding.UTF8.GetBytes(jsonstr);//把数据转成utf-8 的byte数组
            sslStream.Write(message);//写入数据
            sslStream.Flush();//结束写入
            if (downloadCommand.is_download == true) {//判断开始下载文件
                byte[] fileLengthArray = new byte[8];//申请内存
                sslStream.Read(fileLengthArray, 0, 8);//把数据读出来,读取8 个byte长度的数据
                long fileLength = System.BitConverter.ToInt64(fileLengthArray, 0);//获取文件数据的长度
                updateProcessBarHandle?.Invoke((int)Math.Round(100.0 * downloadCommand.filestart / fileLength));//把数据传到进度条显示
                FileStream fs;//文件流
                if (!File.Exists(this.savaPath))//判断文件不存在
                {
                    fs = File.Create(this.savaPath);//创建文件
                }
                else
                {
                    fs = File.OpenWrite(this.savaPath);//打开文件写入数据
                    fs.Seek(downloadCommand.filestart, SeekOrigin.Begin);//获取开始读取的长度
                }
                socketMutex = new Mutex();//这里添加一个线程锁
                is_downloading = true;
                byte[] buffer = new byte[1024]; //申请1024长度的缓存
                long receivedLength = downloadCommand.filestart;
                while (receivedLength < fileLength)//循环读取,每次读取1024
                {
                    socketMutex.WaitOne();//锁起来
                    int block = sslStream.Read(buffer, 0, 1024);//开始读数据
                    socketMutex.ReleaseMutex();//解锁
                    if (block > 0)//如果数据满足1024
                    {
                        fs.Write(buffer, 0, block);//把数据写进去
                        updateProcessBarHandle?.Invoke((int)Math.Round(100.0 * receivedLength / fileLength));//更新进度条
                        receivedLength += block;//数据递增
                    }
                }
                updateProcessBarHandle?.Invoke(100);//下载完毕更新进度条的显示到100%
                fs.Flush();//关闭文件流
                fs.Close();//关闭文件
                socketMutex.Close();//取消线程锁
                downloadSuccessCallback?.Invoke();//返回已经下载完成的信息
                MessageBox.Show("文件下载完成", "提示");
            }
            else//上传文件
            {
                string downloadCommand1Json = ReadMessage(sslStream);//从服务里读数据
                DownloadCommand downloadCommand1 = JsonConvert.DeserializeObject<DownloadCommand>(downloadCommand1Json);//反序列化字符串json
                FileStream fs = File.OpenRead(Path.Combine(this.savaPath, downloadCommand1.filename));//打开文件读取内容
                byte[] sizeArray = System.BitConverter.GetBytes(fs.Length);//获取文件长度
                sslStream.Write(sizeArray);//开始写入长度信息
                sslStream.Flush();//关闭流
                fs.Seek(downloadCommand1.filestart, SeekOrigin.Begin);//开始读取文件数据
                updateProcessBarHandle?.Invoke(0);//更新进度条为0
                socketMutex = new Mutex();//申请线程锁
                is_downloading = true;
                int length;
                byte[] buffer = new byte[1024];//申请1024长度的缓存
                do
                {
                    socketMutex.WaitOne();//锁起来
                    length = fs.Read(buffer, 0, 1024);//开始读数据 1024长度
                    socketMutex.ReleaseMutex();//解锁
                    sslStream.Write(buffer, 0, length);//把数据写到服务流去
                    updateProcessBarHandle?.Invoke((int)Math.Round(100.0 * fs.Seek(0,SeekOrigin.Current) / fs.Length));//更新进度条
                } while (length > 0);
                sslStream.Flush();//关闭服务流
                fs.Close();//关闭文件
                socketMutex.Close();//取消锁
                downloadSuccessCallback?.Invoke();//返回已经上传完毕
                MessageBox.Show("文件上传完成", "提示");//提示出来
            }
            sslStream.Close();//关闭服务
            client.Close();//关闭连接
        }
        catch (Exception e)
        {
            exceptionCallback?.Invoke(e);//出错信息返回
        }
    }
    public void Upload(string path)//上传文件函数
    {
        downloadCommand = new DownloadCommand();
        downloadCommand.filename = Path.GetFileName(path);//获取文件名
        downloadCommand.filestart = 0;//从文件头开始读
        downloadCommand.is_download = false;
        this.savaPath = Path.GetDirectoryName(path);//获取文件路径
        semaphoreWaitFile.Release();//线程启动 最多只能一个线程
    }
    public void Download(string name, string savaPath, int start=0)//下载文件
    {
        downloadCommand = new DownloadCommand();
        downloadCommand.filename = name;
        downloadCommand.filestart = start;
        downloadCommand.is_download = true;

        this.savaPath = savaPath;
        semaphoreWaitFile.Release();//线程启动 最多只能一个线程
    }
    public void Pause()//暂停
    {
        if (socketMutex != null)//先判断线程锁是否存在
        {
            if (is_downloading)//如果正在下载
            {
                socketMutex.WaitOne();//加锁
                is_downloading = false;
                MessageBox.Show("传输已暂停", "提示");//弹出提示
            }
            else
            {
                socketMutex.ReleaseMutex();//解锁
                is_downloading = true;
                MessageBox.Show("传输已恢复", "提示");
            }
        }
    }
    public void RunClient()//服务启动函数
    {
        clientThread.Start();//启动线程
    }
    public void DisconnectClient()//断开连接
    {
        clientThread.Abort();//停止线程
    }
    private static string ReadMessage(SslStream sslStream)//从服务流里读取数据
    {
        byte[] buffer = new byte[2048];//每次读取2048
        StringBuilder messageData = new StringBuilder();//可以自动控制大小
        int bytes;
        do
        {
            bytes = sslStream.Read(buffer, 0, buffer.Length);//开始读取数据
            Decoder decoder = Encoding.UTF8.GetDecoder();//转成utf-8
            char[] chars = new char[decoder.GetCharCount(buffer, 0, bytes)];//开始读取数据
            decoder.GetChars(buffer, 0, bytes, chars, 0);//转成char 数据
            messageData.Append(chars);//拼接数据
            if (messageData.ToString().IndexOf("") != -1)//判断是不是已经写入数据了
            {
                break;
            }
        }
        while (bytes != 0);
        return messageData.ToString();//返回string数据
    }
}

}

服务器端:
using System;
using System.Net;
using System.Net.Sockets;
using System.Net.Security;
using System.Text;
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;
using System.Threading;
using System.Reflection;
using System.Collections.Generic;
using System.IO;
using Newtonsoft.Json;
using System.Reflection.Emit;

namespace Server
{
public sealed class SslTcpServer
{
private X509Certificate serverCertificate = null; //声明证书数据
private TcpListener listener; //声明网络监听服务
private Thread process_thread; //声明一个线程
private Server.UpdateUI startCallback, stopCallback;//声明委托方法
private Server.ExceptionHandle exceptionCallback;//声明委托方法
private Server.LogHandle logCallback;//声明委托方法
private string[] fileLists; //字符串数组
private string prefixPath;

    private class DownloadCommand
    {
        public string filename;
        public int filestart;
        public bool is_download;
    }
    private DownloadCommand receivedCommand;  

    public SslTcpServer(string certificate, int port, 
        string prefixPath,
        string[] fileLists,
        Server.UpdateUI startCallback, 
        Server.UpdateUI stopCallback, 
        Server.ExceptionHandle exceptionCallback, 
        Server.LogHandle logCallback)
    {                                  
        serverCertificate = X509Certificate.CreateFromCertFile(certificate);
        listener = new TcpListener(IPAddress.Any, port);
        this.prefixPath = prefixPath;
        this.fileLists = fileLists;
        this.startCallback = startCallback;
        this.stopCallback = stopCallback;
        this.exceptionCallback = exceptionCallback;
        this.logCallback = logCallback; 
    }

    private void ProcessFun()//启动服务线程
    {
        try
        {
            logCallback?.Invoke("服务器已启动,等待客户端连接...");
            while (true)//一直循环监听
            {
                if (listener.Pending())
                {
                    TcpClient client = listener.AcceptTcpClient();
                    ProcessClient(client);
                }
                else
                {
                    Thread.Sleep(200);
                }
            }
        }
        catch(Exception e)
        {
            exceptionCallback?.Invoke(e);
        }
    }

    public void ServerStart()//开始启动服务
    {
        try
        {
            listener.Start();
            process_thread = new Thread(new ThreadStart(ProcessFun));//开辟线程
            process_thread.Start();
            startCallback?.Invoke();//返回已经启动服务的信息
        }
        catch(Exception e)
        {
            exceptionCallback?.Invoke(e);
        }
    }
    public void ServerAbort()//关闭服务
    {
        process_thread.Abort();//关闭线程
        listener.Stop();//停止监听
        stopCallback?.Invoke();//返回停止监听的信息
        logCallback?.Invoke("服务器已关闭");
    }
    void ProcessClient(TcpClient client)//处理连接的信息
    {
        logCallback?.Invoke("一个客户端已连接");
        SslStream sslStream = new SslStream(client.GetStream(), false);//从服务流里面读数据
        try
        {
            sslStream.AuthenticateAsServer(serverCertificate,
                false, SslProtocols.Tls12, false);//调用证书 解析

            //sslStream.ReadTimeout = 5000;
            //sslStream.WriteTimeout = 5000;
            logCallback?.Invoke("构建共享目录文件列表...");
            string fileListsJson = JsonConvert.SerializeObject(fileLists);//序列化数据成json数据
            logCallback?.Invoke(fileListsJson);
            byte[] message = Encoding.UTF8.GetBytes(fileListsJson);//把数据转成utf-8 的byte数组
            logCallback?.Invoke("正在发送文件列表...");
            sslStream.Write(message);//写入数据
            sslStream.Flush();//结束写入
            logCallback?.Invoke("文件列表发送完成,等待进一步指令...");
            string command = ReadMessage(sslStream);
            receivedCommand = JsonConvert.DeserializeObject<DownloadCommand>(command);
            logCallback?.Invoke("收到指令: " + command);
            string wholePath = Path.Combine(prefixPath, receivedCommand.filename);//获取文件名
            if (receivedCommand.is_download == true)//判断开始下载文件
            {
                if (File.Exists(wholePath))//判断文件存在
                {
                    logCallback?.Invoke("文件开始传输:" + wholePath);
                    FileStream fs = File.OpenRead(wholePath);//文件流
                    byte[] sizeArray = System.BitConverter.GetBytes(fs.Length);//获取文件长度
                    fs.Seek(receivedCommand.filestart, SeekOrigin.Begin);//开始读取文件数据
                    sslStream.Write(sizeArray);//开始写入长度信息
                    sslStream.Flush();//关闭流
                    int length;
                    byte[] buffer = new byte[1024];//申请1024长度的缓存
                    do
                    {
                        length = fs.Read(buffer, 0, 1024);//开始读数据 1024长度
                        sslStream.Write(buffer, 0, length);//把数据写到服务流去
                    } while (length > 0);
                    fs.Close();//关闭文件
                    sslStream.Flush();//关闭服务流
                    logCallback?.Invoke("文件传输完毕:");
                }
                else
                {
                    logCallback?.Invoke("请求的文件不存在:" + wholePath);
                }
            }
            else//上传文件
            {
                FileStream fs;
                DownloadCommand command1 = new DownloadCommand();
                command1.filename = receivedCommand.filename;//获取文件名
                command1.is_download = false;
                if (File.Exists(wholePath))//判断文件存在
                {
                    fs = File.OpenWrite(wholePath);//打开文件
                    fs.Seek(0, SeekOrigin.End);//读取文件长度
                    command1.filestart = (int)fs.Length;//写入长度
                }
                else//不存在则创建文件夹
                {
                    command1.filestart = 0;
                    fs = File.Create(wholePath);
                }
                string command1Json = JsonConvert.SerializeObject(command1);//序列化字符串json
                message = Encoding.UTF8.GetBytes(command1Json);//把数据转成utf-8 的byte数组
                sslStream.Write(message);//写入数据
                sslStream.Flush();//结束写入
                logCallback?.Invoke("已发送回应:指定从文件的第" + command1.filestart.ToString() + "字节开始下载");

                byte[] sizeArray = new byte[8];//申请内存
                sslStream.Read(sizeArray, 0, 8);//把数据读出来,读取8 个byte长度的数据
                long fileLength = System.BitConverter.ToInt64(sizeArray, 0);//文件总大小
                logCallback?.Invoke("文件总大小:" + fileLength.ToString() + "字节");
                logCallback?.Invoke("文件开始接收:" + wholePath);
                byte[] buffer = new byte[1024]; //申请1024长度的缓存
                long receivedLength = command1.filestart;
                while (receivedLength < fileLength)//循环读取,每次读取1024
                {
                    int block = sslStream.Read(buffer, 0, 1024);
                    if (block > 0)
                    {
                        fs.Write(buffer, 0, block);//把数据写进去
                        receivedLength += block;//数据递增
                    }
                }
                logCallback?.Invoke("文件传输完成:" + wholePath);
                fs.Flush();//关闭文件流
                fs.Close();//关闭文件
            }
        }
        catch (AuthenticationException e){//用来捕获错误信息 
            logCallback?.Invoke("Exception: " + e.Message);
            if (e.InnerException != null)
            {
                logCallback?.Invoke("Inner exception: " + e.InnerException.Message);
            }
            logCallback?.Invoke("身份认证失败 - 正在关闭连接...");
            sslStream.Close();//关闭服务流
            client.Close();//关闭连接
            return;
        }
        finally
        {
            sslStream.Close();
            client.Close();
        }
        sslStream.Close();
        client.Close();
    }
    string ReadMessage(SslStream sslStream)//从服务流里读取数据
    {
        byte[] buffer = new byte[2048];//每次读取2048
        StringBuilder messageData = new StringBuilder();//可以自动控制大小
        Decoder decoder = Encoding.UTF8.GetDecoder();//转成utf-8
        int bytes;
        do
        {
            bytes = sslStream.Read(buffer, 0, buffer.Length);//开始读取数据
            char[] chars = new char[decoder.GetCharCount(buffer, 0, bytes)];//转成char 数据
            decoder.GetChars(buffer, 0, bytes, chars, 0);
            messageData.Append(chars);//拼接数据
            if (messageData.ToString().IndexOf("") != -1)//判断是否已经写入数据
            {
                break;
            }
        }
        while (bytes != 0);

        return messageData.ToString();//返回string数据
    }
}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值