6.3创建TcpClient.mdx 7.0 KB
Newer Older
若汝棋茗 已提交
1 2 3 4 5 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 184 185 186
---
id: createtcpclient
sidebar_position: 3
title: 创建TcpClient
sidebar_label: 6.3 创建TcpClient
---

## 一、说明
TcpClient是Tcp系客户端基类,他直接参与tcp的连接、发送、接收、处理、断开等,他的业务与服务器的**SocketClient**是一一对应的。

## 二、特点

- 简单易用。
- IOCP多线程。
- 内存池支持
- 高性能
- 适配器预处理,一键式解决**分包**、**粘包**、对象解析(如HTTP,Json)等。
- 超简单的同步发送、异步发送、接收等操作。
- 基于委托、插件驱动,让每一步都能执行AOP。

## 三、产品应用场景

- 所有Tcp基础使用场景:可跨平台、跨语言使用。
- 自定义协议解析场景:可解析任意数据格式的TCP数据报文。

## 四、客户端工作流程
![](https://cdn.nlark.com/yuque/0/2022/jpeg/25438888/1644495854071-a320a8b5-85ba-4563-a2fa-5bd573af850c.jpeg)


## 五、可配置项
| **属性名** | **属性描述** |
| --- | --- |
| SetBufferLength | 缓存池容量(单位:byte),默认1024*64。
设置建议:
1. 如果数据包较小,建议10k左右的值。更加节约内存。
2. 如果数据包较大,例如文件传输等,建议64k,甚至更大的值。
3. 该值虽然无上限,但是一般不要超过1Mb,不然不仅没意义,还很浪费
 |
| SetRemoteIPHost | 链接到的远程IPHost,支持域名。支持类型:
1. 使用IP&Port,传入形如:127.0.0.1:7789的字符串即可。
2. 使用域名,必须包含协议类型,形如:http://baidu.com或者https://baidu.com:80
 |
| SetReceiveType | 接收类型。
- AUTO:自动接收模式。
- None:不投递IO接收申请,用户可通过GetStream,获取到流以后,自己处理接收。注意:连接端不会感知主动断开。
 |
| UsePlugin | 是否启用插件。在启用时或许会带来一点点性能损耗,基本上不是千万数据交互根本不值一提。 |
| SetClientSslOption | Ssl配置,为Null时则不启用。
注意,当RemoteIPHost使用https、wss的域名时,该配置会使用系统默认配置生效。 |
| SetKeepAliveValue | 为Socket设置的属性。
注意:该配置仅在window平台生效。 |
| SetBindIPHost | 绑定端口。
- 在UdpSessionBase中表示本地监听地址
- 在TcpClient中表示固定客户端端口号。
 |
| SetMaxPackageSize | 数据包最大值,默认1024*1024*10。该值会在适当时间,直接作用于DataHandlingAdapter.MaxPackageSize属性。 |
| UseNoDelay | 设置Socket的NoDelay属性,默认false。 |
| UseDelaySender | 使用延迟[延迟缓存发送](https://www.yuque.com/rrqm/touchsocket/1f21a56ee75f896a5b5b38b37b071881#RL0kx)。 |
| UseReuseAddress | 启用端口复用。该配置可在服务器、或客户端在监听端口时,运行监听同一个端口。可以一定程度缓解端口来不及释放的问题 |

## 六、支持插件接口客户端、服务器均支持
声明自定义实例类,然后实现**ITcpPlugin**接口,即可实现下列事务的触发。
或者继承自**TcpPluginBase**类,重写相应方法即可。

| ###  ITcpPlugin
 |  |
| --- | --- |
| OnConnected | 客户端连接成功后触发 |
| OnConnecting | 在即将完成连接时触发。 |
| OnDisconnected | 会话断开后触发 |
| OnReceivedData | 在收到数据时触发 |
| OnSendingData | 当即将发送数据时,调用该方法在适配器之后,接下来即会发送数据。 |
| OnIDChanged | 当Client的ID被更改后触发 |

## 七、创建TcpClient
简单的处理逻辑可通过**Connecting**、**Connected**、**Received**等委托直接实现。

代码如下:
```csharp
TcpClient tcpClient = new TcpClient();
tcpClient.Connected += (client, e) => { };//成功连接到服务器
tcpClient.Disconnected += (client, e) => { };//从服务器断开连接,当连接不成功时不会触发。
tcpClient.Received += (client, byteBlock, requestInfo) =>
{
    //从服务器收到信息
    string mes = Encoding.UTF8.GetString(byteBlock.Buffer, 0, byteBlock.Len);
    Console.WriteLine($"接收到信息:{mes}");
};

//声明配置
TouchSocketConfig config = new TouchSocketConfig();
config.SetRemoteIPHost(new IPHost("127.0.0.1:7789"))
    .UsePlugin();

//载入配置
tcpClient.Setup(config);
tcpClient.Connect();
tcpClient.Send("RRQM");
```

## 八、接收数据
在TcpClient中,接收数据的方式有很多种。多种方式可以组合使用。

#### 8.1 Received委托处理
当使用TcpClient创建客户端时,内部已经定义好了一个外置委托Received,可以通过该委托直接接收数据。
```csharp
TcpClient tcpClient = new TcpClient();
tcpClient.Received += (client, byteBlock, requestInfo) =>
{
    //从服务器收到信息
    string mes = Encoding.UTF8.GetString(byteBlock.Buffer, 0, byteBlock.Len);
    Console.WriteLine($"接收到信息:{mes}");
};

//声明配置
TouchSocketConfig config = new TouchSocketConfig();
config.SetRemoteIPHost(new IPHost("127.0.0.1:7789"))
    .UsePlugin();

//载入配置
tcpClient.Setup(config);
tcpClient.Connect();
```

#### 8.2 插件处理推荐
按照TouchSocket的设计理念,使用插件处理数据,是一项非常简单,且高度解耦的方式。步骤如下:

1. 服务器配置启用插件(UsePlugin)
2. 新建插件类
3. 添加插件

代码如下:
(1)声明插件
```csharp
public class MyPlugin : TcpPluginBase<TcpClient>
{
    public MyPlugin()
    {
        this.Order = 0;//此值表示插件的执行顺序,当多个插件并存时,该值越大,越在前执行。
    }
   
    protected override void OnReceivedData(TcpClient client, ReceivedDataEventArgs e)
    {
        //这里处理数据接收
        //根据适配器类型,e.ByteBlock与e.RequestInfo会呈现不同的值,具体看文档=》适配器部分。
        ByteBlock byteBlock = e.ByteBlock;
        IRequestInfo requestInfo = e.RequestInfo;

        //e.Handled = true;//表示该数据已经被本插件处理,无需再投递到其他插件。
        base.OnReceivedData(client, e);
    }
}
```
(2)创建使用插件处理的客户端
```csharp
TcpClient client = new TcpClient();
client.Setup(new TouchSocketConfig()
    .SetRemoteIPHost(new IPHost("127.0.0.1:7789"))
    .UsePlugin()
    .ConfigureContainer(a=>
    {
        a.AddConsoleLogger();
    })
    .ConfigurePlugins(a => 
    {
        a.Add<MyPlugin>();
    }))
    .Connect();
```

## 九、发送数据
【同步发送】
TcpClient已经内置了三种同步发送方法,直接调用就可以发送,但需要注意的是,通过该方法发送的数据,会经过**适配器**,如果想要直接发送,请使用**DefaultSend**。如果发送失败,则会立即抛出异常。
```csharp
public virtual void Send(byte[] buffer);
public virtual void Send(ByteBlock byteBlock);
public virtual void Send(byte[] buffer, int offset, int length);
```

【异步发送】
TcpClient已经内置了三种异步发送方法,直接调用就可以发送。如果发送失败,await就会触发异常。
```csharp
public virtual Task SendAsync(byte[] buffer);
public virtual Task SendAsync(byte[] buffer, int offset, int length);
```