这应该是个程序员入门就必备的东西了,但是,这次我们的研究是TouchSocket(林丰工具箱中的Socket通信便是基于TouchSocket制作的,而不是传统的Socket通信)
一.TouchSocket简介
TouchSocket这是一个轻量级的、支持插件的综合网络通信库。基础通信功能包含Tcp、Udp、Ssl、Rpc、Http等。其中http服务器支持WebSocket、静态网页、XmlRpc、WebApi、JsonRpc等扩展插件。和自定义协议的TouchRpc,支持Ssl加密、异步调用、权限管理、错误状态返回、服务回调、分布式调用等。在空载函数执行时,10万次调用仅3.8秒,在不返回状态时,仅0.9秒。

(这可能有点空,但是我们可以理解为比Microsoft System.Socket更好的一个Socket包)
作者B站:https://space.bilibili.com/94253567/channel/collectiondetail?sid=568476
作者gitee:https://gitee.com/RRQM_Home/TouchSocket
二.代码示例
我们先看一下图解


我们再来看一下可配置项
属性名 | 属性描述 |
SetBufferLengt | 缓存池容量(单位:byte),默认1024*64 设置建议: 1.如果数据包较小,建议10k左右的值。更加节约内存 2.如果数据包较大,例如文件传输等,建议64k,甚至更大的值 3.该值虽然无上限,但是一般不要超过1Mb,不然不仅没意义,还很浪费 |
SetMaxPackageSize | 数据包最大值(单位:byte),默认1024*1024*10。该值会在适当时间,直接作用DataHandlingAdapter.MaxPackageSize |
SetThreadCount | 多线程数量。该值在Auto模式下指示线程池的最少线程数量和IO线程数量。 设置建议: 1.异步处理接收数据,此时线程数量设置为内核线程左右的值即可 2.同步处理接收数据,此时应当考虑两个因素。该操作是否为耗时操作,如果是,则该值在允许范围内应当设置更可能大的值。如果不是,则设置为内核线程左右的值即可 |
SetListenIPHosts | 监听IP和端口号组,可以一次性设置多个地址 |
SetServerName | 服务器标识名称,无实际使用意义 |
SetBacklogProperty | Tcp半连接挂起连接队列的最大长度 默认为30 |
SetMaxCount | 最大可连接数,默认为10000 |
SetClearInterval | 清理无数据交互的SocketClient(单位:毫秒),默认60000 毫秒。如果不想清除,可使用-1。但是,并不建议设置-1,因为假如有客户端因为网络故障导致僵死的话,服务器将永久保留其实例。所以最好的方式是按照自己的业务需要,设置对应值,因为从普遍性而言,无数据交互的客户端,如果时间超出10s,则断开的策略是优于一直连接的。或者,自己规定心跳数据包,保持客户端活性 |
SetClearType | 清理统计类型。 1.Receive:为在收到数据时,刷新统计,如果一直有数据接收,则不会被主动清理断开 2.Send:为在发送数据时,刷新统计,如果一直有数据发送,则不会被主动清理断开 支持位域叠加 |
SetReceiveType | 接收类型 1.AUTO:自动接收模式。 2.None:不投递IO接收申请,用户可通过GetStream,获取到流以后,自己处理接收。注意:连接端不会感知主动断开 |
UsePlugin | 是否启用插件。在启用时或许会带来一点点性能损耗,基本上不是千万数据交互根本不值一提 |
SetServiceSslOption | Ssl配置,为Null时则不启用。 |
UseNoDelay | 设置Socket的NoDelay属性,默认false |
设置Socket的NoDelay属性,默认false | 使用延迟发送。 众所周知,tcp数据报文为了发送效率,会默认启用延迟算法。但是这种设置,只能一定程度的缓解小数据发送效率低的问题,因为它为了保证多线程发送的有序性,在send函数中设置了线程同步,所以说,每调用一次send,实际上都是巨大的性能消耗(此处用iocp发送亦然)。所以,要解决该问题, 最终还是要将小数据,组合成大数据,这样才能更高效率的发送。所以,DelaySender正是负责此类工作的。 使用DelaySender,会一定程度的降低发送的及时性,但是降低程度并不高,简单来说: 1.如果一个包大于512kb,则不会延迟,直接发送。 2.如果发送第一个包,与第二个包的时间间隔小于一个线程池线程调度的时间(这个时间极短,一般来说会在10微秒左右),则会将这两个包压缩为一个包发送。 |
UseReuseAddress | 启用端口复用。该配置可在服务器、或客户端在监听端口时,运行监听同一个端口。可以一定程度缓解端口来不及释放的问题 |
相信大家肯定迫不及待了,那么我们现在就看一下TCP的部分源码吧
(1)客 户 端(仅展示部分内容,更多内容请自行在若汝棋茗的博客探索)
1创建TCP协议连接代码(当然,你也可以使用泛型创建)
if (tcpClient == null)
{
tcpClient = new TcpClient();
tcpClient.Connected += (client, e) =>
{
tcpClient.Send("服务器与客户端已成功连接");
};//连接到服务器
tcpClient.Disconnected += (client, e) =>
{
tcpClient.Send($"断开连接,原因:{e.Message}");
};//从服务器断开连接,当连接不成功时不会触发。
tcpClient.Received += (client, byteBlock, requestInfo) =>
{
//从服务器收到信息
string mes = Encoding.UTF8.GetString(byteBlock.Buffer, 0, byteBlock.Len);
this.ShowLogMsg($"接收到信息:{mes}");
};
//声明配置
TouchSocketConfig config = new TouchSocketConfig();
config.SetRemoteIPHost(new IPHost(this.tb1.Text))
.UsePlugin()
.ConfigureContainer(a =>
{
a.SetSingletonLogger(new LoggerGroup(new FileLogger(), new EasyLogger(this.ShowLogMsg)));
});
//载入配置
tcpClient.Setup(config);
tcpClient.Connect();
tcpClient.Send("客户端已连接至服务器");
}
(由于是私人开发的Nuget包,在语法方面更加符合中国人开发的特点,如果实在理解不了,可以观看官方的付费教学视频,受版权原因,我们在这里不做语法解释)
2.发送字符串代码
try
{
this.tcpClient?.Send(this.tb2.Text); //tb2正常改为你的TextBox
}
catch (Exception ex)
{
this.ShowLogMsg(ex.Message);
throw;
}
this.tb2.Text = "";
(没错,这扔然需要错误拦截)
3.界面设计
你可以这样设计界面,当然,在设计界面前,你也可以使用不同的美化包(如:SunnyUI),也可以在最后使用Blender进行美化

