解决MySql布尔型新旧版本兼容问题,采用枚举来表示布尔型的数据表。由正向工程赋值
|
# NewLife.Net ÍøÂç¿âʹÓÃÊÖ²á
## Ŀ¼
- [¸ÅÊö](/NewLife/X/Blob/dev/Doc/#¸ÅÊö)
- [¼Ü¹¹Éè¼Æ](/NewLife/X/Blob/dev/Doc/#¼Ü¹¹Éè¼Æ)
- [¿ìËÙÈëÃÅ](/NewLife/X/Blob/dev/Doc/#¿ìËÙÈëÃÅ)
- [ºËÐÄ×é¼þ](/NewLife/X/Blob/dev/Doc/#ºËÐÄ×é¼þ)
- [¸ß¼¶ÌØÐÔ](/NewLife/X/Blob/dev/Doc/#¸ß¼¶ÌØÐÔ)
- [×î¼Ñʵ¼ù](/NewLife/X/Blob/dev/Doc/#×î¼Ñʵ¼ù)
- [ÐÔÄÜÓÅ»¯](/NewLife/X/Blob/dev/Doc/#ÐÔÄÜÓÅ»¯)
- [³£¼ûÎÊÌâ](/NewLife/X/Blob/dev/Doc/#³£¼ûÎÊÌâ)
---
## ¸ÅÊö
NewLife.Net ÊÇÐÂÉúÃüÍŶӿª·¢µÄ¸ßÐÔÄÜÍøÂçͨÐſ⣬֧³Ö TCP/UDP ÐÒ飬ͬʱ¼æÈÝ IPv4 ºÍ IPv6¡£¸Ã¿âÉè¼Æ¾«Á¼£¬¾Ã¾Éú²ú»·¾³¿¼Ñ飬ÊÊÓÃÓÚ¹¹½¨¸÷ÖÖÍøÂçÓ¦Ó÷þÎñÆ÷¡£
### ÌØÐÔ
- **¶àÐÒéÖ§³Ö**£ºÍ¬Ê±Ö§³Ö TCP ºÍ UDP ÐÒé
- **˫ջ֧³Ö**£ºÍêÃÀÖ§³Ö IPv4 ºÍ IPv6
- **¸ßÐÔÄÜ**£º»ùÓÚÒì²½ IO Ä£ÐÍ£¬Ê¹Óà IOCP ʵÏָ߲¢·¢
- **¹ÜµÀ´¦Àí**£ºÁé»îµÄÏûÏ¢¹ÜµÀ£¬Ö§³ÖÐÒé±à½âÂë
- **SSL/TLS**£ºÔÉúÖ§³Ö°²È«´«Êä
- **»á»°¹ÜÀí**£ºÍêÉÆµÄÁ¬½Ó»á»°¹ÜÀí»úÖÆ
- **Ḭ̈߳²È«**£ºËùÓкËÐIJÙ×÷²ÉÓÃÔ×Ó²Ù×÷±£Ö¤Ḭ̈߳²È«
- **¿ÉÀ©Õ¹**£ºÒ×ÓÚÀ©Õ¹µÄ¼Ü¹¹Éè¼Æ
### ÊÊÓó¡¾°
- ¼´Ê±Í¨Ñ¶·þÎñÆ÷
- ÓÎÏ··þÎñÆ÷
- ÎïÁªÍøÊý¾Ý²É¼¯
- RPC Ô¶³Ìµ÷ÓÃ
- ×Ô¶¨ÒåÐÒé·þÎñ
---
## ¼Ü¹¹Éè¼Æ
### ÕûÌå¼Ü¹¹
```
©°©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©´
©¦ Ó¦Óò㠩¦
©¦ NetServer / NetServer<TSession> ©¦
©¦ ©À©¤©¤ INetSession (»á»°¹ÜÀí) ©¦
©¦ ©À©¤©¤ INetHandler (Êý¾Ý´¦ÀíÆ÷) ©¦
©¦ ©¸©¤©¤ Pipeline (ÏûÏ¢¹ÜµÀ) ©¦
©À©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©È
©¦ Socket·þÎñ²ã ©¦
©¦ ISocketServer ©¦
©¦ ©À©¤©¤ TcpServer (TCP·þÎñ¶Ë) ©¦
©¦ ©¸©¤©¤ UdpServer (UDP·þÎñ¶Ë) ©¦
©À©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©È
©¦ Socket»á»°²ã ©¦
©¦ ISocketSession ©¦
©¦ ©À©¤©¤ TcpSession (TCP»á»°) ©¦
©¦ ©¸©¤©¤ UdpSession (UDP»á»°) ©¦
©À©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©È
©¦ »ù´¡ÉèÊ©²ã ©¦
©¦ SessionBase ©¦
©¦ ©À©¤©¤ ProcessEvent (ºËÐĽÓÊÕ´¦Àí) ©¦
©¦ ©À©¤©¤ Òì²½IO (SocketAsyncEventArgs) ©¦
©¦ ©¸©¤©¤ »º³åÇø¹ÜÀí ©¦
©¸©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¼
```
### ºËÐÄÀà¹ØÏµ
```
NetServer
©À©¤©¤ ISocketServer[] Servers // Socket·þÎñÆ÷¼¯ºÏ
©¦ ©À©¤©¤ TcpServer // TCP·þÎñ
©¦ ©¸©¤©¤ UdpServer // UDP·þÎñ
©À©¤©¤ IDictionary<Int32, INetSession> Sessions // ÍøÂç»á»°¼¯ºÏ
©¸©¤©¤ IPipeline Pipeline // ÏûÏ¢¹ÜµÀ
INetSession (ÍøÂç»á»°)
©À©¤©¤ ISocketSession Session // µ×²ãSocket»á»°
©À©¤©¤ NetServer Host // ËùÊô·þÎñÆ÷
©¸©¤©¤ INetHandler Handler // Êý¾Ý´¦ÀíÆ÷
ISocketSession (Socketȇȡ)
©À©¤©¤ TcpSession // TCPÁ¬½Ó»á»°
©¸©¤©¤ UdpSession // UDPÁ¬½Ó»á»°
```
### Êý¾ÝÁ÷Ïò
**½ÓÊÕÊý¾ÝÁ÷**£º
```
Socket½ÓÊÕ ¡ú ProcessEvent ¡ú OnPreReceive ¡ú Pipeline.Read ¡ú OnReceive ¡ú Receivedʼþ
```
**·¢ËÍÊý¾ÝÁ÷**£º
```
Send/SendMessage ¡ú Pipeline.Write ¡ú OnSend ¡ú Socket·¢ËÍ
```
### ÉúÃüÖÜÆÚ
```
[¿Í»§¶ËÁ¬½Ó] ¡ú [´´½¨ISocketSession] ¡ú [Server_NewSession]
¡ý
[OnNewSession] ¡ú [CreateSession] ¡ú [AddSession]
¡ý
[NetSession.Start()] ¡ú [OnConnected]
¡ý
[Êý¾ÝÊÕ·¢Ñ»·]
¡ý
[¿Í»§¶Ë¶Ï¿ª/³¬Ê±] ¡ú [Close(reason)] ¡ú [OnDisconnected] ¡ú [Dispose]
```
---
## ¿ìËÙÈëÃÅ
### ×î¼òµ¥µÄ Echo ·þÎñÆ÷
```csharp
using NewLife.Net;
// ´´½¨·þÎñÆ÷
var server = new NetServer
{
Port = 12345, // ¼àÌý¶Ë¿Ú
Log = XTrace.Log, // ÆôÓÃÈÕÖ¾
};
// ´¦Àí½ÓÊÕÊý¾Ý
server.Received += (sender, e) =>
{
if (sender is INetSession session)
{
// Echo »Ø¸´
session.Send(e.Packet);
}
};
// Æô¶¯·þÎñ
server.Start();
Console.WriteLine($"·þÎñÒÑÆô¶¯£¬¼àÌý¶Ë¿Ú£º{server.Port}");
Console.ReadLine();
// Í£Ö¹·þÎñ
server.Stop("Manual");
```
### ´´½¨¿Í»§¶ËÁ¬½Ó
```csharp
using NewLife.Net;
// ´´½¨TCP¿Í»§¶Ë
var uri = new NetUri("tcp://127.0.0.1:12345");
var client = uri.CreateRemote();
client.Log = XTrace.Log;
// ´ò¿ªÁ¬½Ó
client.Open();
// ·¢ËÍÊý¾Ý
client.Send("Hello Server");
// ½ÓÊÕÊý¾Ý
var pk = client.Receive();
Console.WriteLine($"ÊÕµ½£º{pk.ToStr()}");
// ¹Ø±ÕÁ¬½Ó
client.Close("Done");
```
### ʹÓà UDP ÐÒé
```csharp
// ·þÎñ¶Ë
var server = new NetServer
{
Port = 12345,
ProtocolType = NetType.Udp, // Ö¸¶¨UDP
};
server.Start();
// ¿Í»§¶Ë
var uri = new NetUri("udp://127.0.0.1:12345");
var client = uri.CreateRemote();
client.Open();
client.Send("Hello UDP");
```
---
## ºËÐÄ×é¼þ
### NetServer - ÍøÂç·þÎñÆ÷
NetServer ÊÇÍøÂç·þÎñÆ÷µÄÖ÷Èë¿Ú£¬¹ÜÀí¶à¸öµ×²ã Socket ·þÎñÆ÷¡£
#### »ù±¾ÅäÖÃ
```csharp
var server = new NetServer
{
// »ù±¾ÅäÖÃ
Name = "MyServer", // ·þÎñÃû£¨Ä¬ÈÏÀàÃûÈ¥µôServerºó׺£©
Port = 12345, // ¼àÌý¶Ë¿Ú£¬0ÎªËæ»ú¶Ë¿Ú
ProtocolType = NetType.Tcp, // ÐÒéÀàÐÍ£ºTcp/Udp/Unknown(ͬʱ¼àÌý)
AddressFamily = AddressFamily.InterNetwork, // µØÖ·×壺IPv4/IPv6/Unspecified(ͬʱ)
// »á»°ÅäÖÃ
SessionTimeout = 1200, // »á»°³¬Ê±£¨Ã룩£¬Ä¬ÈÏ20·ÖÖÓ
UseSession = true, // ÊÇ·ñʹÓûỰ¼¯ºÏ
// SSLÅäÖÃ
SslProtocol = SslProtocols.Tls12, // SSLÐÒé°æ±¾
Certificate = cert, // X509Ö¤Êé
// ÈÕÖ¾ÅäÖÃ
Log = XTrace.Log, // ·þÎñÆ÷ÈÕÖ¾
SocketLog = XTrace.Log, // SocketÈÕÖ¾
SessionLog = XTrace.Log, // »á»°ÈÕÖ¾
LogSend = true, // ¼Ç¼·¢ËÍÈÕÖ¾
LogReceive = true, // ¼Ç¼½ÓÊÕÈÕÖ¾
// ÐÔÄÜÅäÖÃ
StatPeriod = 600, // ͳ¼ÆÖÜÆÚ£¨Ã룩£¬0½ûÓÃ
ReuseAddress = true, // µØÖ·ÖØÓÃ
// ×·×ÙÅäÖÃ
Tracer = tracer, // APM×·×ÙÆ÷
SocketTracer = tracer, // Socket²ã×·×ÙÆ÷
// ÒÀÀµ×¢Èë
ServiceProvider = serviceProvider, // ·þÎñÌṩÕß
};
```
#### ÐÒéÀàÐÍÅäÖÃ
```csharp
// ½ö¼àÌý TCP
server.ProtocolType = NetType.Tcp;
// ½ö¼àÌý UDP
server.ProtocolType = NetType.Udp;
// ͬʱ¼àÌý TCP ºÍ UDP£¨Ä¬ÈÏ£©
server.ProtocolType = NetType.Unknown;
// HTTP/WebSocket£¨×Ô¶¯ÆôÓÃHTTP½âÎö£©
server.ProtocolType = NetType.Http;
```
#### µØÖ·×åÅäÖÃ
```csharp
// ½ö IPv4
server.AddressFamily = AddressFamily.InterNetwork;
// ½ö IPv6
server.AddressFamily = AddressFamily.InterNetworkV6;
// ͬʱ¼àÌý IPv4 ºÍ IPv6£¨Ä¬ÈÏ£©
server.AddressFamily = AddressFamily.Unspecified;
```
#### ʼþ´¦Àí
```csharp
// лỰʼþ
server.NewSession += (sender, e) =>
{
var session = e.Session;
Console.WriteLine($"ÐÂÁ¬½Ó£º{session.Remote}");
};
// Êý¾Ý½ÓÊÕʼþ
server.Received += (sender, e) =>
{
if (sender is INetSession session)
{
Console.WriteLine($"ÊÕµ½[{session.Remote}]£º{e.Packet?.ToStr()}");
// ´¦Àí½âÂëºóµÄÏûÏ¢
if (e.Message != null)
{
// ´¦ÀíÏûÏ¢¶ÔÏó
}
}
};
// ´íÎóʼþ
server.Error += (sender, e) =>
{
Console.WriteLine($"´íÎó£º{e.Exception.Message}");
};
```
#### »á»°¹ÜÀí
```csharp
// »ñȡָ¶¨»á»°
var session = server.GetSession(sessionId);
// ±éÀúËùÓлỰ
foreach (var item in server.Sessions)
{
Console.WriteLine($"ȇȡ {item.Key}: {item.Value.Remote}");
}
// µ±Ç°»á»°ÊýºÍ×î¸ß»á»°Êý
Console.WriteLine($"ÔÚÏß: {server.SessionCount}/{server.MaxSessionCount}");
```
#### ÊÖ¶¯Ìí¼Ó·þÎñÆ÷
```csharp
// ·½Ê½1£ºÊ¹Óà AddServer
server.AddServer(IPAddress.Any, 8080, NetType.Tcp);
server.AddServer(IPAddress.Any, 8081, NetType.Udp);
// ·½Ê½2£ºÊ¹Óà AttachServer
var tcpServer = new TcpServer { Port = 8080 };
server.AttachServer(tcpServer);
// ·½Ê½3£ºÖØÔØ EnsureCreateServer
public class MyServer : NetServer
{
public override void EnsureCreateServer()
{
if (Servers.Count > 0) return;
var tcp = new TcpServer { Port = Port };
AttachServer(tcp);
}
}
```
### NetSession - ÍøÂç»á»°
ÿ¸öÁ¬½Ó¶ÔÓ¦Ò»¸ö»á»°£¬ÓÃÓÚ´¦Àí¸ÃÁ¬½ÓµÄÒµÎñÂß¼¡£
#### ×Ô¶¨Òå»á»°
```csharp
public class MySession : NetSession
{
/// <summary>Óû§ID</summary>
public Int32 UserId { get; set; }
/// <summary>Á¬½Óʱ¼ä</summary>
public DateTime ConnectTime { get; set; }
/// <summary>Á¬½Ó½¨Á¢</summary>
protected override void OnConnected()
{
base.OnConnected();
ConnectTime = DateTime.Now;
WriteLog("¿Í»§¶ËÒÑÁ¬½Ó");
// ·¢ËÍ»¶ÓÏûÏ¢
Send("Welcome!");
}
/// <summary>Á¬½Ó¶Ï¿ª</summary>
protected override void OnDisconnected(String reason)
{
base.OnDisconnected(reason);
WriteLog($"¿Í»§¶ËÒѶϿª£º{reason}");
}
/// <summary>ÊÕµ½Êý¾Ý</summary>
protected override void OnReceive(ReceivedEventArgs e)
{
base.OnReceive(e);
// ÔʼÊý¾Ý°ü
var pk = e.Packet;
// ¾¹ý¹ÜµÀ½âÂëºóµÄÏûÏ¢¶ÔÏó
var msg = e.Message;
// ÒµÎñ´¦Àí
ProcessData(pk, msg);
}
/// <summary>·¢Éú´íÎó</summary>
protected override void OnError(Object? sender, ExceptionEventArgs e)
{
base.OnError(sender, e);
WriteError("·¢Éú´íÎó£º{0}", e.Exception.Message);
}
private void ProcessData(IPacket? pk, Object? msg)
{
// ÒµÎñÂß¼
}
}
// ʹÓ÷ºÐÍ·þÎñÆ÷
var server = new NetServer<MySession>
{
Port = 12345,
};
server.Start();
// »ñȡָ¶¨»á»°£¨Ç¿ÀàÐÍ£©
var session = server.GetSession(sessionId);
if (session != null)
{
session.UserId = 123;
session.Send("Hello");
}
```
#### ·¢ËÍÊý¾Ý
```csharp
public class MySession : NetSession
{
public void SendData()
{
// ·¢ËÍ×Ö½ÚÊý×é
Send(new Byte[] { 0x01, 0x02, 0x03 });
Send(data, offset, count);
// ·¢ËÍ×Ö·û´®£¨Ä¬ÈÏUTF-8£©
Send("Hello World");
Send("ÄãºÃ", Encoding.UTF8);
// ·¢ËÍÊý¾Ý°ü
var packet = new ArrayPacket(data);
Send(packet);
// ·¢ËÍÁ÷
using var stream = File.OpenRead("data.bin");
Send(stream);
// ·¢ËÍSpan£¨¸ßÐÔÄÜ£¬Á㿽±´£©
ReadOnlySpan<Byte> span = stackalloc Byte[100];
Send(span);
// ͨ¹ý¹ÜµÀ·¢ËÍÏûÏ¢£¨»á¾¹ý±àÂëÆ÷£©
var bytes = SendMessage(new MyRequest { Cmd = "ping" });
// ·¢ËÍÏìÓ¦ÏûÏ¢£¨¹ØÁªÇëÇóÉÏÏÂÎÄ£©
SendReply(new MyResponse { Result = "OK" }, e);
}
// Òì²½·¢ËͲ¢µÈ´ýÏìÓ¦
public async Task<MyResponse> QueryAsync()
{
var response = await SendMessageAsync(new MyRequest { Cmd = "query" });
return response as MyResponse;
}
// ´ø³¬Ê±µÄÒì²½ÇëÇó
public async Task<MyResponse> QueryWithTimeoutAsync()
{
using var cts = new CancellationTokenSource(5000);
var response = await SendMessageAsync(request, cts.Token);
return response as MyResponse;
}
}
```
#### »á»°Êý¾Ý´æ´¢
```csharp
public class MySession : NetSession
{
protected override void OnConnected()
{
base.OnConnected();
// ʹÓÃË÷ÒýÆ÷´æ´¢Êý¾Ý£¨Óëµ×²ãSocket»á»°¹²Ïí£©
this["userId"] = 12345;
this["loginTime"] = DateTime.Now;
// ʹÓà Items ×Öµä
Items["userData"] = new UserData();
}
protected override void OnReceive(ReceivedEventArgs e)
{
base.OnReceive(e);
// ¶ÁÈ¡»á»°Êý¾Ý
var userId = (Int32)this["userId"];
var userData = Items["userData"] as UserData;
}
}
```
#### ·ºÐͻỰ£¨Ç¿ÀàÐÍHost·ÃÎÊ£©
```csharp
// ×Ô¶¨Òå·þÎñÆ÷
public class GameServer : NetServer<GameSession>
{
public GameConfig Config { get; set; }
public IDatabase Database { get; set; }
}
// ×Ô¶¨Òå»á»°
public class GameSession : NetSession<GameServer>
{
protected override void OnReceive(ReceivedEventArgs e)
{
base.OnReceive(e);
// Ö±½Ó·ÃÎÊ×Ô¶¨Òå·þÎñÆ÷ÊôÐÔ£¨Ç¿ÀàÐÍ£©
var config = Host.Config;
var db = Host.Database;
}
}
```
### Pipeline - ÏûÏ¢¹ÜµÀ
¹ÜµÀÓÃÓÚÐÒé±à½âÂ룬֧³ÖÁ´Ê½´¦Àí¡£
#### ±ê×¼±à½âÂëÆ÷
```csharp
using NewLife.Net.Handlers;
var server = new NetServer { Port = 12345 };
// Ìí¼Ó±ê×¼±à½âÂëÆ÷£¨4×Ö½ÚÍ·²¿+Êý¾Ý£©
server.Add<StandardCodec>();
// Ìí¼ÓJSON±à½âÂëÆ÷
server.Add<JsonCodec>();
// ½ÓÊÕ½âÂëºóµÄÏûÏ¢
server.Received += (s, e) =>
{
// e.Message ÊǽâÂëºóµÄÏûÏ¢¶ÔÏó
if (e.Message is DefaultMessage msg)
{
Console.WriteLine($"±êÖ¾£º{msg.Flag}");
Console.WriteLine($"ÐòÁкţº{msg.Sequence}");
Console.WriteLine($"¸ºÔØ£º{msg.Payload?.ToStr()}");
}
};
server.Start();
```
#### ×Ô¶¨Òå´¦ÀíÆ÷
```csharp
public class MyHandler : Handler
{
public override Boolean Read(IHandlerContext context, Object message)
{
// ½âÂë´¦Àí£¨½ÓÊÕÊý¾Ýʱ£©
if (message is IPacket pk)
{
var myMsg = ParseMessage(pk);
return context.FireRead(myMsg);
}
return base.Read(context, message);
}
public override Boolean Write(IHandlerContext context, Object message)
{
// ±àÂë´¦Àí£¨·¢ËÍÊý¾Ýʱ£©
if (message is MyMessage msg)
{
var pk = EncodeMessage(msg);
return context.FireWrite(pk);
}
return base.Write(context, message);
}
}
// ×¢²á´¦ÀíÆ÷
server.Add(new MyHandler());
```
### INetHandler - ÍøÂç´¦ÀíÆ÷
ÓÃÓڻỰ¼¶±ðµÄÊý¾ÝÔ¤´¦Àí¡£
```csharp
public class MyServer : NetServer<MySession>
{
// Ϊÿ¸ö»á»°´´½¨´¦ÀíÆ÷
public override INetHandler? CreateHandler(INetSession session)
{
return new MyNetHandler();
}
}
public class MyNetHandler : INetHandler
{
public INetSession? Session { get; set; }
public void Init(INetSession session)
{
Session = session;
}
public void Process(ReceivedEventArgs e)
{
// Ô¤´¦ÀíÊý¾Ý£¨ÔÚOnReceive֮ǰ£©
// ¿ÉÒÔÐÞ¸Ä e.Packet »ò e.Message
// ¿ÉÒÔÉèÖà e.Packet = null À´×èÖ¹ºóÐø´¦Àí
}
public void Dispose()
{
// ÇåÀí×ÊÔ´
}
}
```
---
## ¸ß¼¶ÌØÐÔ
### SSL/TLS ¼ÓÃÜ
```csharp
// ·þÎñ¶ËSSL
var cert = new X509Certificate2("server.pfx", "password");
var server = new NetServer
{
Port = 443,
ProtocolType = NetType.Tcp,
SslProtocol = SslProtocols.Tls12 | SslProtocols.Tls13,
Certificate = cert,
};
server.Start();
// ¿Í»§¶ËSSL
var client = new TcpSession
{
Remote = new NetUri("tcp://127.0.0.1:443"),
SslProtocol = SslProtocols.Tls12,
// ¿ÉÑ¡£º¿Í»§¶ËÖ¤Êé
Certificate = clientCert,
};
client.Open();
```
### Ⱥ·¢ÏûÏ¢
```csharp
// Ⱥ·¢Êý¾Ý°ü¸øËùÓпͻ§¶Ë
await server.SendAllAsync(new ArrayPacket(data));
// ´øÌõ¼þȺ·¢£¨¹ýÂËÆ÷£©
await server.SendAllAsync(data, session =>
session["RoomId"]?.ToString() == "123");
// Ⱥ·¢¹ÜµÀÏûÏ¢£¨»á¾¹ý±àÂëÆ÷£©
server.SendAllMessage(new BroadcastMessage { Content = "Hello" });
// Ⱥ·¢²¢¹ýÂË
server.SendAllMessage(message, session => session.ID > 100);
// Åųý×Ô¼º
server.SendAllMessage(message, session => session.ID != mySession.ID);
```
### ÏûÏ¢ÇëÇóÏìÓ¦
```csharp
// ¿Í»§¶Ë·¢ËÍÇëÇ󲢵ȴýÏìÓ¦
var client = new TcpSession { Remote = uri };
client.Add<StandardCodec>();
client.Open();
// Òì²½·¢ËÍÏûÏ¢²¢µÈ´ýÏìÓ¦
var response = await client.SendMessageAsync(request);
// ´ø³¬Ê±µÄÇëÇó
using var cts = new CancellationTokenSource(5000);
var response = await client.SendMessageAsync(request, cts.Token);
```
### ÒÀÀµ×¢Èë
```csharp
// ÅäÖ÷þÎñ
services.AddSingleton<IMyService, MyService>();
services.AddScoped<IScopedService, ScopedService>();
var server = new NetServer<MySession>
{
Port = 12345,
ServiceProvider = serviceProvider,
};
// ÔڻỰÖÐʹÓã¨×Ô¶¯´´½¨Scope£©
public class MySession : NetSession
{
protected override void OnConnected()
{
base.OnConnected();
// ServiceProvider ÒÑ×Ô¶¯´´½¨ Scope
var service = ServiceProvider?.GetService<IMyService>();
var scoped = ServiceProvider?.GetService<IScopedService>();
}
// ÄÚÖ÷þÎñ¿ìËÙ»ñÈ¡
public override Object GetService(Type serviceType)
{
if (serviceType == typeof(INetSession)) return this;
if (serviceType == typeof(NetServer)) return (this as INetSession).Host;
if (serviceType == typeof(ISocketSession)) return Session;
if (serviceType == typeof(ISocketServer)) return Server;
return base.GetService(serviceType);
}
}
```
### APM ÐÔÄÜ×·×Ù
```csharp
var server = new NetServer
{
Port = 12345,
Tracer = tracer, // Ó¦Óòã×·×Ù
SocketTracer = tracer, // Socket²ã×·×Ù
};
// ×·×ٵIJÙ×÷°üÀ¨£º
// - net:{Name}:Connect Á¬½Óʼþ
// - net:{Name}:Receive ½ÓÊÕÊý¾Ý
// - net:{Name}:Send ·¢ËÍÊý¾Ý
// - net:{Name}:Disconnect ¶Ï¿ªÁ¬½Ó
```
---
## ×î¼Ñʵ¼ù
### 1. ×ÊÔ´¹ÜÀí
```csharp
// ʹÓÃusingÈ·±£×ÊÔ´ÊÍ·Å
using var server = new NetServer { Port = 12345 };
server.Start();
// »òÕßÔÚfinallyÖÐÍ£Ö¹
var server = new NetServer { Port = 12345 };
try
{
server.Start();
// ...
}
finally
{
server.Stop("Shutdown");
server.Dispose();
}
```
### 2. Òì³£´¦Àí
```csharp
// »á»°¼¶Òì³£´¦Àí
public class MySession : NetSession
{
protected override void OnReceive(ReceivedEventArgs e)
{
try
{
base.OnReceive(e);
ProcessData(e.Packet);
}
catch (Exception ex)
{
WriteError("´¦ÀíÊý¾ÝÒì³££º{0}", ex.Message);
// ²»ÒªÔÚÕâÀï¹Ø±ÕÁ¬½Ó£¬ÈÃÉϲã¾ö¶¨
}
}
}
// ·þÎñÆ÷¼¶Òì³£´¦Àí
server.Error += (s, e) =>
{
XTrace.WriteException(e.Exception);
};
```
### 3. ÈÕÖ¾ÅäÖÃ
```csharp
// Éú²ú»·¾³ÅäÖÃ
var server = new NetServer
{
Log = XTrace.Log, // ·þÎñÆ÷ÈÕÖ¾
SessionLog = null, // ¹Ø±Õ»á»°ÈÕÖ¾
SocketLog = null, // ¹Ø±ÕSocketÈÕÖ¾
LogSend = false, // ¹Ø±Õ·¢ËÍÈÕÖ¾
LogReceive = false, // ¹Ø±Õ½ÓÊÕÈÕÖ¾
StatPeriod = 600, // 10·ÖÖÓÊä³öÒ»´Îͳ¼Æ
};
// µ÷ÊÔ»·¾³ÅäÖÃ
var server = new NetServer
{
Log = XTrace.Log,
SocketLog = XTrace.Log,
SessionLog = XTrace.Log,
LogSend = true,
LogReceive = true,
StatPeriod = 60, // 1·ÖÖÓÊä³öͳ¼Æ
};
```
### 4. »á»°×´Ì¬¹ÜÀí
```csharp
public class GameSession : NetSession
{
public Player Player { get; set; }
protected override void OnConnected()
{
base.OnConnected();
// ³õʼ»¯Íæ¼Ò¶ÔÏó
Player = new Player();
}
protected override void OnReceive(ReceivedEventArgs e)
{
base.OnReceive(e);
// ʹÓÃItems´æ´¢ÁÙʱÊý¾Ý
this["LastActiveTime"] = DateTime.Now;
// ʹÓÃÇ¿ÀàÐÍÊôÐÔ
Player?.HandlePacket(e.Packet);
}
protected override void OnDisconnected(String reason)
{
base.OnDisconnected(reason);
// ÇåÀíÍæ¼ÒÊý¾Ý
Player?.SaveAndCleanup();
Player = null;
}
}
```
---
## ÐÔÄÜÓÅ»¯
### 1. »á»°¼¯ºÏÓÅ»¯
```csharp
// ¸ß²¢·¢³¡¾°ÏÂÈç²»ÐèÒª±éÀú»á»°£¬¿É½ûÓûỰ¼¯ºÏ
server.UseSession = false;
// »á»°¼¯ºÏʹÓà ConcurrentDictionary£¬±éÀúʱֱ½Ó±éÀú Values
foreach (var session in server.Sessions.Values)
{
// ±ÜÃâ KeyValuePair µÄ¶îÍ⿪Ïú
}
```
### 2. Ⱥ·¢ÓÅ»¯
```csharp
// Ⱥ·¢ÒÑÓÅ»¯ÎªÍ¬²½·¢ËÍ£¬±ÜÃâ Task.Run ¿ªÏú
// Ö±½Ó±éÀú _Sessions.Values£¬¼õÉÙ×Öµä²Ù×÷¿ªÏú
await server.SendAllAsync(data);
// Èç¹ûÐèÒª²¢Ðз¢ËÍ£¬×ÔÐÐʵÏÖ
var tasks = server.Sessions.Values
.Where(predicate)
.Select(s => Task.Run(() => s.Send(data)));
await Task.WhenAll(tasks);
```
### 3. Ô×Ó²Ù×÷
```csharp
// SessionCount ºÍ MaxSessionCount ʹÓÃÔ×Ó²Ù×÷¸üÐÂ
// ±ÜÃâËø¾ºÕù£¬Ìá¸ß²¢·¢ÐÔÄÜ
var count = server.SessionCount; // µ±Ç°»á»°Êý
var max = server.MaxSessionCount; // ÀúÊ·×î¸ß»á»°Êý
```
### 4. ×·×ÙÊý¾ÝÓÅ»¯
```csharp
// Send ·½·¨×·×ÙÊý¾ÝÏÞÖÆ³¤¶È£¬±ÜÃâ´óÊý¾Ý°üÓ°Ïì×·×ÙÐÔÄÜ
// ×Ö·û´®ºÍ×Ö½ÚÊý×é×î¶à¼Ç¼64×Ö½Ú
public virtual INetSession Send(String msg, Encoding? encoding = null)
{
// ×·×Ùʱֻ¼Ç¼ǰ64×Ö·û
using var span = host?.Tracer?.NewSpan($"net:{host.Name}:Send",
msg.Length > 64 ? msg[..64] : msg, ...);
...
}
```
### 5. ·ÀÖØÈë±£»¤
```csharp
// Start ºÍ Close ·½·¨¶¼ÓзÀÖØÈë±£»¤
// ʹÓà Interlocked.CompareExchange È·±£Ö»Ö´ÐÐÒ»´Î
public virtual void Start()
{
if (Interlocked.CompareExchange(ref _running, 1, 0) != 0) return;
...
}
public void Close(String reason)
{
if (Interlocked.CompareExchange(ref _running, 0, 1) != 1) return;
...
}
```
### 6. TCP ÐÔÄÜÅäÖÃ
```csharp
// ·ÃÎʵײãTcpServer½øÐÐÅäÖÃ
if (server.Server is TcpServer tcp)
{
tcp.NoDelay = true; // ½ûÓÃNagleËã·¨£¨µÍÑÓ³Ù£©
tcp.KeepAliveInterval = 60; // KeepAlive¼ä¸ô
}
```
---
## ³£¼ûÎÊÌâ
### Q: ÈçºÎ´¦ÀíÕ³°ü/²ð°ü£¿
A: ʹÓà StandardCodec »ò×Ô¶¨ÒåÐÒé´¦ÀíÆ÷¡£StandardCodec ²ÉÓà 4 ×Ö½ÚÍ·²¿±êʶÊý¾Ý³¤¶È¡£
```csharp
server.Add<StandardCodec>();
```
### Q: ÈçºÎʵÏÖÐÄÌø¼ì²â£¿
A: ÉèÖûỰ³¬Ê±Ê±¼ä£¬¿Í»§¶Ë¶¨ÆÚ·¢ËÍÐÄÌø°ü¡£
```csharp
server.SessionTimeout = 120; // 2·ÖÖÓÎÞÊý¾ÝÔò¶Ï¿ª
// ¿Í»§¶Ë¶¨Ê±·¢ËÍÐÄÌø
timer.Elapsed += (s, e) => client.Send("ping");
```
### Q: ÈçºÎ»ñÈ¡¿Í»§¶ËÕæÊµIP£¿
A: ͨ¹ý»á»°µÄ Remote ÊôÐÔ»ñÈ¡¡£
```csharp
server.NewSession += (s, e) =>
{
var ip = e.Session.Remote.Address;
var port = e.Session.Remote.Port;
Console.WriteLine($"¿Í»§¶Ë£º{ip}:{port}");
};
```
### Q: ÈçºÎÏÞÖÆ×î´óÁ¬½ÓÊý£¿
A: ÔÚ OnNewSession Öмì²é²¢¾Ü¾ø¡£
```csharp
public class MyServer : NetServer
{
public Int32 MaxConnections { get; set; } = 1000;
protected override INetSession OnNewSession(ISocketSession session)
{
if (SessionCount >= MaxConnections)
{
WriteLog("Á¬½ÓÊý³¬ÏÞ£¬¾Ü¾øÁ¬½Ó£º{0}", session.Remote);
session.Dispose();
return null;
}
return base.OnNewSession(session);
}
}
```
### Q: ·þÎñÆ÷ÖØÆôʱ¶Ë¿Ú±»Õ¼Óã¿
A: ÆôÓõØÖ·ÖØÓá£
```csharp
server.ReuseAddress = true;
```
### Q: ÈçºÎ·¢ËÍÎļþ£¿
A: ʹÓÃÁ÷·¢ËÍ»òÀ©Õ¹·½·¨¡£
```csharp
// ¼òµ¥·¢ËÍÁ÷
using var stream = File.OpenRead("data.bin");
session.Send(stream);
// ·Ö°ü·¢ËÍ£¨ÅäºÏStandardCodec£©
client.SendFile("data.bin");
```
### Q: UDP ÈçºÎÇø·Ö¿Í»§¶Ë£¿
A: UDP ÐÒéÏ£¬Ã¿¸ö²»Í¬µÄÔ¶³ÌµØÖ·»á´´½¨¶ÀÁ¢µÄ»á»°¡£
```csharp
server.Received += (s, e) =>
{
var session = s as INetSession;
Console.WriteLine($"À´×Ô {session.Remote} µÄÊý¾Ý");
};
```
### Q: ÈçºÎʵÏֹ㲥·¿¼ä£¿
A: ʹÓûỰÊý¾Ý±ê¼Ç·¿¼ä£¬Èº·¢Ê±¹ýÂË¡£
```csharp
// ¼ÓÈë·¿¼ä
session["RoomId"] = "room1";
// ·¿¼ä¹ã²¥
server.SendAllMessage(message, s => s["RoomId"]?.ToString() == "room1");
```
---
## ¸½Â¼
### ±ê×¼ÍøÂç·â°üÐÒé
ÐÂÉúÃüÍŶӱê×¼ÍøÂç·â°üÐÒ飨DefaultMessage£©£º
```
| 1 Flag | 1 Sequence | 2 Length | N Payload |
```
- **Flag** (1×Ö½Ú)£º±êʶ룬¿ÉÓ÷¶Î§0~63£¬±êʶÏûÏ¢ÀàÐÍ/¼ÓÃÜ/ѹËõµÈ
- **Sequence** (1×Ö½Ú)£ºÐòÁкţ¬ÓÃÓÚÇëÇóÏìÓ¦Åä¶Ô
- **Length** (2×Ö½Ú)£ºÊý¾Ý³¤¶È£¬×î´ó64KB
- **Payload** (N×Ö½Ú)£º¸ºÔØÊý¾Ý
### ¹Ø¼üÀàÐÍËÙ²é
| ÀàÐÍ | ˵Ã÷ |
|------|------|
| `NetServer` | ÍøÂç·þÎñÆ÷£¬¹ÜÀí¶à¸öSocket·þÎñÆ÷ºÍ»á»° |
| `NetServer<TSession>` | ·ºÐÍÍøÂç·þÎñÆ÷£¬×Ô¶¯´´½¨Ö¸¶¨ÀàÐͻỰ |
| `NetSession` | ÍøÂç»á»°»ùÀ࣬´¦Àíµ¥¸öÁ¬½ÓµÄÒµÎñÂß¼ |
| `NetSession<TServer>` | ·ºÐÍÍøÂç»á»°£¬Ç¿ÀàÐÍ·ÃÎÊHost |
| `INetSession` | ÍøÂç»á»°½Ó¿Ú |
| `INetHandler` | ÍøÂç´¦ÀíÆ÷½Ó¿Ú£¬»á»°¼¶Êý¾ÝÔ¤´¦Àí |
| `IPipeline` | ÏûÏ¢¹ÜµÀ½Ó¿Ú |
| `ISocketServer` | Socket·þÎñÆ÷½Ó¿Ú |
| `ISocketSession` | Socket»á»°½Ó¿Ú |
| `TcpServer` | TCP·þÎñÆ÷ |
| `UdpServer` | UDP·þÎñÆ÷ |
| `TcpSession` | TCP¿Í»§¶Ë/»á»° |
### Ïà¹ØÁ´½Ó
- GitHub: https://github.com/NewLifeX/X
- Gitee: https://gitee.com/NewLifeX/X
- Îĵµ: https://newlifex.com
---
*±¾Îĵµ×îºó¸üУº2025Äê7ÔÂ*
|