跳到主要内容
版本:1.3.9

多线程文件传输

一、说明

多线程文件传输,顾名思义,就是多个连接链路,共同传输一个文件。

多线程传输的优点是什么?和常规文件传输相比,场景有哪些不同?

首先,常规文件传输是基于单个连接链路的,所以,单个连接的传输速率上限,就是常规传输的上限。一般来说,局域网当中,单个连接即可占满所有带宽,所以这时候多线程传输和常规传输并无差别。但是,在云服务器,或者在有流量均衡算法的网络中,每个连接的最大速率不是带宽的最大速率,那么这时候,两个差距是比较大的。

例如,我自己租的一个单核云服务器,它的单个连接速率只有1Mb,但是弹性带宽却有10Mb。宏观表象就是,一个客户端连接时,可以用1Mb带宽,两个客户端连接时,就可以用2Mb。那么这时候,多线程传输就显得格外重要了。

其次,多线程传输是无状态的,所以对于断线重连,换网重连等操作,是完全无感的。

二、使用

因为是多链路传输,所以,就必须建立多个客户端的连接到服务器。这里使用已经封装好的通信模型ClientFactory。

ClientFactory的通信模型使用的是一个主通信端+多个传输客户端。

对于客户端的配置,请详细参考创建TouchRpc客户端

private TcpTouchRpcClientFactory CreateClientFactory()
{
TcpTouchRpcClientFactory clientFactory = new TcpTouchRpcClientFactory()
{
MinCount = 5,
MaxCount = 10,
OnGetTransferConfig = () => //配置辅助通信
{
return new TouchSocketConfig()
.SetRemoteIPHost("tcp://127.0.0.1:7789");
}
};
clientFactory.MainConfig
.SetRemoteIPHost("tcp://127.0.0.1:7789");//配置主通信
return clientFactory;
}

【拉取文件】

TcpTouchRpcClientFactory clientFactory = CreateClientFactory();
var resultCon = clientFactory.CheckStatus();//检验主通信器连接状态。默认如果没有连接,则会建立。
if (resultCon.IsSuccess())
{
var fileOperator = new MultithreadingFileOperator()
{
ResourcePath = path,//请求资源路径
SavePath = savePath,//本地保存路径
};
//此处相当于Timer,每秒获取传输的速度和进度
LoopAction loopAction = LoopAction.CreateLoopAction(1000, (loop) =>
{
if (fileOperator.IsEnd)
{
loop.SafeDispose();
}

Console.WriteLine($"速度:{fileOperator.Speed()},进度:{fileOperator.Progress}");
});
_=loopAction.RunAsync();

Result result= await clientFactory.PullFileAsync(fileOperator);
if (result.IsSuccess())
{
MessageBox.Show(result.ToString());
}
}
else
{
MessageBox.Show(resultCon.ToString());
}

【推送文件】

TcpTouchRpcClientFactory clientFactory = CreateClientFactory();
var resultCon = clientFactory.CheckStatus();//检验主通信器连接状态。默认如果没有连接,则会建立。
if (resultCon.IsSuccess())
{
var fileOperator = new MultithreadingFileOperator()
{
ResourcePath = path,
SavePath = savePath,
};

//此处相当于Timer,每秒获取传输的速度和进度
LoopAction loopAction = LoopAction.CreateLoopAction(1000, (loop) =>
{
if (fileOperator.IsEnd)
{
loop.SafeDispose();
}

Console.WriteLine($"速度:{fileOperator.Speed()},进度:{fileOperator.Progress}");
});
_=loopAction.RunAsync();

Result result=await clientFactory.PushFileAsync(fileOperator);
if (result.IsSuccess())
{
MessageBox.Show(result.ToString());
}
}
else
{
MessageBox.Show(resultCon.ToString());
}

三、客户端之间传输文件

该功能也支持客户端之间互相传输。使用方法基本一致,需要额外指定目标Id,以及获取传输的Id集合即可。

多线程的客户端之间传输文件,不像其他操作类型那么简单。因为除了需要指定目的Id外,还需要指定获取目标Id的,传输客户端的Id集合,不然,获取数据的时候,仍然会是单线程工作的。

此外,服务器也需要同意路由

internal class MyTouchRpcPlugin : TouchRpcPluginBase
{
protected override void OnRouting(ITouchRpc client, PackageRouterEventArgs e)
{
if (e.RouterType== RouteType.PushFile||e.RouterType== RouteType.PullFile)
{
e.IsPermitOperation = true;
}
base.OnRouting(client, e);
}
}

【获取目标传输客户端的Id集合】 在TcpTouchRpcClientFactory属性中,有个OnFindTransferIds。通过实现该属性,使其能够获取到对应客户端的传输客户端Id集合(下列代码为模拟值,要具体实现该功能,还得自行实现)。

TcpTouchRpcClientFactory clientFactory = new TcpTouchRpcClientFactory()
{
MinCount = 5,
MaxCount = 10,
OnGetMainConfig = () =>//配置主通信
{
return new TouchSocketConfig()
.SetRemoteIPHost("tcp://127.0.0.1:7789")
.SetVerifyToken("FileService");
},
OnGetTransferConfig = () => //配置辅助通信
{
return new TouchSocketConfig()
.SetRemoteIPHost("tcp://127.0.0.1:7789")
.SetVerifyToken("FileService");
}
,
OnFindTransferIds = (client,targetId) =>
{
//此处的操作不唯一,可能需要rpc实现。
//其目的比较简单,就是获取到targetId对应的主客户端的所有传输客户端的Id集合。
//这样就实现了多个客户端向多个客户端传输文件的目的。

return new string[] { targetId};//此处为模拟结果。
}
};