(1)服 务 端(仅展示部分内容,更多内容请自行在若汝棋茗的博客探索)
服务器的代码就更简单了,只有几十行,便能实现本地的TCP服务器创建
如下服务器适用于Console控制台程序
using System;
using System.Text;
using TouchSocket.Core;
using TouchSocket.Sockets;
namespace TCP本地服务端
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("在这里你可以写你想写的内容");
TcpService service = new TcpService();
service.Connecting = (client, e) => { };//有客户端正在连接
service.Connected = (client, e) => { };//有客户端成功连接
service.Disconnected = (client, e) => { };//有客户端断开连接
service.Received = (client, byteBlock, requestInfo) =>
{
//从客户端收到信息
string mes = Encoding.UTF8.GetString(byteBlock.Buffer, 0, byteBlock.Len);
client.Logger.Info($"已从{client.ID}接收到信息:{mes}");
client.Send(mes);//将收到的信息直接返回给发送方
//client.Send("id",mes);//将收到的信息返回给特定ID的客户端
var ids = service.GetIDs();
foreach (var clientId in ids)//将收到的信息返回给在线的所有客户端。
{
if (clientId != client.ID)//不给自己发
{
service.Send(clientId, mes);
}
}
};
service.Setup(new TouchSocketConfig()//载入配置
.SetListenIPHosts(new IPHost[] { new IPHost("tcp://127.0.0.1:7789"), new IPHost(7790) })//同时监听两个地址
.ConfigureContainer(a =>//容器的配置顺序应该在最前面
{
a.AddConsoleLogger();//添加一个控制台日志注入(注意:在maui中控制台日志不可用)
})
.ConfigurePlugins(a =>
{
//a.Add();//此处可以添加插件
}))
.Start();//启动
Console.ReadLine();
}
}
}
实例窗口展示

三.其他场景应用

四.结束语
那么本期开源Socket介绍就结束了,希望可以帮助到大家!
Gitee: https://gitee.com/RRQM_Home/TouchSocket
官方文档: https://www.yuque.com/rrqm/touchsocket
Blibli: https://space.bilibili.com/94253567/channel/collectiondetail?sid=568476
谢谢大家!
赞赏:

6666