Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
dotNET Platform
MQTTnet
提交
d4dad486
MQTTnet
项目概览
dotNET Platform
/
MQTTnet
10 个月 前同步成功
通知
0
Star
1
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
MQTTnet
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
提交
d4dad486
编写于
9月 14, 2022
作者:
C
Christian
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Fix and improve session takeover process handling.
上级
c009cbef
变更
6
隐藏空白更改
内联
并排
Showing
6 changed file
with
59 addition
and
45 deletion
+59
-45
.github/workflows/ReleaseNotes.md
.github/workflows/ReleaseNotes.md
+1
-0
MQTTnet.sln.DotSettings
MQTTnet.sln.DotSettings
+1
-0
Source/MQTTnet.Tests/Server/Session_Tests.cs
Source/MQTTnet.Tests/Server/Session_Tests.cs
+12
-26
Source/MQTTnet/Implementations/MqttTcpServerListener.cs
Source/MQTTnet/Implementations/MqttTcpServerListener.cs
+1
-1
Source/MQTTnet/Server/Internal/MqttClient.cs
Source/MQTTnet/Server/Internal/MqttClient.cs
+19
-1
Source/MQTTnet/Server/Internal/MqttClientSessionsManager.cs
Source/MQTTnet/Server/Internal/MqttClientSessionsManager.cs
+25
-17
未找到文件。
.github/workflows/ReleaseNotes.md
浏览文件 @
d4dad486
*
[Core] MQTT Packets being sent over web socket transport are now setting the web socket frame boundaries correctly (#1499).
*
[Client] Keep alive mechanism now uses the configured timeout value from the options (thanks to @Stannieman, #1495).
*
[Server] A DISCONNECT packet is no longer sent to MQTT clients < 5.0.0 (thanks to @logicaloud, #1506).
*
[Server] Improved "take over" process handling.
MQTTnet.sln.DotSettings
浏览文件 @
d4dad486
...
...
@@ -241,5 +241,6 @@ See the LICENSE file in the project root for more information.</s:String>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateThisQualifierSettings/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=PINGREQ/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=PINGRESP/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Tnet/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=unsub/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
\ No newline at end of file
Source/MQTTnet.Tests/Server/Session_Tests.cs
浏览文件 @
d4dad486
...
...
@@ -124,7 +124,9 @@ namespace MQTTnet.Tests.Server
}
[
TestMethod
]
public
async
Task
Handle_Parallel_Connection_Attempts
()
[
DataRow
(
MqttProtocolVersion
.
V311
)]
[
DataRow
(
MqttProtocolVersion
.
V500
)]
public
async
Task
Handle_Parallel_Connection_Attempts
(
MqttProtocolVersion
protocolVersion
)
{
using
(
var
testEnvironment
=
CreateTestEnvironment
())
{
...
...
@@ -132,7 +134,7 @@ namespace MQTTnet.Tests.Server
await
testEnvironment
.
StartServer
();
var
options
=
new
MqttClientOptionsBuilder
().
WithClientId
(
"1"
).
WithKeepAlivePeriod
(
TimeSpan
.
FromSeconds
(
5
));
var
options
=
new
MqttClientOptionsBuilder
().
WithClientId
(
"1"
).
With
Timeout
(
TimeSpan
.
FromSeconds
(
1
)).
WithProtocolVersion
(
protocolVersion
).
With
KeepAlivePeriod
(
TimeSpan
.
FromSeconds
(
5
));
var
hasReceive
=
false
;
...
...
@@ -146,7 +148,10 @@ namespace MQTTnet.Tests.Server
// Try to connect 50 clients at the same time.
var
clients
=
await
Task
.
WhenAll
(
Enumerable
.
Range
(
0
,
50
).
Select
(
i
=>
ConnectAndSubscribe
(
testEnvironment
,
options
,
OnReceive
)));
var
connectedClients
=
clients
.
Where
(
c
=>
c
?.
IsConnected
??
false
).
ToList
();
await
LongTestDelay
();
var
connectedClients
=
clients
.
Where
(
c
=>
c
!=
null
).
Where
(
c
=>
c
.
TryPingAsync
().
GetAwaiter
().
GetResult
()).
ToList
();
Assert
.
AreEqual
(
1
,
connectedClients
.
Count
);
...
...
@@ -161,26 +166,7 @@ namespace MQTTnet.Tests.Server
Assert
.
AreEqual
(
true
,
hasReceive
);
}
}
[
TestMethod
]
public
async
Task
Manage_Session_MaxParallel
()
{
using
(
var
testEnvironment
=
CreateTestEnvironment
())
{
testEnvironment
.
IgnoreClientLogErrors
=
true
;
var
serverOptions
=
new
MqttServerOptionsBuilder
();
await
testEnvironment
.
StartServer
(
serverOptions
);
var
options
=
new
MqttClientOptionsBuilder
().
WithClientId
(
"1"
);
var
clients
=
await
Task
.
WhenAll
(
Enumerable
.
Range
(
0
,
10
).
Select
(
i
=>
TryConnect
(
testEnvironment
,
options
)));
var
connectedClients
=
clients
.
Where
(
c
=>
c
?.
IsConnected
??
false
).
ToList
();
Assert
.
AreEqual
(
1
,
connectedClients
.
Count
);
}
}
[
DataTestMethod
]
[
DataRow
(
MqttQualityOfServiceLevel
.
ExactlyOnce
)]
[
DataRow
(
MqttQualityOfServiceLevel
.
AtLeastOnce
)]
...
...
@@ -360,7 +346,7 @@ namespace MQTTnet.Tests.Server
}
}
async
Task
<
IMqttClient
>
ConnectAndSubscribe
(
TestEnvironment
testEnvironment
,
MqttClientOptionsBuilder
options
,
Action
onReceive
)
static
async
Task
<
IMqttClient
>
ConnectAndSubscribe
(
TestEnvironment
testEnvironment
,
MqttClientOptionsBuilder
options
,
Action
onReceive
)
{
try
{
...
...
@@ -379,13 +365,13 @@ namespace MQTTnet.Tests.Server
return
sendClient
;
}
catch
(
Exception
)
catch
{
return
null
;
}
}
async
Task
<
IMqttClient
>
TryConnect
(
TestEnvironment
testEnvironment
,
MqttClientOptionsBuilder
options
)
static
async
Task
<
IMqttClient
>
TryConnect
(
TestEnvironment
testEnvironment
,
MqttClientOptionsBuilder
options
)
{
try
{
...
...
Source/MQTTnet/Implementations/MqttTcpServerListener.cs
浏览文件 @
d4dad486
...
...
@@ -134,7 +134,7 @@ namespace MQTTnet.Implementations
continue
;
}
Task
.
Run
(()
=>
TryHandleClientConnectionAsync
(
clientSocket
),
cancellationToken
).
RunInBackground
(
_logger
);
_
=
Task
.
Factory
.
StartNew
(()
=>
TryHandleClientConnectionAsync
(
clientSocket
),
cancellationToken
,
TaskCreationOptions
.
PreferFairness
,
TaskScheduler
.
Default
).
ConfigureAwait
(
false
);
}
catch
(
OperationCanceledException
)
{
...
...
Source/MQTTnet/Server/Internal/MqttClient.cs
浏览文件 @
d4dad486
...
...
@@ -98,7 +98,7 @@ namespace MQTTnet.Server
try
{
Task
.
Run
(()
=>
SendPacketsLoop
(
cancellationToken
),
cancellationToken
).
RunInBackground
(
_logger
);
_
=
Task
.
Factory
.
StartNew
(()
=>
SendPacketsLoop
(
cancellationToken
),
cancellationToken
,
TaskCreationOptions
.
PreferFairness
,
TaskScheduler
.
Default
).
ConfigureAwait
(
false
);
IsRunning
=
true
;
...
...
@@ -391,7 +391,20 @@ namespace MQTTnet.Server
{
return
;
}
// Check for cancellation again because receive packet might block some time.
if
(
cancellationToken
.
IsCancellationRequested
)
{
return
;
}
// The TCP connection of this client may be still open but the client has already been taken over by
// a new TCP connection. So we must exit here to make sure to no longer process any message.
if
(
IsTakenOver
||
!
IsRunning
)
{
return
;
}
var
processPacket
=
true
;
if
(
_eventContainer
.
InterceptingInboundPacketEvent
.
HasHandlers
)
...
...
@@ -493,6 +506,11 @@ namespace MQTTnet.Server
return
;
}
if
(
IsTakenOver
||
!
IsRunning
)
{
return
;
}
try
{
await
SendPacketAsync
(
packetBusItem
.
Packet
,
cancellationToken
).
ConfigureAwait
(
false
);
...
...
Source/MQTTnet/Server/Internal/MqttClientSessionsManager.cs
浏览文件 @
d4dad486
...
...
@@ -23,7 +23,6 @@ namespace MQTTnet.Server
{
readonly
Dictionary
<
string
,
MqttClient
>
_clients
=
new
Dictionary
<
string
,
MqttClient
>(
4096
);
readonly
AsyncLock
_createConnectionSyncRoot
=
new
AsyncLock
();
readonly
MqttServerEventContainer
_eventContainer
;
readonly
MqttNetSourceLogger
_logger
;
readonly
MqttServerOptions
_options
;
...
...
@@ -39,6 +38,8 @@ namespace MQTTnet.Server
readonly
object
_sessionsManagementLock
=
new
object
();
readonly
HashSet
<
MqttSession
>
_subscriberSessions
=
new
HashSet
<
MqttSession
>();
readonly
SemaphoreSlim
_createConnectionSyncRoot
=
new
SemaphoreSlim
(
1
,
1
);
public
MqttClientSessionsManager
(
MqttServerOptions
options
,
MqttRetainedMessagesManager
retainedMessagesManager
,
...
...
@@ -75,6 +76,8 @@ namespace MQTTnet.Server
public
async
Task
DeleteSessionAsync
(
string
clientId
)
{
_logger
.
Verbose
(
"Deleting session for client '{0}'."
,
clientId
);
MqttClient
connection
;
lock
(
_clients
)
...
...
@@ -193,7 +196,7 @@ namespace MQTTnet.Server
public
void
Dispose
()
{
_createConnectionSyncRoot
?
.
Dispose
();
_createConnectionSyncRoot
.
Dispose
();
lock
(
_sessionsManagementLock
)
{
...
...
@@ -444,7 +447,7 @@ namespace MQTTnet.Server
IMqttChannelAdapter
channelAdapter
,
ValidatingConnectionEventArgs
validatingConnectionEventArgs
)
{
MqttClient
c
onnection
;
MqttClient
c
lient
;
bool
sessionShouldPersist
;
...
...
@@ -470,8 +473,9 @@ namespace MQTTnet.Server
sessionShouldPersist
=
!
connectPacket
.
CleanSession
;
}
using
(
await
_createConnectionSyncRoot
.
WaitAsync
(
CancellationToken
.
None
).
ConfigureAwait
(
false
))
await
_createConnectionSyncRoot
.
WaitAsync
(
CancellationToken
.
None
).
ConfigureAwait
(
false
);
try
{
MqttSession
session
;
lock
(
_sessionsManagementLock
)
...
...
@@ -484,7 +488,7 @@ namespace MQTTnet.Server
{
if
(
connectPacket
.
CleanSession
)
{
_logger
.
Verbose
(
"Deleting existing session of client '{0}'."
,
connectPacket
.
ClientId
);
_logger
.
Verbose
(
"Deleting existing session of client '{0}'
due to clean start
."
,
connectPacket
.
ClientId
);
session
=
CreateSession
(
connectPacket
.
ClientId
,
validatingConnectionEventArgs
.
SessionItems
,
sessionShouldPersist
);
}
else
...
...
@@ -507,40 +511,44 @@ namespace MQTTnet.Server
await
_eventContainer
.
PreparingSessionEvent
.
InvokeAsync
(
preparingSessionEventArgs
).
ConfigureAwait
(
false
);
}
MqttClient
existing
;
MqttClient
existing
Client
;
lock
(
_clients
)
{
_clients
.
TryGetValue
(
connectPacket
.
ClientId
,
out
existing
);
c
onnection
=
CreateConnection
(
connectPacket
,
channelAdapter
,
session
);
_clients
.
TryGetValue
(
connectPacket
.
ClientId
,
out
existing
Client
);
c
lient
=
CreateClient
(
connectPacket
,
channelAdapter
,
session
);
_clients
[
connectPacket
.
ClientId
]
=
c
onnection
;
_clients
[
connectPacket
.
ClientId
]
=
c
lient
;
}
if
(
existing
!=
null
)
if
(
existing
Client
!=
null
)
{
existing
.
IsTakenOver
=
true
;
await
existing
.
StopAsync
(
MqttDisconnectReasonCode
.
SessionTakenOver
).
ConfigureAwait
(
false
);
existing
Client
.
IsTakenOver
=
true
;
await
existing
Client
.
StopAsync
(
MqttDisconnectReasonCode
.
SessionTakenOver
).
ConfigureAwait
(
false
);
if
(
_eventContainer
.
ClientConnectedEvent
.
HasHandlers
)
{
var
eventArgs
=
new
ClientDisconnectedEventArgs
(
existing
.
Id
,
MqttClientDisconnectType
.
Takeover
,
existing
.
Endpoint
,
existing
.
Session
.
Items
);
var
eventArgs
=
new
ClientDisconnectedEventArgs
(
existing
Client
.
Id
,
MqttClientDisconnectType
.
Takeover
,
existingClient
.
Endpoint
,
existingClient
.
Session
.
Items
);
await
_eventContainer
.
ClientDisconnectedEvent
.
InvokeAsync
(
eventArgs
).
ConfigureAwait
(
false
);
}
}
}
finally
{
_createConnectionSyncRoot
.
Release
();
}
return
c
onnection
;
return
c
lient
;
}
MqttClient
CreateC
onnection
(
MqttConnectPacket
connectPacket
,
IMqttChannelAdapter
channelAdapter
,
MqttSession
session
)
MqttClient
CreateC
lient
(
MqttConnectPacket
connectPacket
,
IMqttChannelAdapter
channelAdapter
,
MqttSession
session
)
{
return
new
MqttClient
(
connectPacket
,
channelAdapter
,
session
,
_options
,
_eventContainer
,
this
,
_rootLogger
);
}
MqttSession
CreateSession
(
string
clientId
,
IDictionary
sessionItems
,
bool
isPersistent
)
{
_logger
.
Verbose
(
"Created
a
new session for client '{0}'."
,
clientId
);
_logger
.
Verbose
(
"Created new session for client '{0}'."
,
clientId
);
return
new
MqttSession
(
clientId
,
isPersistent
,
sessionItems
,
_options
,
_eventContainer
,
_retainedMessagesManager
,
this
);
}
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录