SuperSocket 2.0 客户端通信实现
在 SuperSocket 2.0 中,客户端通信可以通过 SuperSocket.Client 实现。以下是具体的实现步骤和代码示例。
1. 报文结构解析
SuperSocket 使用 StringPackageInfo 类来定义报文结构:
public class StringPackageInfo : IKeyedPackageInfo<string>, IStringPackage
{
public string Key { get; set; }
public string Body { get; set; }
public string[] Parameters { get; set; }
}
报文中的参数以空格分隔,例如 "ADD 1 2" 表示 Key 为 "ADD",Parameters 包含 "1" 和 "2"。
2. 分段标记要求
使用 CommandLinePipelineFilter 时,必须在报文末尾添加 \r\n(即 Environment.NewLine)作为分段标记。缺少该标记可能导致服务器无法正确解析数据。
3. 启动 Telnet 示例服务端
以下代码展示了一个简单的 Telnet 服务端实现:
var host = SuperSocketHostBuilder
.Create<StringPackageInfo, CommandLinePipelineFilter>()
.UsePackageHandler(async (session, package) =>
{
await session.SendAsync(Encoding.UTF8.GetBytes($"{package.Key} ADD 1 2{Environment.NewLine}"));
})
.ConfigureSuperSocket(options =>
{
options.Name = "Echo Server";
options.Listeners = new List<ListenOptions>
{
new ListenOptions
{
Ip = "Any",
Port = 4040
}
};
}).Build();
await host.RunAsync();
此服务端监听端口 4040,并对每个请求返回格式化的响应。
4. 客户端交互实现
通过 SuperSocket.Client 实现客户端通信:
添加依赖
首先,在项目中添加 SuperSocket.Client 的 NuGet 包:
<PackageReference Include="SuperSocket.Client" Version="2.0.1" />
客户端代码
以下是一个完整的客户端实现:
var easyClient = new EasyClient<StringPackageInfo>(new CommandLinePipelineFilter()
{
Decoder = new DefaultStringPackageDecoder()
});
var client = easyClient.AsClient();
var ipAddress = IPAddress.Loopback;
var port = 4040;
var ipEndPoint = new IPEndPoint(ipAddress, port);
// 连接到服务端
await client.ConnectAsync(ipEndPoint);
// 构建并发送消息
var message = new StringPackageInfo()
{
Key = "GREET",
Parameters = new[] { "Hello", "World" }
};
var messageStr = $"{message.Key} {string.Join(' ', message.Parameters)}{Environment.NewLine}";
var messageBytes = Encoding.UTF8.GetBytes(messageStr);
await client.SendAsync(messageBytes);
// 接收服务端响应
var receivedPack = await client.ReceiveAsync();
Console.WriteLine($"Received: {receivedPack.Key} {receivedPack.Body}");
运行后,客户端将与服务端进行交互,并打印接收到的响应。
5. 单进程多线程实现
以下代码展示了如何在同一进程中分别启动服务端和客户端:
public class Program
{
static async Task StartServer()
{
var host = SuperSocketHostBuilder
.Create<StringPackageInfo, CommandLinePipelineFilter>()
.UsePackageHandler(async (session, package) =>
{
await session.SendAsync(Encoding.UTF8.GetBytes($"{package.Key} ADD 1 2{Environment.NewLine}"));
})
.ConfigureSuperSocket(options =>
{
options.Name = "Echo Server";
options.Listeners = new List<ListenOptions>
{
new ListenOptions
{
Ip = "Any",
Port = 4040
}
};
}).Build();
await host.RunAsync();
}
static async Task StartClient()
{
var easyClient = new EasyClient<StringPackageInfo>(new CommandLinePipelineFilter()
{
Decoder = new DefaultStringPackageDecoder()
});
var client = easyClient.AsClient();
var ipAddress = IPAddress.Loopback;
var port = 4040;
var ipEndPoint = new IPEndPoint(ipAddress, port);
await client.ConnectAsync(ipEndPoint);
var message = new StringPackageInfo()
{
Key = "GREET",
Parameters = new[] { "Hello", "World" }
};
var messageStr = $"{message.Key} {string.Join(' ', message.Parameters)}{Environment.NewLine}";
var messageBytes = Encoding.UTF8.GetBytes(messageStr);
await client.SendAsync(messageBytes);
var receivedPack = await client.ReceiveAsync();
Console.WriteLine($"Received: {receivedPack.Key} {receivedPack.Body}");
}
static async Task Main(string[] args)
{
// 异步启动服务端
_ = Task.Run(StartServer);
while (true)
{
Console.ReadLine(); // 按 Enter 触发一次客户端请求
await StartClient();
}
}
}
运行程序后,服务端将在后台运行,每次按下 Enter 键时,客户端会发起一次请求并接收响应。