67 Star 423 Fork 84

GVPdotNET China / RRQMSocket

Create your Gitee Account
Explore and code with more than 6 million developers,Free private repositories !:)
Sign up
Clone or download
Cancel
Notice: Creating folder will generate an empty file .keep, because not support in Git
Loading...
README.md

图片名称

NuGet version (RRQMSocket) License Download star fork

合抱之木,生于毫末;九层之台,起于垒土。

简体中文 | English

💿描述

名称 版本(Nuget Version) 下载(Nuget Download) 描述
RRQMSocket NuGet version (RRQMSocket) Download RRQMSocket是一个整合性的、超轻量级的网络通信服务框架。它具有 高并发连接高并发处理事件订阅插件式扩展多线程处理内存池对象池 等特点,让使用者能够更加简单的、快速的搭建网络框架。在发送效率上,同步发送可达20w/s,异步发送可达60w/s。服务器在接收、处理效率上因线程数量而定。
RRQMSocket.FileTransfer NuGet version (RRQMSocket.FileTransfer) Download RRQMSocket.FileTransfer是一个高性能的文件传输框架,您可以用它传输任意大小的文件,它可以完美支持上传下载混合式队列传输断点续传快速上传传输限速获取文件信息删除文件等。在实时测试中,它的传输速率可达500Mb/s。
RRQMSocket.RPC NuGet version (RRQMSocket.RPC) Download RRQMSocket.RPC是一个超轻量、高性能、可扩展的微服务管理平台框架,目前已完成开发RRQMRPCXmlRpcJsonRpcWebApi部分。RRQMRPC部分使用RRQM专属协议,支持客户端异步调用,服务端异步触发、以及outref关键字,函数回调等。在调用效率上也是非常强悍,在调用空载函数,且返回状态时,10w次调用仅用时3.8秒,不返回状态用时0.9秒。其他协议调用性能详看性能评测。
RRQMSocket.RPC.WebApi NuGet version (RRQMSocket.RPC.WebApi) Download RRQMSocket.RPC.WebApi是一个扩展于RRQMSocket.RPC的WebApi组件,可以通过该组件创建WebApi服务解析器,让桌面端、Web端、移动端可以跨语言调用RPC函数。功能支持路由、Get传参、Post传参等。
RRQMSocket.RPC.XmlRpc NuGet version (RRQMSocket.RPC.XmlRpc) Download RRQMSocket.RPC.XmlRpc是一个扩展于RRQMSocket.RPC的XmlRpc组件,可以通过该组件创建XmlRpc服务解析器,完美支持XmlRpc数据类型,类型嵌套,Array等,也能与CookComputing.XmlRpcV2完美对接。不限Web,Android等平台。
RRQMSocket.RPC.JsonRpc NuGet version (RRQMSocket.RPC.JsonRpc) Download RRQMSocket.RPC.JsonRpc是一个扩展于RRQMSocket.RPC的JsonRpc组件,可以通过该组件创建JsonRpc服务解析器,支持JsonRpc全部功能,可与Web,Android等平台无缝对接。
RRQMSocket.Http NuGet version (RRQMSocket.Http) Download RRQMSocket.Http是一个能够简单解析Http的服务组件,能够快速响应Http服务请求。

🖥支持环境

  • .NET Framework4.5及以上。
  • .NET Core3.1及以上。
  • .NET Standard2.0及以上。

