開源地址:https://github.com/hiramtan/HiSocket
HiSocket
輕量Socket通信邏輯,可以在C#項目或Unity3d項目中使用.
如何使用
可以選擇使用dll或者使用源碼,把它添加到自己的工程中即可使用.
- Dll: HiSocket_xx.zip
- 源碼: 源碼
快速開始:
//tcp example private IPackage package = new PackageExample(); private TcpConnection tcp; void Init() { tcp = new TcpConnection(package); tcp.OnConnected += OnConnected; tcp.OnReceive += OnReceive; //... //... tcp.Connect("127.0.0.1",999); } void OnConnected() { //connect success tcp.Send(new byte[10]);//send message } void OnReceive(byte[] bytes) { //get message from server }
更多示例:
- C#項目示例:示例
- Unity項目示例:示例
總覽
項目包含:
- Connection
- TcpConnection
- TcpSocket
- Package
- UdpConnection
- UdpSocket
- Plugin
- Message
- Message register
- Aes encryption
- Byte message
- Protobuf message
功能
- Tcp socket
- Udp socket
- 可伸縮字節表
- 高性能字節塊緩沖區
- 消息注冊和回調
- 二進制字節消息封裝
- Protobuf消息封裝
- AES消息加密
詳情
- Tcp和Udp都是采用主線程異步連接的方式(避免主線程阻塞).
- 高性能字節緩沖區避免內存空間重復申請,減少GC.
- 可以添加一系列的事件監聽獲取當前的連接狀態.
- 如果使用Tcp協議需要實現IPackage接口處理粘包拆包.
- 如果使用Udp協議需要聲明緩沖區大小.
- Ping: 源碼包含一個Ping插件可以使用,但是如果用在unity3d工程中會報錯(因為mono的問題,在.net2.0會報錯.net4.6可以正常使用)
高級功能
- 如果對Socket很熟悉,也可以使用TcpSocket(UdpSocket)來實現功能,但是還是推薦使用TcpConnection(UdpConnection)的方式.
- 通過接口可以訪問底層Socket對象擴展邏輯,比如修改超時時間.
- 通過接口可以獲得發送接收緩沖區,比如斷開連接時是否要將發送緩沖區數據全部發出?重連后怎樣處理發送緩沖區的數據.
- OnSocketReceive和OnReceive是不同的,比如當OnSocketReceive接受大小是100字節,當用戶解包時不做操作,OnReceive大小是100字節,當用戶解包時做解壓縮(解密等)操作后,OnReceive大小不再是100.
- 可以向TcpConnection(UdpConnection)添加不同的插件完成所需的功能,
- 注冊基類可以方便快速注冊消息(基於反射)
- Byte block buffer 采用有序鏈表實現,當有區塊空閑時會重用區塊.
- .etc
介紹
Tcp 協議提供可靠有序的流字節傳輸,用戶需要自己分割數據,在這個框架中可以繼承IPackage接口來實現.
Tcp協議傳輸字節流,用戶需要分割字節流獲得正確的數據包,當創建一個tcp協議的socket時,需要傳入一個Package對象來封包和解包.
最初創建連接時我們定義了一個packer來分割數據包,當發送消息時我們在數據頭部插入消息長度/當接收到消息時我們根據頭部的消息長度獲得數據包的大小.
Udp協議提供不可靠的報文消息,用戶無法知道當前連接狀態,但是消息包時完整的.
如果創建upd連接,需要指定發送接收緩沖區大小.
- Ping :
因為mono在.net2.0和2.0 subset的bug,可以在unity3d使用如下邏輯獲取ping值.csharp
public int PingTime;
private Ping p;
private float timeOut = 1;
private float lastTime;
void Start()
{
StartCoroutine(Ping());
}
IEnumerator Ping()
{
p = new Ping("127.0.0.1");
lastTime = Time.realtimeSinceStartup;
while (!p.isDone && Time.realtimeSinceStartup - lastTime < 1)
{
yield return null;
}
PingTime = p.time;
p.DestroyPing();
yield return new WaitForSeconds(1);
StartCoroutine(Ping());
} - 消息注冊
- Protobuf
- 字節消息
- 加密
Example
在HiSocketExample 和 HiSocket.unitypackage有很多示例, 其中有一些如下:
Package example:
/// <summary> /// Example: Used to pack or unpack message /// You should inheritance IPackage interface and implement your own logic /// </summary> class PackageExample : IPackage { /// <summary> /// Pack your message here(this is only an example) /// </summary> /// <param name="source"></param> /// <param name="unpackedHandler"></param> public void Unpack(IByteArray source, Action<byte[]> unpackedHandler) { // Unpack your message(use int, 4 byte as head) while (source.Length >= 4) { var head = source.Read(4); int bodyLength = BitConverter.ToInt32(head, 0);// get body's length if (source.Length >= bodyLength) { var unpacked = source.Read(bodyLength);// get body unpackedHandler(unpacked); } else { source.Insert(0, head);// rewrite in, used for next time } } } /// <summary> /// Unpack your message here(this is only an example) /// </summary> /// <param name="source"></param> /// <param name="packedHandler"></param> public void Pack(IByteArray source, Action<byte[]> packedHandler) { // Add head length to your message(use int, 4 byte as head) var length = source.Length; var head = BitConverter.GetBytes(length); source.Insert(0, head);// add head bytes var packed = source.Read(source.Length); packedHandler(packed); } }
private IPackage _package = new PackageExample(); private TcpConnection _tcp; static void Main(string[] args) { } void Init() { _tcp = new TcpConnection(_package); _tcp.OnConnected += OnConnected; _tcp.OnReceive += Receive; //_tcp.OnError //_tcp.OnDisconnected } void OnConnected() { //connect success _tcp.Send(new byte[10]);//send message _tcp.DisConnect();//disconnect } void Receive(byte[] bytes) { //get message from server }
void Init() { var tcp = new TcpConnection(new PackageExample()); tcp.AddPlugin(new PingPlugin("ping", tcp)); //tcp.GetPlugin("ping"); }