cnblogs.com/coldairarrow/p/11336771.html
簡(jiǎn)介
DotNettySocket是一個(gè).NET跨平臺(tái)Socket框架(支持.NET4.5+及.NET Standard2.0+),同時(shí)支持TcpSocket、WebSocket和UdpSocket,其基于微軟強(qiáng)大的DotNetty框架,力求為Socket通訊提供簡(jiǎn)單、高效、優(yōu)雅的操作方式。
安裝方式:Nuget安裝DotNettySocket即可
項(xiàng)目地址:https://github.com/Coldairarrow/DotNettySocket
產(chǎn)生背景
兩年前最開(kāi)始接觸物聯(lián)網(wǎng)的時(shí)候,需要用到Tcp及Udp通訊,為了方便使用,將原始的Socket進(jìn)行了簡(jiǎn)單的封裝,基本滿足了需求,并將框架開(kāi)源。
但是由于精力及實(shí)力有限,沒(méi)有進(jìn)一步優(yōu)化原框架。后來(lái)發(fā)現(xiàn)了強(qiáng)大的DotNetty框架,DotNetty是微軟Azure團(tuán)隊(duì)開(kāi)源基于Java Netty框架的移植版,其性能優(yōu)異、維護(hù)團(tuán)隊(duì)強(qiáng)大,許多.NET強(qiáng)大的框架都使用它。
DotNetty功能強(qiáng)大,但是用起來(lái)還是不夠簡(jiǎn)潔(或許是個(gè)人感覺(jué)),剛好最近項(xiàng)目需要用到WebSocket,因此鄙人抽時(shí)間基于DotNetty進(jìn)行簡(jiǎn)單封裝了下,擼出一個(gè)力求簡(jiǎn)單、高效、優(yōu)雅的Socket框架。
使用方式
TcpSocket
Tcp是面向連接的,所以服務(wù)端對(duì)連接的管理就至關(guān)重要,框架支持各種事件的處理、給連接設(shè)置連接名(身份標(biāo)識(shí))、通過(guò)連接名找到特定連接、連接收發(fā)數(shù)據(jù)、分包、粘包處理。
using Coldairarrow.DotNettySocket;
using System;
using System.Text;
using System.Threading.Tasks;
namespace TcpSocket.Server
{
class Program
{
static async Task Main(string[] args)
{
var theServer = await SocketBuilderFactory.GetTcpSocketServerBuilder(6001)
.SetLengthFieldEncoder(2)
.SetLengthFieldDecoder(ushort.MaxValue, 0, 2, 0, 2)
.OnConnectionClose((server, connection) =>
{
Console.WriteLine($"連接關(guān)閉,連接名[{connection.ConnectionName}],當(dāng)前連接數(shù):{server.GetConnectionCount()}");
})
.OnException(ex =>
{
Console.WriteLine($"服務(wù)端異常:{ex.Message}");
})
.OnNewConnection((server, connection) =>
{
connection.ConnectionName = $"名字{connection.ConnectionId}";
Console.WriteLine($"新的連接:{connection.ConnectionName},當(dāng)前連接數(shù):{server.GetConnectionCount()}");
})
.OnRecieve((server, connection, bytes) =>
{
Console.WriteLine($"服務(wù)端:數(shù)據(jù){Encoding.UTF8.GetString(bytes)}");
connection.Send(bytes);
})
.OnSend((server, connection, bytes) =>
{
Console.WriteLine($"向連接名[{connection.ConnectionName}]發(fā)送數(shù)據(jù):{Encoding.UTF8.GetString(bytes)}");
})
.OnServerStarted(server =>
{
Console.WriteLine($"服務(wù)啟動(dòng)");
}).BuildAsync();
Console.ReadLine();
}
}
}
using Coldairarrow.DotNettySocket;
using System;
using System.Net;
using System.Text;
using System.Threading.Tasks;
namespace UdpSocket.Client
{
class Program
{
static async Task Main(string[] args)
{
var theClient = await SocketBuilderFactory.GetUdpSocketBuilder()
.OnClose(server =>
{
Console.WriteLine($"客戶端關(guān)閉");
})
.OnException(ex =>
{
Console.WriteLine($"客戶端異常:{ex.Message}");
})
.OnRecieve((server, point, bytes) =>
{
Console.WriteLine($"客戶端:收到來(lái)自[{point.ToString()}]數(shù)據(jù):{Encoding.UTF8.GetString(bytes)}");
})
.OnSend((server, point, bytes) =>
{
Console.WriteLine($"客戶端發(fā)送數(shù)據(jù):目標(biāo)[{point.ToString()}]數(shù)據(jù):{Encoding.UTF8.GetString(bytes)}");
})
.OnStarted(server =>
{
Console.WriteLine($"客戶端啟動(dòng)");
}).BuildAsync();
while (true)
{
await theClient.Send(Guid.NewGuid().ToString(), new IPEndPoint(IPAddress.Parse("127.0.0.1"), 6003));
await Task.Delay(1000);
}
}
}
}
WebSocket
WebSocket與TcpSocket接口基本保持一致,僅有的區(qū)別就是TcpSocket支持字節(jié)的收發(fā)并且需要自行處理分包粘包。
而WebSocket直接收發(fā)字符串(UTF-8)編碼,并且無(wú)需考慮分包粘包??蚣苣壳皼](méi)有支持WSS,建議解決方案是使用Nginx轉(zhuǎn)發(fā)即可(相關(guān)資料一搜便有)
using Coldairarrow.DotNettySocket;
using System;
using System.Threading.Tasks;
namespace WebSocket.Server
{
class Program
{
static async Task Main(string[] args)
{
var theServer = await SocketBuilderFactory.GetWebSocketServerBuilder(6002)
.OnConnectionClose((server, connection) =>
{
Console.WriteLine($"連接關(guān)閉,連接名[{connection.ConnectionName}],當(dāng)前連接數(shù):{server.GetConnectionCount()}");
})
.OnException(ex =>
{
Console.WriteLine($"服務(wù)端異常:{ex.Message}");
})
.OnNewConnection((server, connection) =>
{
connection.ConnectionName = $"名字{connection.ConnectionId}";
Console.WriteLine($"新的連接:{connection.ConnectionName},當(dāng)前連接數(shù):{server.GetConnectionCount()}");
})
.OnRecieve((server, connection, msg) =>
{
Console.WriteLine($"服務(wù)端:數(shù)據(jù){msg}");
connection.Send(msg);
})
.OnSend((server, connection, msg) =>
{
Console.WriteLine($"向連接名[{connection.ConnectionName}]發(fā)送數(shù)據(jù):{msg}");
})
.OnServerStarted(server =>
{
Console.WriteLine($"服務(wù)啟動(dòng)");
}).BuildAsync();
Console.ReadLine();
}
}
}
using Coldairarrow.DotNettySocket;
using System;
using System.Threading.Tasks;
namespace WebSocket.ConsoleClient
{
class Program
{
static async Task Main(string[] args)
{
var theClient = await SocketBuilderFactory.GetWebSocketClientBuilder("127.0.0.1", 6002)
.OnClientStarted(client =>
{
Console.WriteLine($"客戶端啟動(dòng)");
})
.OnClientClose(client =>
{
Console.WriteLine($"客戶端關(guān)閉");
})
.OnException(ex =>
{
Console.WriteLine($"異常:{ex.Message}");
})
.OnRecieve((client, msg) =>
{
Console.WriteLine($"客戶端:收到數(shù)據(jù):{msg}");
})
.OnSend((client, msg) =>
{
Console.WriteLine($"客戶端:發(fā)送數(shù)據(jù):{msg}");
})
.BuildAsync();
while (true)
{
await theClient.Send(Guid.NewGuid().ToString());
await Task.Delay(1000);
}
}
}
}
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>菜鳥(niǎo)教程(runoob.com)</title>
<script type="text/javascript">
function WebSocketTest() {
if ("WebSocket" in window) {
var ws = new WebSocket("ws://127.0.0.1:6002");
ws.onopen = function () {
console.log('連上服務(wù)端');
setInterval(function () {
ws.send("111111");
}, 1000);
};
ws.onmessage = function (evt) {
var received_msg = evt.data;
console.log('收到' + received_msg);
};
ws.onclose = function () {
console.log("連接已關(guān)閉...");
};
}
else {
alert("您的瀏覽器不支持 WebSocket!");
}
}
</script>
</head>
<body>
<div id="sse">
<a href="javascript:WebSocketTest()">運(yùn)行 WebSocket</a>
</div>
</body>
</html>
UdpSocket
Udp天生便是收發(fā)一體的,以下分為服務(wù)端與客戶端僅僅是為了方便理解
using Coldairarrow.DotNettySocket;
using System;
using System.Text;
using System.Threading.Tasks;
namespace UdpSocket.Server
{
class Program
{
static async Task Main(string[] args)
{
var theServer = await SocketBuilderFactory.GetUdpSocketBuilder(6003)
.OnClose(server =>
{
Console.WriteLine($"服務(wù)端關(guān)閉");
})
.OnException(ex =>
{
Console.WriteLine($"服務(wù)端異常:{ex.Message}");
})
.OnRecieve((server, point, bytes) =>
{
Console.WriteLine($"服務(wù)端:收到來(lái)自[{point.ToString()}]數(shù)據(jù):{Encoding.UTF8.GetString(bytes)}");
server.Send(bytes, point);
})
.OnSend((server, point, bytes) =>
{
Console.WriteLine($"服務(wù)端發(fā)送數(shù)據(jù):目標(biāo)[{point.ToString()}]數(shù)據(jù):{Encoding.UTF8.GetString(bytes)}");
})
.OnStarted(server =>
{
Console.WriteLine($"服務(wù)端啟動(dòng)");
}).BuildAsync();
Console.ReadLine();
}
}
}
using Coldairarrow.DotNettySocket;
using System;
using System.Net;
using System.Text;
using System.Threading.Tasks;
namespace UdpSocket.Client
{
class Program
{
static async Task Main(string[] args)
{
var theClient = await SocketBuilderFactory.GetUdpSocketBuilder()
.OnClose(server =>
{
Console.WriteLine($"客戶端關(guān)閉");
})
.OnException(ex =>
{
Console.WriteLine($"客戶端異常:{ex.Message}");
})
.OnRecieve((server, point, bytes) =>
{
Console.WriteLine($"客戶端:收到來(lái)自[{point.ToString()}]數(shù)據(jù):{Encoding.UTF8.GetString(bytes)}");
})
.OnSend((server, point, bytes) =>
{
Console.WriteLine($"客戶端發(fā)送數(shù)據(jù):目標(biāo)[{point.ToString()}]數(shù)據(jù):{Encoding.UTF8.GetString(bytes)}");
})
.OnStarted(server =>
{
Console.WriteLine($"客戶端啟動(dòng)");
}).BuildAsync();
while (true)
{
await theClient.Send(Guid.NewGuid().ToString(), new IPEndPoint(IPAddress.Parse("127.0.0.1"), 6003));
await Task.Delay(1000);
}
}
}
}
結(jié)尾
以上所有示例在源碼中都有,希望能夠幫助到大家。
- EOF -
該文章在 2025/6/20 10:33:06 編輯過(guò)