dotnet / MQTTnet

MQTTnet is a high performance .NET library for MQTT based communication. It provides a MQTT client and a MQTT server (broker). The implementation is based on the documentation from http://mqtt.org/.
MIT License
4.46k stars 1.06k forks source link

Takes 7-10 minutes to re-connect to mqtt on Xamarin.iOS #1147

Closed felipemomm closed 2 years ago

felipemomm commented 3 years ago

Describe the bug

Everything works fine, I can connect to AWS using certificate, etc, however when I remove the internet cable from the router to simulate an internet loss and then I plug it again after 5 minutes, it takes too long to reconnect on iOS. In some cases I can even close the app, open it again and it still takes time to connect.

One option to overcome the issue is disconnecting from the Wifi and connecting it again, in this case, it reconnects fast.

For Android, it reconnects really fast and flawlessly.

I keep retrying every 5s and it throws "System.Net.Sockets.SocketException: Could not resolve host 'myAwsEndpoint'" and after 7-10 minutes, it suddenly reconnects.

In normal situations (without removing the cable, etc), it takes just a few seconds to connect to Aws.

Also, this only happens if the cable is removed. If I just disable the internet only for my iPad in my router admin panel and restore it after some minutes, it reconnects fast and flawlessly.

Is it a known Xamarin/iOS issue?

Which project is your bug related to?

To Reproduce

Steps to reproduce the behavior:

  1. Using this version of MQTTnet '3.0.15' (or even the latest code from the repository)
  2. Application built with Xamarin.Forms and using an iPad to test
  3. Connect to mqtt server
  4. After some time, remove the internet cable from the router
  5. Wait something like 5 minutes and plug the cable again
  6. It will take a lot of time to reconnect (7-10 minutes) and keeps throwing the error mentioned before.

Expected behavior

It should re-connect as soon as possible, not more than a few seconds (that's what happens on Android).

Code example

Just calling: _mqttClient.ConnectAsync(options);

Stack Trace

MQTTnet.Exceptions.MqttCommunicationException: Error while connecting with host 'myAwsEndpoint:8883'. ---> System.Net.Sockets.SocketException: Could not resolve host 'myAwsEndpoint'
  at System.Net.Sockets.SocketAsyncResult.CheckIfThrowDelayedException () [0x0003b] in /Library/Frameworks/Xamarin.iOS.framework/Versions/Current/src/Xamarin.iOS/mcs/class/System/System.Net.Sockets/SocketAsyncResult.cs:134 
  at System.Net.Sockets.Socket.EndConnect (System.IAsyncResult asyncResult) [0x0002c] in /Library/Frameworks/Xamarin.iOS.framework/Versions/Current/src/Xamarin.iOS/mcs/class/System/System.Net.Sockets/Socket.cs:1214 
  at System.Net.Sockets.SocketTaskExtensions+<>c.<ConnectAsync>b__5_1 (System.IAsyncResult asyncResult) [0x00000] in /Library/Frameworks/Xamarin.iOS.framework/Versions/Current/src/Xamarin.iOS/mcs/class/System/System.Net.Sockets/SocketTaskExtensions.cs:65 
  at System.Threading.Tasks.TaskFactory`1[TResult].FromAsyncCoreLogic (System.IAsyncResult iar, System.Func`2[T,TResult] endFunction, System.Action`1[T] endAction, System.Threading.Tasks.Task`1[TResult] promise, System.Boolean requiresSynchronization) [0x00019] in /Library/Frameworks/Xamarin.iOS.framework/Versions/Current/src/Xamarin.iOS/external/corert/src/System.Private.CoreLib/src/System/Threading/Tasks/FutureFactory.cs:538 
--- End of stack trace from previous location where exception was thrown ---

  at MQTTnet.Implementations.CrossPlatformSocket.ConnectAsync (System.String host, System.Int32 port, System.Threading.CancellationToken cancellationToken) [0x000a9] in /Users/Downloads/MQTTnet-master/Source/MQTTnet/Implementations/CrossPlatformSocket.cs:122 
   --- End of inner exception stack trace ---
  at MQTTnet.Implementations.CrossPlatformSocket.ConnectAsync (System.String host, System.Int32 port, System.Threading.CancellationToken cancellationToken) [0x001f7] in /Users/Downloads/MQTTnet-master/Source/MQTTnet/Implementations/CrossPlatformSocket.cs:138 
  at MQTTnet.Implementations.MqttTcpChannel.ConnectAsync (System.Threading.CancellationToken cancellationToken) [0x00377] in /Users/Downloads/MQTTnet-master/Source/MQTTnet/Implementations/MqttTcpChannel.cs:124 
  at MQTTnet.Internal.MqttTaskTimeout.WaitAsync (System.Func`2[T,TResult] action, System.TimeSpan timeout, System.Threading.CancellationToken cancellationToken) [0x00093] in /Users/Downloads/MQTTnet-master/Source/MQTTnet/Internal/MqttTaskTimeout.cs:19 
  at MQTTnet.Adapter.MqttChannelAdapter.ConnectAsync (System.TimeSpan timeout, System.Threading.CancellationToken cancellationToken) [0x0017f] in /Users/Downloads/MQTTnet-master/Source/MQTTnet/Adapter/MqttChannelAdapter.cs:80 
  at MQTTnet.Client.MqttClient.ConnectAsync (MQTTnet.Client.Options.IMqttClientOptions options, System.Threading.CancellationToken cancellationToken) [0x00201] in /Users/Downloads/MQTTnet-master/Source/MQTTnet/Client/MqttClient.cs:95 
  at MQTTnet.Client.MqttClient.ConnectAsync (MQTTnet.Client.Options.IMqttClientOptions options, System.Threading.CancellationToken cancellationToken) [0x005c3] in /Users/Downloads/MQTTnet-master/Source/MQTTnet/Client/MqttClient.cs:133 
chkr1011 commented 3 years ago

I don't think we can fix this issue in this project. We make use of plain sockets from .net framework only. The behavior of the operating system is not under our control.

Maybe you could translate the DNS name to the IP and pass the IP only to the MQTT client library? Then the lookup can be avoided.

phaseOne commented 3 years ago

I'm wondering if the .NET socket implementation on iOS is using POSIX sockets or the CFStream API. Anyone know? The gRPC project has identified similar issues with low-level TCP sockets on iOS.

chkr1011 commented 2 years ago

Closing this issue since we cannot do much about it in this library.