🥪支持框架

  • WPF
  • Winform
  • Blazor
  • Xamarin
  • Mono
  • Unity
  • 其他(即所有C#系)

🌴RRQMSocket特点速览

对象池

对象池在RRQMSocket有很多应用,最主要的两个就是连接对象池处理对象池。连接对象池就是当客户端成功连接时,首先会去连接对象池中找TcpSocketClient,然后没有的话,才会创建。如果哪个客户端掉线了,它的TcpSocketClient就会被回收。这也就是ID重用的原因。

然后就是处理对象池,在RRQMSocket中,接收数据的线程和IOCP内核线程是分开的,也就是比如说客户端给服务器发送了1w条数据,但是服务器收到后处理起来很慢,那传统的iocp肯定会放慢接收速率,然后通知客户端的tcp窗口,发生拥塞,然后让客户端暂缓发送。但是在RRQMSocket中会把收到的数据通过队列全都存起来,首先不影响iocp的接收,同时再分配线程去处理收到的报文信息,这样就相当于一个“泄洪湖泊”,能很大程度的提高处理数据的能力。

多线程

由于有处理对象池的存在,使多线程处理变得简单。在客户端连接完成时,会自动分配该客户端辅助类(TcpSocketClient)的消息处理逻辑线程,假如服务器线程数量为10,则第一个连接的客户端会被分配到0号线程中,第二个连接将被分配到1号线程中,以此类推,循环分配。当某个客户端收到数据时,会将数据排入当前线程所独自拥有的队列当中,并唤醒线程执行。

传统IOCP和RRQMSocket

RRQMSocket的IOCP和传统也不一样的,以微软官方为例,使用MemoryBuffer开辟一块内存,然后均分,然后给每个会话分配一个区接收,等收到数据以后,再复制一份,然后把复制的数据抛出处理。而RRQMSocket是每次接收之前,从内存池拿一个可用内存块,然后直接用于接收,等收到数据以后,直接就把这个内存块抛出去了,这样就避免了复制操作,虽然只是细小的设计,但是在传输1000w64kb的数据时,性能相差了10倍。所以也是基于此,文件传输时效率才会高。

数据处理适配器

相信大家都使用过其他的Socket产品,例如HPSocket,SuperSocket等,那么RRQMSocket在设计时也是借鉴了其他产品的优秀设计理念,数据处理适配器就是其中之一,但和其他产品的设计不同的是,RRQMSocket的适配器功能更加强大,它可以无视真实的数据,而模拟出想要的数据,例如:可以对数据进行预处理,从而解决数据分包。粘包的问题,也可以直接解析HTTP协议,经过适配器处理后传回一个HttpRequest对象等。

粘包、分包解决

在RRQMSocket中处理TCP粘包、分包问题是非常简单的。只需要更改不同的数据处理适配器即可。例如:使用固定包头,只需要给TcpSocketClient和TcpClient赋值FixedHeaderDataHandlingAdapter的实例即可。同样对应的处理器也有固定长度终止字符分割 等。

🔗联系作者

✨API文档

RRQMSocket API文档

📦 安装

🍻RRQM系产品

名称 版本(Nuget Version) 下载(Nuget Download) 描述
RRQMCore NuGet version (RRQMCore) Download RRQMCore是为RRQM系提供基础服务功能的库,其中包含:内存池对象池等待逻辑池AppMessenger3DES加密Xml快速存储运行时间测量器文件快捷操作高性能序列化器规范日志接口等。
RRQMMVVM NuGet version (RRQMMVVM) Download RRQMMVVM是超轻简的MVVM框架,但是麻雀虽小,五脏俱全。
RRQMSkin NuGet version (RRQMSkin) Download RRQMSkin是WPF的控件样式库,其中包含: 无边框窗体圆角窗体水波纹按钮输入提示筛选框控件拖动效果圆角图片框弧形文字扇形元素指针元素饼图时钟速度表盘 等。

💐快速入门

一、TCP框架

1.1 创建服务器

详细过程请阅读API文档,以下仅简单示例。

创建RRQMTcpService

RRQMTcpService是对TcpService的简单封装,指定辅助类为RRQMSocketClient,在辅助类中不做任何数据处理,仅将数据在RRQMTcpService中抛出。

RRQMTcpService service = new RRQMTcpService();

//订阅事件
//service.ClientConnected += Service_ClientConnected;//订阅连接事件
//service.ClientDisconnected += Service_ClientDisconnected;//订阅断开连接事件
//service.CreatSocketCliect += Service_CreatSocketCliect;//订阅创建辅助类事件,可直接设置其他属性。
//service.OnReceived += Service_OnReceived;//可直接订阅收到数据事件。

//属性设置
service.IsCheckClientAlive = true;//使用空包检验活性,不会对数据有任何影响。
service.BufferLength = 1024;//设置缓存池大小,该数值在框架中经常用于申请ByteBlock,所以该值会影响内存池效率。
service.IDFormat = "TcpSocketClient_{0}";//设置分配ID的格式, 格式必须符合字符串格式,至少包含一个补位, 初始值为“{0}-TCP”
service.Logger = new Log();//设置内部日志记录器,默认日志是控制台输出。
service.MaxCount = 1000;//设置最大连接数,可动态设置,当已连接数超过设置数值时,将主动断开客户端。

//方法
service.Bind(7789, 2);//绑定监听,可绑定Ipv6,可监听所有地址。

Console.WriteLine("RRQMTcpService绑定成功");

创建TokenTcpService

TokenTcpService是继承于TcpService的功能扩展服务器,该服务器的主要功能是通过验证“口令”对连接的客户端进行筛选,及时的将不允许连接恶意连接不安全连接的客户端拒之门外,也可以实现租户模式

TokenTcpService<MyTcpSocketClient> service = new TokenTcpService<MyTcpSocketClient>();
service.VerifyToken = "ABC";

//方法
service.Bind(7789, 2);//绑定监听,可绑定Ipv6,可监听所有地址。

Console.WriteLine("TokenTcpService绑定成功");

注意: 使用该服务器必须遵循连接协议,或使用专属客户端(TokenTcpClient)连接。

1.2 创建客户端

创建TcpClient

TcpClient可与任意服务器进行连接、收发,处理数据,也可以更加方便的处理粘包和分包,亦或者解析数据结构。

TcpClient client = new TcpClient();

//属性
client.BufferLength = 1024;//设置缓存池大小,该数值在框架中经常用于申请ByteBlock,所以该值会影响内存池效率。
client.Logger = new Log();//设置内部日志记录器,默认日志是控制台输出。
client.DataHandlingAdapter = new NormalDataHandlingAdapter();//数据处理适配器,可用于处理粘包、解析对象。

//事件
//client.ConnectedService += Client_ConnectedService;
//client.DisconnectedService += Client_DisconnectedService;
//client.OnReceived += Client_OnReceived;

//方法
client.Connect(new IPHost("127.0.0.1:7789"));//连接
Console.WriteLine("连接成功");
client.Send(Encoding.UTF8.GetBytes("若汝棋茗"));//发送数据
Console.WriteLine("发送成功");

创建TokenTcpClient

TokenTcpClient client = new TokenTcpClient();

//属性
client.VerifyToken="ABC";//设置链接口令。
client.BufferLength = 1024;//设置缓存池大小,该数值在框架中经常用于申请ByteBlock,所以该值会影响内存池效率。
client.Logger = new Log();//设置内部日志记录器,默认日志是控制台输出。
client.DataHandlingAdapter = new NormalDataHandlingAdapter();//数据处理适配器,可用于处理粘包、解析对象。

//事件
//client.ConnectedService += Client_ConnectedService;
//client.DisconnectedService += Client_DisconnectedService;
//client.OnReceived += Client_OnReceived;

//方法
client.Connect(new IPHost("127.0.0.1:7789"));//连接
Console.WriteLine("连接成功");
client.Send(Encoding.UTF8.GetBytes("若汝棋茗"));//发送数据
Console.WriteLine("发送成功");

1.3 数据处理适配器

数据处理适配器的主要作用就是对发送、接收的数据进行封装和解析。在RRQMSocket中,可以利用数据处理适配器解决粘包分包问题,也能解析Http数据报文。

类型

  • NormalDataHandlingAdapter普通TCP报文处理器
  • FixedSizeDataHandlingAdapter固定长度TCP报文处理器
  • TerminatorDataHandlingAdapter终止字符TCP报文处理器
  • FixedHeaderDataHandlingAdapter固定包头TCP报文处理器
  • HttpDataHandlingAdapter解析Http处理器(需安装RRQMSocket.Http)

客户端使用

客户端比较简单,直接对其赋值即可。

client.DataHandlingAdapter = new NormalDataHandlingAdapter();//数据处理适配器,可用于处理粘包、解析对象。

服务器使用

在服务器使用适配器时,必须保证每个TcpSocketClient都拥有一个单独实例的适配器,所以可以订阅CreatSocketCliect事件,然后又因为RRQMSocket中有连接对象池,所以最好进行新创建判断,然后再创建实例化,避免多次实例化赋值带来的性能问题。

 private static void Service_CreatSocketCliect(RRQMSocketClient arg1, CreatOption arg2)
 {
     if (arg2.NewCreate)
     {
         arg1.DataHandlingAdapter = new NormalDataHandlingAdapter();
     }
 }

如果是自定义继承的TcpSocketClient,可以重写Create方法。

注意:在构造函数内赋值适配器无效,会被Create方法覆盖

public class MyTcpSocketClient : TcpSocketClient
{
    /// <summary>
    /// 初次创建对象,效应相当于构造函数,但是调用时机在构造函数之后,可覆盖父类方法
    /// </summary>
    public override void Create()
    {
        this.DataHandlingAdapter = new NormalDataHandlingAdapter();//普通TCP报文处理器
        //this.DataHandlingAdapter = new FixedHeaderDataHandlingAdapter();//固定包头TCP报文处理器
        //this.DataHandlingAdapter = new FixedSizeDataHandlingAdapter(1024);//固定长度TCP报文处理器
        //this.DataHandlingAdapter = new TerminatorDataHandlingAdapter(1024, "\r\n");//终止字符TCP报文处理器
    }
}

1.4 Demo

RRQMBox

二、文件传输框架

2.1 特点

  • 简单易用。
  • 多线程处理。
  • 高性能,传输速度可达500Mb/s。
  • 超简单的传输限速设置,1k-10Gb 无级调节。
  • 超简单的传输速度、传输进度获取。
  • 随心所欲的暂停、继续、停止传输。
  • 系统化的权限管理,让敏感文件只允许私有化下载。
  • 随时发送消息,让客户端和服务器交流不延迟。
  • 基于事件驱动,让每一步操作尽在掌握。
  • 可视化的文件块流,可以实现像迅雷一样的填充式进度条。
  • 超简单的断点续传设置,为大文件传输保驾护航。
  • 无状态上传断点续传设置,让同一个文件,在不同客户端之间接力上传。
  • 已经上传的文件,再次上传时,可实现快速上传。
  • 极少的GC释放。

2.2 创建文件服务器

以下进行简单示例,详细使用见文件传输入门

 FileService fileService = new FileService();
 fileService.VerifyToken ="123ABC";
 
 fileService.BreakpointResume = true;//支持断点续传
 try
 {
     fileService.Bind(7789,2);//直接监听7789端口号。多线程,默认为1,此处设置线程数量为2
/* 订阅相关事件
 fileService.ClientConnected += FileService_ClientConnected;
 fileService.ClientDisconnected += FileService_ClientDisconnected;

 fileService.BeforeTransfer += FileService_BeforeTransfer ;
 fileService.FinishedTransfer += FileService_FinishedTransfer ;
 fileService.ReceiveSystemMes += FileService_ReceiveSystemMes;
*/
 }
 catch (Exception ex)
 {
     MessageBox.Show(ex.Message);
 }

2.3 传输文件

先初始化客户端。


FileClient fileClient = new FileClient();
//订阅事件
//fileClient.TransferFileError += FileClient_TransferFileError;
//fileClient.BeforeFileTransfer += this.FileClient_BeforeFileTransfer; ;
//fileClient.FinishedFileTransfer += this.FileClient_FinishedFileTransfer; ;
//fileClient.DisconnectedService += FileClient_DisConnectedService;
//fileClient.ReceiveSystemMes += this.FileClient_ReceiveSystemMes;
//fileClient.ConnectedService += this.FileClient_ConnectedService;
//fileClient.FileTransferCollectionChanged += this.FileClient_FileTransferCollectionChanged;
fileClient.Connect(new IPHost("127.0.0.1:7789"));//连接服务器。

调用RequestTransfer进行传输文件。此方法可上传,也可下载。请求成功后会将传输排入队列,然后依次传输。

上传


//restart属性可以自由设定。
//breakpointResume也可自由指定,但最好是从fileClient获取属性。
UrlFileInfo urlFileInfo = UrlFileInfo.CreatUpload("C:/1.txt", restart: true, breakpointResume: this.fileClient.BreakpointResume);
fileClient.RequestTransfer(urlFileInfo);

下载


//restart属性可以自由设定。
UrlFileInfo urlFileInfo = UrlFileInfo.CreatDownload("C:/1.txt", restart: true);
fileClient.RequestTransfer(urlFileInfo);

2.4 属性获取

  • TransferSpeed:获取传输速度
  • TransferProgress:获取传输进度
  • TransferFileInfo:获取正在传输的文件信息
  • TransferStatus:获取传输状态
  • BreakpointResume:获取是否支持断点续传(该属性与服务器同步)
  • ReceiveDirectory:获取或设置接收文件夹
  • FileTransferCollection:获取传输文件集合

2.5 功能方法

fileClient.PauseTransfer();//暂停传输
fileClient.ResumeTransfer();//恢复传输

foreach (var item in fileClient.FileTransferCollection)
{
    fileClient.CancelTransfer(item);//从传输列表中获得传输信息,然后取消该传输任务
    break;
}

fileClient.StopThisTransfer();//停止当前下载
fileClient.StopAllTransfer();//停止所有下载
fileClient.SendSystemMessage("RRQM");//发送系统消息
fileClient.SendBytesWaitReturn(new byte[10],0,10);//发生字节数组并等待返回

2.6 Demo示例

Demo位置: RRQMBox

说明: 可以看到,图一正在上传一个Window的系统镜像文件,大约4.2Gb,传输速度已达到346Mb/s,这是因为服务器和客户端在同一电脑上,磁盘性能限制导致的。其次,GC基本上没有释放,性能非常强悍,图二是下载文件,性能依旧非常强悍。

上传文件 下载文件

三、RPC框架

RPC框架是所有远程过程调用的微服务管理平台,在该平台的托管下,使多种协议、多种序列化方式调用成为可能。目前可使用RRQMRPC、WebApi、XmlRpc、JsonRpc共同调用。

3.1 RRQMRPC

特点

  • 简单易用。
  • 多线程处理。
  • 高性能,在保证送达但不返回的情况下,10w次调用用时0.8s,在返回的情况下,用时3.9s。
  • 支持TCP、UDP等不同的协议调用相同服务。
  • 支持指定服务异步执行。
  • 支持权限管理,让非法调用死在萌芽时期。
  • 全自动 代码生成 ,可使用系统编译成dll调用,也可以使用插件生成代理调用。
  • 代理方法会生成异步方法,支持客户端异步调用。
  • 支持out、ref ,参数设定默认值等。
  • 随心所欲的序列化方式,除了自带的超轻量级二进制序列化、xml序列化外,用户可以自己随意使用其他序列化。
  • 支持编译式调用,也支持方法名+参数式调用。
  • 全异常反馈 ,服务里发生的异常,会一字不差的反馈到客户端。
  • 超简单、自由的回调方式

创建RRQMRPC服务器

新建类文件,继承于ServerProvider,并将其中公共方法标识为RRQMRPCMethod即可。

public class Server: ServerProvider
{
    [RRQMRPCMethod]
    public string TestOne(string str)
    {
        return "若汝棋茗";
    }
 }

启动RRQMRPC服务器

RPCService rpcService = new RPCService();
rpcService.RegistAllService();//注册所有服务

TcpRPCParser tcpRPCParser = new TcpRPCParser();
tcpRPCParser.SerializeConverter = new BinarySerializeConverter();
tcpRPCParser.Bind(7789, 5);
tcpRPCParser.NameSpace = "RRQMTest";
Console.WriteLine("TCP解析器添加完成");

rpcService.AddRPCParser("TcpParser", tcpRPCParser);

rpcService.OpenRPCServer();
Console.WriteLine("RPC启动完成");

Console.ReadKey();

客户端引用

首先得下载RRQMRPCVSIX插件,然后安装插件,成功后右击任意项目即可看见“重新引用RRQMRPC”条目。

图片名称

然后点击,弹出窗口,输入IP及端口,点击确认,即可下载完成引用,此时会在项目下生成RRQMRPC文件夹,里面含有代理文件。

图片名称

创建客户端

RPCClient client = new RPCClient();

client.InitializedRPC(new IPHost("127.0.0.1:7789"));

Server server = new Server(client);

string mes=server.TestOne("RRQM");//调用

RRQMRPC性能测试

说明: 图一、图二、图三分别为UDP无反馈调用TCP有反馈调用TCP连接池有反馈调用。调用次数均为10w次,调用性能非常nice。在无反馈中,吞吐量达14.28w,在有反馈中达2.72w,简直秒杀WCF(WCF使用http协议,在本机测试吞吐量为310)

输入图片说明

输入图片说明

输入图片说明

示例Demo

RRQMBox

3.2 WebApi

WebApi功能,目前仅仅适用于Api调用,不具备MVC全部功能。

特点

  • 多线程处理。
  • 高性能,100个客户端,10w次调用,仅用时17s。
  • 全异常反馈 ,服务里发生的异常,会一字不差的反馈到客户端。
  • 支持大部分路由规则。

创建WebApi服务器

新建类文件,继承于ServerProvider,使用Rount属性指定路由规则,同时将其中公共方法标识为Route即可。同时也可制定路由规则。

[Route("/[controller]/[action]")]
public class Server: ServerProvider
{
    [Route]
    public string TestOne(string str)
    {
        return "若汝棋茗";
    }
 }

启动WebApi服务器

RPCService rpcService = new RPCService();
rpcService.RegistAllService();//注册所有服务

WebApiParser webApiParser = new WebApiParser();
webApiParser.Bind(7792, 5);
Console.WriteLine("webApiParser解析器添加完成");

rpcService.AddRPCParser("webApiParser", webApiParser);

rpcService.OpenRPCServer();
Console.WriteLine("RPC启动完成");

Console.ReadKey();

此时即可使用PostManagent测试,也可以直接使用浏览器访问。

注意:默认数据格式是xml,如需Json,请详看说明文档。

性能测试

3.3 XmlRpc

完美支持XmlRpc数据类型,类型嵌套,Array等。

创建XmlRpc服务器

新建类文件,继承于ServerProvider,同时将其中公共方法标识为XmlRpc即可。

public class Server: ServerProvider
{
    [XmlRpc]
    public string TestOne(string str)
    {
        return "若汝棋茗";
    }
 }

启动XmlRpc服务器

RPCService rpcService = new RPCService();
rpcService.RegistAllService();//注册所有服务

XmlRpcParser xmlRpcParser = new XmlRpcParser();
xmlRpcParser.Bind(7793, 5);
Console.WriteLine("xmlRpcParser解析器添加完成");

rpcService.AddRPCParser("xmlRpcParser", xmlRpcParser);

rpcService.OpenRPCServer();
Console.WriteLine("RPC启动完成");

Console.ReadKey();

此时即可使用CookComputing.XmlRpcV2测试。

3.4 JsonRpc

创建JsonRpc服务器

新建类文件,继承于ServerProvider,同时将其中公共方法标识为JsonRpc即可。

public class Server: ServerProvider
{
    [JsonRpc]
    public string TestOne(string str)
    {
        return "若汝棋茗";
    }
 }

启动XmlRpc服务器

RPCService rpcService = new RPCService();
rpcService.RegistAllService();//注册所有服务

JsonRpcParser jsonRpcParser = new JsonRpcParser();
jsonRpcParser.Bind(7793, 5);
Console.WriteLine("jsonRpcParser解析器添加完成");

rpcService.AddRPCParser("jsonRpcParser", jsonRpcParser);

rpcService.OpenRPCServer();
Console.WriteLine("RPC启动完成");

Console.ReadKey();

此时即可使用Json格式数据调用RPC。

TcpClient tcpClient = new TcpClient();
//tcpClient.OnReceived += TcpClient_OnReceived;//接收返回数据。
tcpClient.Connect(new IPHost("127.0.0.1:7793"));

tcpClient.Send(Encoding.UTF8.GetBytes("{\"jsonrpc\":\"2.0\",\"method\":\"TestOne\",\"params\":[5],\"id\":1}\r\n"));//此处必须包含“\r\n”。

致谢

谢谢大家对我的支持,如果还有其他问题,请加群QQ:234762506讨论。

💕 支持本项目

您的支持就是我不懈努力的动力。打赏时请一定留下您的称呼。

赞助总金额:516.6¥

赞助名单:

(以下排名只按照打赏时间顺序)

1.Bobo Joker

2.UnitySir

3.Coffee

4.Ninety

5.*琼

图片名称

Comments ( 18 )

Sign in for post a comment

About

RRQMSocket是一个整合性网络通信框架,特点是支持高并发、事件驱动、易用性强、二次开发难度低等。其中主要内容包括:TCP、UDP服务通信框架、大文件传输、RPC、WebApi、XmlRpc、JsonRpc等内容 spread retract
Cancel

Releases (13)

All

RRQMSocket

Contributors

All

Activities

load more
can not load any more
C#
1
https://git.oschina.net/dotnetchina/RRQMSocket.git
git@git.oschina.net:dotnetchina/RRQMSocket.git
dotnetchina
RRQMSocket
RRQMSocket
master

Search