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

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

客户端:
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数据
}
}

posted @ 2021-08-27 21:38  xuquanyi  阅读(120)  评论(0编辑  收藏  举报