d.多线程文件传输.mdx 6.0 KB
Newer Older
若汝棋茗 已提交
1
---
若汝棋茗 已提交
2 3 4 5
id: multithreadingfiletransfer
sidebar_position: 4
title: 多线程文件传输
sidebar_label: d.多线程文件传输
若汝棋茗 已提交
6 7
---

若汝棋茗 已提交
8

若汝棋茗 已提交
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
<a name="TXjhF"></a>

## 一、说明仅企业版

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

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

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

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

<a name="qLp3q"></a>

## 二、使用

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

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

对于客户端的配置,请详细参考[创建TouchRpc客户端](<..\7.3 创建TouchRpc客户端.md>)

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

    return clientFactory;
}
```

【拉取文件】

```csharp
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());
}

```

【推送文件】

```csharp
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());
}
```

<a name="SPTXq"></a>

## 三、客户端之间传输文件

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

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

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

```csharp
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集合(下列代码为模拟值,要具体实现该功能,还得自行实现)。

```csharp
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};//此处为模拟结果。
    }
};
```