Dmtp基础功能
定义
命名空间:TouchSocket.Dmtp
程序集:TouchSocket.Dmtp.dll
一、连接
连接验证可以初步保证连接客户端的安全性。框架内部默认使用一个string类型的Token作为验证凭证。当然也允许服务器进行其他验证。具体如下:
1.1 Token验证
在服务器或客户端的配置上,设置VerifyToken,即可实现字符串Token验证。
var config = new TouchSocketConfig()
.SetDmtpOption(new DmtpOption()
{
VerifyToken = "Dmtp"
});
1.2 动态验证
使用插件,实现IDmtpHandshakingPlugin插件。然后可以自行判断一些信息,比如:IP地址、元数据等。
设置元数据。
var config = new TouchSocketConfig()
.SetDmtpOption(new DmtpOption()
{
VerifyToken = "Dmtp",
Metadata=new Metadata().Add("a","a")
});
internal class MyVerifyPlugin : PluginBase,IDmtpHandshakingPlugin
{
public async Task OnDmtpHandshaking(IDmtpActorObject client, DmtpVerifyEventArgs e)
{
if (e.Metadata["a"] != "a")
{
e.IsPermitOperation = false;//不允许连接
e.Message = "元数据不对";//同时返回消息
e.Handled = true;//表示该消息已在此处处理。
return;
}
if (e.Token == "Dmtp")
{
e.IsPermitOperation = true;
e.Handled = true;
return;
}
await e.InvokeNext();
}
}
1.4 跨语言
为使Dmtp服务器支持跨语言,Dmtp在设计之初就预留了跨语言连接的便利性。诚如Dmtp描述所示,其基础数据报文为Flags+Length+Data
。而框架内部的Handshake、Ping、Pong、Close等指令均是采用Json数据格式。但是及时如此,连接时的真正数据,还与其基础协议有关。具体如下:
以连接、操作TcpDmtpService
为例。其基础协议即为tcp
,则使用常规的tcp
客户端即可模拟链接。
using var tcpClient = new TcpClient();//创建一个普通的tcp客户端 。
tcpClient.Received = (client, e) =>
{
//此处接收服务器返回的消息
var head = e.ByteBlock.ToArray(0,2);
e.ByteBlock.Seek(2, SeekOrigin.Begin);
var flags = e.ByteBlock.ReadUInt16(bigEndian: true);
var length = e.ByteBlock.ReadInt32(bigEndian: true);
var json = Encoding.UTF8.GetString(e.ByteBlock.Buffer, e.ByteBlock.Pos, e.ByteBlock.CanReadLen);
ConsoleLogger.Default.Info($"收到响应:flags={flags},length={length},json={json}");
return Task.CompletedTask;
};
//开始链接服务器
tcpClient.Connect("127.0.0.1:7789");
//以json的数据方式。
//其中Token、Metadata为连接的验证数据,分别为字符串、字符串字典类型。
//Id则表示指定的默认id,字符串类型。
//Sign为本次请求的序号,一般在连接时指定一个大于0的任意数字即可。
var json = @"{""Token"":""Dmtp"",""Metadata"":{""a"":""a""},""Id"":null,""Sign"":1}";
//将json转为utf-8编码。
var jsonBytes = Encoding.UTF8.GetBytes(json);
using (var byteBlock = new ByteBlock())
{
//按照Head+Flags+Length+Data的格式。
byteBlock.Write(Encoding.ASCII.GetBytes("dm"));
byteBlock.Write(TouchSocketBitConverter.BigEndian.GetBytes((ushort)1));
byteBlock.Write(TouchSocketBitConverter.BigEndian.GetBytes((int)jsonBytes.Length));
byteBlock.Write(jsonBytes);
tcpClient.Send(byteBlock);
}
await Task.Delay(2000);
接收输出:
收到的Json字符串,会返回服务器最终修改的Token、Metadata。同时还包括分配或指定的Id。Sign会与请求时一致,表示这是同一组请求。Status等于1即为连接成功。其他值则可能在Message表明连接失败的原因。
收到响应:flags=2,length=124,json={"Token":"Dmtp","Metadata":{"a":"a"},"Id":"1","Message":null,"Sign":1,"Status":1}
其他Json请求,包括:
【请求连接】
- Token:连接令牌,字符串类型。
- Metadata:连接元数据,字典类型。
- Id:初始连接Id,字符串类型。
- Sign:请求序号,整数类型,应当每次请求递增。
- Status(仅返回时携带):连接状态,整数类型,为1时成功,其他状态可以获取Message。
- Message(仅返回时携带):连接消息。
{"Token":"Dmtp","Metadata":{"a":"a"},"Id":null,"Sign":1}
【Ping】
- Sign:请求序号,整数类型,应当每次请求递增。
- Status(仅返回时携带):连接状态,整数类型,为1时成功,其他状态可以获取Message。
- Message(仅返回时携带):连接消息。
- Route:是否路由,布尔类型,当TargetId不为空时应设为True。
- SourceId:源Id,字符串类型,当需要Ping其他客户端时,应该将该值设为自身Id,以保证返回的信息能够顺利路由回来。
- TargetId:目标Id,字符串类型,当需要Ping其他客户端时,应该将该值设为目标Id,以保证信息能够顺利送达。
{"Sign":0,"Status":0,"Message":null,"Route":false,"SourceId":null,"TargetId":null}
【Close】
Close报文直接采用utf8编码的字符串。
"close"
DMTP基础功能是比较容易跨语言的,但这并不意味着DMTP所有的功能都支持。其扩展功能,则需要实际的跨平台设计。不过依靠简单的Head+Flags+Length+Data的格式,也能自己实现很多的功能。
二、Id同步
在Dmtp中,存在于服务器的辅助客户端(SocketClient),与远程客户端(Client)是一一对应关系,其Id也完全一致。所以在任意一方修改Id(调用ResetId),都会同时修改远程Id。所以合理使用该操作,可以完成复用Id(重置Id)的需求。
三、发送数据
Dmtp提供协议发送数据,又叫协议扩展功能,就是对现有的Dmtp进行自定义的扩展协议。
使用起来是非常简单的,每个DmtpActor,都实现了Send方法接口。
第一个参数为ushort类型,使用者可以约定任意大于20数值。
client.Send(1000,Encoding.UTF8.GetBytes("RRQM"));