Skip to content

Commit de7230c

Browse files
committed
[修改] Udp 模块增加 XML 文档注释,优化 UDP 连接监听器和主机构建器扩展
1 parent dae48a7 commit de7230c

8 files changed

Lines changed: 157 additions & 31 deletions

src/GameFrameX.SuperSocket.Udp/IPAddressUdpSessionIdentifierProvider.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,17 @@
33

44
namespace GameFrameX.SuperSocket.Udp
55
{
6+
/// <summary>
7+
/// Provides session identifiers for UDP sessions based on IP addresses.
8+
/// </summary>
69
class IPAddressUdpSessionIdentifierProvider : IUdpSessionIdentifierProvider
710
{
11+
/// <summary>
12+
/// Gets the session identifier for a UDP session.
13+
/// </summary>
14+
/// <param name="remoteEndPoint">The remote endpoint of the UDP session.</param>
15+
/// <param name="data">The data received from the remote endpoint.</param>
16+
/// <returns>The session identifier for the UDP session.</returns>
817
public string GetSessionIdentifier(IPEndPoint remoteEndPoint, ArraySegment<byte> data)
918
{
1019
return remoteEndPoint.Address.ToString() + ":" + remoteEndPoint.Port;

src/GameFrameX.SuperSocket.Udp/IUdpSessionIdentifierProvider.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,17 @@
33

44
namespace GameFrameX.SuperSocket.Udp
55
{
6+
/// <summary>
7+
/// Provides a mechanism to identify UDP sessions based on remote endpoint and data.
8+
/// </summary>
69
public interface IUdpSessionIdentifierProvider
710
{
11+
/// <summary>
12+
/// Gets the session identifier for a UDP session.
13+
/// </summary>
14+
/// <param name="remoteEndPoint">The remote endpoint of the UDP session.</param>
15+
/// <param name="data">The data received from the remote endpoint.</param>
16+
/// <returns>The session identifier for the UDP session.</returns>
817
string GetSessionIdentifier(IPEndPoint remoteEndPoint, ArraySegment<byte> data);
918
}
1019
}

src/GameFrameX.SuperSocket.Udp/UdpConnectionFactory.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,17 @@
66

77
namespace GameFrameX.SuperSocket.Udp
88
{
9+
/// <summary>
10+
/// Provides a factory for creating UDP connections.
11+
/// </summary>
912
public class UdpConnectionFactory : IConnectionFactory
1013
{
14+
/// <summary>
15+
/// Creates a UDP connection based on the specified connection information.
16+
/// </summary>
17+
/// <param name="connection">The connection information.</param>
18+
/// <param name="cancellationToken">A token to monitor for cancellation requests.</param>
19+
/// <returns>A task that represents the asynchronous creation operation.</returns>
1120
public Task<IConnection> CreateConnection(object connection, CancellationToken cancellationToken)
1221
{
1322
var connectionInfo = (UdpConnectionInfo)connection;

src/GameFrameX.SuperSocket.Udp/UdpConnectionFactoryBuilder.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,17 @@
66

77
namespace GameFrameX.SuperSocket.Udp
88
{
9+
/// <summary>
10+
/// Builds a connection factory for UDP connections.
11+
/// </summary>
912
public class UdpConnectionFactoryBuilder : IConnectionFactoryBuilder
1013
{
14+
/// <summary>
15+
/// Builds a connection factory based on the specified listen and connection options.
16+
/// </summary>
17+
/// <param name="listenOptions">The options for the listener.</param>
18+
/// <param name="connectionOptions">The options for the connection.</param>
19+
/// <returns>A connection factory for UDP connections.</returns>
1120
public IConnectionFactory Build(ListenOptions listenOptions, ConnectionOptions connectionOptions)
1221
{
1322
return new UdpConnectionFactory();

src/GameFrameX.SuperSocket.Udp/UdpConnectionInfo.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,29 @@
55

66
namespace GameFrameX.SuperSocket.Udp
77
{
8+
/// <summary>
9+
/// Represents information about a UDP connection.
10+
/// </summary>
811
internal struct UdpConnectionInfo
912
{
13+
/// <summary>
14+
/// Gets or sets the socket associated with the connection.
15+
/// </summary>
1016
public Socket Socket { get; set; }
1117

18+
/// <summary>
19+
/// Gets or sets the connection options.
20+
/// </summary>
1221
public ConnectionOptions ConnectionOptions { get; set; }
1322

23+
/// <summary>
24+
/// Gets or sets the session identifier for the connection.
25+
/// </summary>
1426
public string SessionIdentifier { get; set; }
1527

28+
/// <summary>
29+
/// Gets or sets the remote endpoint of the connection.
30+
/// </summary>
1631
public IPEndPoint RemoteEndPoint { get; set; }
1732
}
1833
}

src/GameFrameX.SuperSocket.Udp/UdpConnectionListener.cs

Lines changed: 59 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313

1414
namespace GameFrameX.SuperSocket.Udp
1515
{
16+
/// <summary>
17+
/// Represents a listener for UDP connections.
18+
/// </summary>
1619
class UdpConnectionListener : IConnectionListener
1720
{
1821
private ILogger _logger;
@@ -21,14 +24,29 @@ class UdpConnectionListener : IConnectionListener
2124

2225
private IPEndPoint _acceptRemoteEndPoint;
2326

27+
/// <summary>
28+
/// Gets the factory for creating connections.
29+
/// </summary>
2430
public IConnectionFactory ConnectionFactory { get; }
25-
26-
public ListenOptions Options { get; }
27-
31+
32+
/// <summary>
33+
/// Gets the options for the listener.
34+
/// </summary>
35+
public ListenOptions Options { get; }
36+
37+
/// <summary>
38+
/// Gets the options for the connection.
39+
/// </summary>
2840
public ConnectionOptions ConnectionOptions { get; }
2941

42+
/// <summary>
43+
/// Gets a value indicating whether the listener is running.
44+
/// </summary>
3045
public bool IsRunning { get; private set; }
3146

47+
/// <summary>
48+
/// Occurs when a new connection is accepted.
49+
/// </summary>
3250
public event NewConnectionAcceptHandler NewConnectionAccept;
3351

3452
private static readonly ArrayPool<byte> _bufferPool = ArrayPool<byte>.Shared;
@@ -41,6 +59,15 @@ class UdpConnectionListener : IConnectionListener
4159

4260
private IAsyncSessionContainer _sessionContainer;
4361

62+
/// <summary>
63+
/// Initializes a new instance of the <see cref="UdpConnectionListener"/> class.
64+
/// </summary>
65+
/// <param name="options">The options for the listener.</param>
66+
/// <param name="connectionOptions">The options for the connection.</param>
67+
/// <param name="connectionFactory">The factory for creating connections.</param>
68+
/// <param name="logger">The logger instance.</param>
69+
/// <param name="udpSessionIdentifierProvider">The provider for UDP session identifiers.</param>
70+
/// <param name="sessionContainer">The container for managing sessions.</param>
4471
public UdpConnectionListener(ListenOptions options, ConnectionOptions connectionOptions, IConnectionFactory connectionFactory, ILogger logger, IUdpSessionIdentifierProvider udpSessionIdentifierProvider, IAsyncSessionContainer sessionContainer)
4572
{
4673
Options = options;
@@ -51,15 +78,19 @@ public UdpConnectionListener(ListenOptions options, ConnectionOptions connection
5178
_sessionContainer = sessionContainer;
5279
}
5380

81+
/// <summary>
82+
/// Starts the UDP connection listener.
83+
/// </summary>
84+
/// <returns><c>true</c> if the listener started successfully; otherwise, <c>false</c>.</returns>
5485
public bool Start()
5586
{
5687
var options = Options;
5788

5889
try
59-
{
60-
var listenEndpoint = options.ToEndPoint();
90+
{
91+
var listenEndpoint = options.ToEndPoint();
6192
var listenSocket = _listenSocket = new Socket(listenEndpoint.AddressFamily, SocketType.Dgram, ProtocolType.Udp);
62-
93+
6394
if (options.NoDelay)
6495
listenSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.NoDelay, true);
6596

@@ -82,7 +113,7 @@ public bool Start()
82113
catch (PlatformNotSupportedException)
83114
{
84115
_logger.LogWarning("Failed to set socket option SIO_UDP_CONNRESET because the platform doesn't support it.");
85-
}
116+
}
86117

87118
IsRunning = true;
88119

@@ -115,12 +146,12 @@ private async Task KeepAccept(Socket listenSocket)
115146

116147
var packageData = new ArraySegment<byte>(buffer, 0, result.ReceivedBytes);
117148
var remoteEndPoint = result.RemoteEndPoint as IPEndPoint;
118-
149+
119150
var sessionID = _udpSessionIdentifierProvider.GetSessionIdentifier(remoteEndPoint, packageData);
120151

121152
var session = await _sessionContainer.GetSessionByIDAsync(sessionID);
122153

123-
IVirtualConnection connection = null;
154+
IVirtualConnection connection = null;
124155

125156
if (session != null)
126157
{
@@ -136,13 +167,13 @@ private async Task KeepAccept(Socket listenSocket)
136167
OnNewConnectionAccept(connection);
137168
}
138169

139-
await connection.WritePipeDataAsync(packageData.AsMemory(), _cancellationTokenSource.Token);
170+
await connection.WriteInputPipeDataAsync(packageData.AsMemory(), _cancellationTokenSource.Token);
140171
}
141172
catch (Exception e)
142173
{
143174
if (e is ObjectDisposedException || e is NullReferenceException)
144175
break;
145-
176+
146177
if (e is SocketException se)
147178
{
148179
var errorCode = se.ErrorCode;
@@ -153,7 +184,7 @@ private async Task KeepAccept(Socket listenSocket)
153184
break;
154185
}
155186
}
156-
187+
157188
_logger.LogError(e, $"Listener[{this.ToString()}] failed to receive udp data");
158189
}
159190
finally
@@ -196,16 +227,25 @@ private async ValueTask<IConnection> CreateConnection(Socket socket, IPEndPoint
196227
{
197228
_logger.LogError(e, $"Failed to create connection for {socket.RemoteEndPoint}.");
198229
return null;
199-
}
230+
}
200231
}
201232

233+
/// <summary>
234+
/// Creates a connection using the specified socket.
235+
/// </summary>
236+
/// <param name="connection">The socket representing the connection.</param>
237+
/// <returns>A task that represents the asynchronous operation. The task result contains the created connection.</returns>
202238
public async Task<IConnection> CreateConnection(object connection)
203239
{
204240
var socket = (Socket)connection;
205241
var remoteEndPoint = socket.RemoteEndPoint as IPEndPoint;
206242
return await CreateConnection(socket, remoteEndPoint, _udpSessionIdentifierProvider.GetSessionIdentifier(remoteEndPoint, null));
207243
}
208244

245+
/// <summary>
246+
/// Stops the UDP connection listener asynchronously.
247+
/// </summary>
248+
/// <returns>A task that represents the asynchronous stop operation.</returns>
209249
public Task StopAsync()
210250
{
211251
var listenSocket = _listenSocket;
@@ -217,17 +257,22 @@ public Task StopAsync()
217257

218258
_cancellationTokenSource.Cancel();
219259
listenSocket.Close();
220-
260+
221261
return _stopTaskCompletionSource.Task;
222262
}
223263

224264
public override string ToString()
225265
{
226266
return Options?.ToString();
227267
}
268+
269+
/// <summary>
270+
/// Disposes the resources used by the UDP connection listener.
271+
/// </summary>
228272
public void Dispose()
229273
{
230274
var listenSocket = _listenSocket;
275+
231276
if (listenSocket != null && Interlocked.CompareExchange(ref _listenSocket, null, listenSocket) == listenSocket)
232277
{
233278
listenSocket.Dispose();

src/GameFrameX.SuperSocket.Udp/UdpConnectionListenerFactory.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111

1212
namespace GameFrameX.SuperSocket.Udp
1313
{
14+
/// <summary>
15+
/// Creates connection listeners for UDP connections.
16+
/// </summary>
1417
class UdpConnectionListenerFactory : IConnectionListenerFactory
1518
{
1619
private readonly IConnectionFactoryBuilder _connectionFactoryBuilder;
@@ -19,13 +22,26 @@ class UdpConnectionListenerFactory : IConnectionListenerFactory
1922

2023
private readonly IAsyncSessionContainer _sessionContainer;
2124

25+
/// <summary>
26+
/// Initializes a new instance of the <see cref="UdpConnectionListenerFactory"/> class.
27+
/// </summary>
28+
/// <param name="connectionFactoryBuilder">The builder for creating connection factories.</param>
29+
/// <param name="udpSessionIdentifierProvider">The provider for UDP session identifiers.</param>
30+
/// <param name="sessionContainer">The container for managing sessions.</param>
2231
public UdpConnectionListenerFactory(IConnectionFactoryBuilder connectionFactoryBuilder, IUdpSessionIdentifierProvider udpSessionIdentifierProvider, IAsyncSessionContainer sessionContainer)
2332
{
2433
_connectionFactoryBuilder = connectionFactoryBuilder;
2534
_udpSessionIdentifierProvider = udpSessionIdentifierProvider;
2635
_sessionContainer = sessionContainer;
2736
}
2837

38+
/// <summary>
39+
/// Creates a connection listener based on the specified options.
40+
/// </summary>
41+
/// <param name="options">The options for the listener.</param>
42+
/// <param name="connectionOptions">The options for the connection.</param>
43+
/// <param name="loggerFactory">The factory for creating loggers.</param>
44+
/// <returns>A connection listener for UDP connections.</returns>
2945
public IConnectionListener CreateConnectionListener(ListenOptions options, ConnectionOptions connectionOptions, ILoggerFactory loggerFactory)
3046
{
3147
connectionOptions.Logger = loggerFactory.CreateLogger(nameof(IConnection));

src/GameFrameX.SuperSocket.Udp/UdpServerHostBuilderExtensions.cs

Lines changed: 31 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,32 +7,46 @@
77

88
namespace GameFrameX.SuperSocket.Udp
99
{
10+
/// <summary>
11+
/// Provides extension methods for configuring a UDP server host builder.
12+
/// </summary>
1013
public static class UdpServerHostBuilderExtensions
1114
{
15+
/// <summary>
16+
/// Configures the host builder to use UDP.
17+
/// </summary>
18+
/// <param name="hostBuilder">The host builder to configure.</param>
19+
/// <returns>The configured host builder.</returns>
1220
public static ISuperSocketHostBuilder UseUdp(this ISuperSocketHostBuilder hostBuilder)
1321
{
1422
return (hostBuilder.ConfigureServices((context, services) =>
23+
{
24+
services.AddSingleton<IConnectionListenerFactory, UdpConnectionListenerFactory>();
25+
services.AddSingleton<IConnectionFactoryBuilder, UdpConnectionFactoryBuilder>();
26+
}) as ISuperSocketHostBuilder)
27+
.ConfigureSupplementServices((context, services) =>
28+
{
29+
if (!services.Any(s => s.ServiceType == typeof(IUdpSessionIdentifierProvider)))
1530
{
16-
services.AddSingleton<IConnectionListenerFactory, UdpConnectionListenerFactory>();
17-
services.AddSingleton<IConnectionFactoryBuilder, UdpConnectionFactoryBuilder>();
18-
}) as ISuperSocketHostBuilder)
19-
.ConfigureSupplementServices((context, services) =>
20-
{
21-
if (!services.Any(s => s.ServiceType == typeof(IUdpSessionIdentifierProvider)))
22-
{
23-
services.AddSingleton<IUdpSessionIdentifierProvider, IPAddressUdpSessionIdentifierProvider>();
24-
}
31+
services.AddSingleton<IUdpSessionIdentifierProvider, IPAddressUdpSessionIdentifierProvider>();
32+
}
2533

26-
if (!services.Any(s => s.ServiceType == typeof(IAsyncSessionContainer)))
27-
{
28-
services.TryAddEnumerable(ServiceDescriptor.Singleton<IMiddleware, InProcSessionContainerMiddleware>(s => s.GetRequiredService<InProcSessionContainerMiddleware>()));
29-
services.AddSingleton<InProcSessionContainerMiddleware>();
30-
services.AddSingleton<ISessionContainer>((s) => s.GetRequiredService<InProcSessionContainerMiddleware>());
31-
services.AddSingleton<IAsyncSessionContainer>((s) => s.GetRequiredService<ISessionContainer>().ToAsyncSessionContainer());
32-
}
33-
});
34+
if (!services.Any(s => s.ServiceType == typeof(IAsyncSessionContainer)))
35+
{
36+
services.TryAddEnumerable(ServiceDescriptor.Singleton<IMiddleware, InProcSessionContainerMiddleware>(s => s.GetRequiredService<InProcSessionContainerMiddleware>()));
37+
services.AddSingleton<InProcSessionContainerMiddleware>();
38+
services.AddSingleton<ISessionContainer>((s) => s.GetRequiredService<InProcSessionContainerMiddleware>());
39+
services.AddSingleton<IAsyncSessionContainer>((s) => s.GetRequiredService<ISessionContainer>().ToAsyncSessionContainer());
40+
}
41+
});
3442
}
3543

44+
/// <summary>
45+
/// Configures the host builder to use UDP with a specific package type.
46+
/// </summary>
47+
/// <typeparam name="TReceivePackage">The type of the package to receive.</typeparam>
48+
/// <param name="hostBuilder">The host builder to configure.</param>
49+
/// <returns>The configured host builder.</returns>
3650
public static ISuperSocketHostBuilder<TReceivePackage> UseUdp<TReceivePackage>(this ISuperSocketHostBuilder<TReceivePackage> hostBuilder)
3751
{
3852
return (hostBuilder as ISuperSocketHostBuilder).UseUdp() as ISuperSocketHostBuilder<TReceivePackage>;

0 commit comments

Comments
 (0)