目錄 "簡介" "產生背景" "使用方式" "TcpSocket" "WebSocket" "UdpSocket" "結尾" 簡介 DotNettySocket是一個.NET跨平臺Socket框架(支持.NET4.5+及.NET Standard2.0+),同時支持TcpSocket、WebSock ...
目錄
簡介
DotNettySocket是一個.NET跨平臺Socket框架(支持.NET4.5+及.NET Standard2.0+),同時支持TcpSocket、WebSocket和UdpSocket,其基於微軟強大的DotNetty框架,力求為Socket通訊提供簡單、高效、優雅的操作方式。
安裝方式:Nuget安裝DotNettySocket即可
項目地址:https://github.com/Coldairarrow/DotNettySocket
產生背景
兩年前最開始接觸物聯網的時候,需要用到Tcp及Udp通訊,為了方便使用,將原始的Socket進行了簡單的封裝,基本滿足了需求,並將框架開源。但是由於精力及實力有限,沒有進一步優化原框架。後來發現了強大的DotNetty框架,DotNetty是微軟Azure團隊開源基於Java Netty框架的移植版,其性能優異、維護團隊強大,許多.NET強大的框架都使用它。DotNetty功能強大,但是用起來還是不夠簡潔(或許是個人感覺),剛好最近項目需要用到WebSocket,因此鄙人抽時間基於DotNetty進行簡單封裝了下,擼出一個力求簡單、高效、優雅的Socket框架。
使用方式
TcpSocket
Tcp是面向連接的,所以服務端對連接的管理就至關重要,框架支持各種事件的處理、給連接設置連接名(身份標識)、通過連接名找到特定連接、連接收發數據、分包、粘包處理。
- 服務端
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($"連接關閉,連接名[{connection.ConnectionName}],當前連接數:{server.GetConnectionCount()}");
})
.OnException(ex =>
{
Console.WriteLine($"服務端異常:{ex.Message}");
})
.OnNewConnection((server, connection) =>
{
connection.ConnectionName = $"名字{connection.ConnectionId}";
Console.WriteLine($"新的連接:{connection.ConnectionName},當前連接數:{server.GetConnectionCount()}");
})
.OnRecieve((server, connection, bytes) =>
{
Console.WriteLine($"服務端:數據{Encoding.UTF8.GetString(bytes)}");
connection.Send(bytes);
})
.OnSend((server, connection, bytes) =>
{
Console.WriteLine($"向連接名[{connection.ConnectionName}]發送數據:{Encoding.UTF8.GetString(bytes)}");
})
.OnServerStarted(server =>
{
Console.WriteLine($"服務啟動");
}).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($"客戶端關閉");
})
.OnException(ex =>
{
Console.WriteLine($"客戶端異常:{ex.Message}");
})
.OnRecieve((server, point, bytes) =>
{
Console.WriteLine($"客戶端:收到來自[{point.ToString()}]數據:{Encoding.UTF8.GetString(bytes)}");
})
.OnSend((server, point, bytes) =>
{
Console.WriteLine($"客戶端發送數據:目標[{point.ToString()}]數據:{Encoding.UTF8.GetString(bytes)}");
})
.OnStarted(server =>
{
Console.WriteLine($"客戶端啟動");
}).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介面基本保持一致,僅有的區別就是TcpSocket支持位元組的收發並且需要自行處理分包粘包。而WebSocket直接收發字元串(UTF-8)編碼,並且無需考慮分包粘包。框架目前沒有支持WSS,建議解決方案是使用Nginx轉發即可(相關資料一搜便有)
- 服務端
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($"連接關閉,連接名[{connection.ConnectionName}],當前連接數:{server.GetConnectionCount()}");
})
.OnException(ex =>
{
Console.WriteLine($"服務端異常:{ex.Message}");
})
.OnNewConnection((server, connection) =>
{
connection.ConnectionName = $"名字{connection.ConnectionId}";
Console.WriteLine($"新的連接:{connection.ConnectionName},當前連接數:{server.GetConnectionCount()}");
})
.OnRecieve((server, connection, msg) =>
{
Console.WriteLine($"服務端:數據{msg}");
connection.Send(msg);
})
.OnSend((server, connection, msg) =>
{
Console.WriteLine($"向連接名[{connection.ConnectionName}]發送數據:{msg}");
})
.OnServerStarted(server =>
{
Console.WriteLine($"服務啟動");
}).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($"客戶端啟動");
})
.OnClientClose(client =>
{
Console.WriteLine($"客戶端關閉");
})
.OnException(ex =>
{
Console.WriteLine($"異常:{ex.Message}");
})
.OnRecieve((client, msg) =>
{
Console.WriteLine($"客戶端:收到數據:{msg}");
})
.OnSend((client, msg) =>
{
Console.WriteLine($"客戶端:發送數據:{msg}");
})
.BuildAsync();
while (true)
{
await theClient.Send(Guid.NewGuid().ToString());
await Task.Delay(1000);
}
}
}
}
- 網頁客戶端
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>菜鳥教程(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('連上服務端');
setInterval(function () {
ws.send("111111");
}, 1000);
};
ws.onmessage = function (evt) {
var received_msg = evt.data;
console.log('收到' + received_msg);
};
ws.onclose = function () {
console.log("連接已關閉...");
};
}
else {
alert("您的瀏覽器不支持 WebSocket!");
}
}
</script>
</head>
<body>
<div id="sse">
<a href="javascript:WebSocketTest()">運行 WebSocket</a>
</div>
</body>
</html>
UdpSocket
Udp天生便是收發一體的,以下分為服務端與客戶端僅僅是為了方便理解
- 服務端
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($"服務端關閉");
})
.OnException(ex =>
{
Console.WriteLine($"服務端異常:{ex.Message}");
})
.OnRecieve((server, point, bytes) =>
{
Console.WriteLine($"服務端:收到來自[{point.ToString()}]數據:{Encoding.UTF8.GetString(bytes)}");
server.Send(bytes, point);
})
.OnSend((server, point, bytes) =>
{
Console.WriteLine($"服務端發送數據:目標[{point.ToString()}]數據:{Encoding.UTF8.GetString(bytes)}");
})
.OnStarted(server =>
{
Console.WriteLine($"服務端啟動");
}).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($"客戶端關閉");
})
.OnException(ex =>
{
Console.WriteLine($"客戶端異常:{ex.Message}");
})
.OnRecieve((server, point, bytes) =>
{
Console.WriteLine($"客戶端:收到來自[{point.ToString()}]數據:{Encoding.UTF8.GetString(bytes)}");
})
.OnSend((server, point, bytes) =>
{
Console.WriteLine($"客戶端發送數據:目標[{point.ToString()}]數據:{Encoding.UTF8.GetString(bytes)}");
})
.OnStarted(server =>
{
Console.WriteLine($"客戶端啟動");
}).BuildAsync();
while (true)
{
await theClient.Send(Guid.NewGuid().ToString(), new IPEndPoint(IPAddress.Parse("127.0.0.1"), 6003));
await Task.Delay(1000);
}
}
}
}
結尾
以上所有示例在源碼中都有,若覺得不錯請點贊加星星,希望能夠幫助到大家。
有任何問題請及時反饋或加群交流
QQ群1:(已滿)
QQ群2:579202910