使用 Microsoft.Extensions.Caching.Redis.Core 连接 redis,在 Linux 上运行时报下面的错误:
This platform does not support connecting sockets to DNS endpoints via the instance Connect and ConnectAsync methods, due to the potential for a host name to map to multiple IP addresses and sockets becoming invalid for use after a failed connect attempt. Use the static ConnectAsync method, or provide to the instance methods the specific IPAddress desired. at System.Net.Sockets.Socket.ThrowIfNotSupportsMultipleConnectAttempts() at System.Net.Sockets.Socket.BeginConnect(String host, Int32 port, AsyncCallback requestCallback, Object state) at System.Threading.Tasks.TaskFactory`1.FromAsyncImpl[TArg1,TArg2](Func`5 beginMethod, Func`2 endFunction, Action`1 endAction, TArg1 arg1, TArg2 arg2, Object state, TaskCreationOptions creationOptions) at System.Net.Sockets.SocketTaskExtensions.ConnectAsync(Socket socket, String host, Int32 port) at StackExchange.Redis.SocketManager.BeginConnect(EndPoint endpoint, ISocketCallback callback, ConnectionMultiplexer multiplexer, TextWriter log) at StackExchange.Redis.PhysicalConnection.BeginConnect(TextWriter log) at StackExchange.Redis.PhysicalBridge.GetConnection(TextWriter log) at StackExchange.Redis.ServerEndPoint..ctor(ConnectionMultiplexer multiplexer, EndPoint endpoint, TextWriter log) at StackExchange.Redis.ConnectionMultiplexer.<ReconfigureAsync>d__119.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at StackExchange.Redis.ConnectionMultiplexer.<ConnectAsync>d__72.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.Extensions.Caching.Redis.RedisCache.<ConnectAsync>d__17.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.Extensions.Caching.Redis.RedisCache.<GetAndRefreshAsync>d__19.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.Extensions.Caching.Redis.RedisCache.<RefreshAsync>d__15.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.AspNetCore.Session.DistributedSession.<CommitAsync>d__31.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.AspNetCore.Session.SessionMiddleware.<Invoke>d__9.MoveNext()
而换成IP地址就能正常连接。
问题发生在 StackExchange.Redis 的源码中下面的部分:
socket.ConnectAsync(dnsEndpoint.Host, dnsEndpoint.Port).ContinueWith(t => { multiplexer.LogLocked(log, "EndConnect: {0}", formattedEndpoint); EndConnectImpl(t, multiplexer, log, tuple); multiplexer.LogLocked(log, "Connect complete: {0}", formattedEndpoint); });
在github上提交了一个解决这个问题的pull request:Wordaround for connecting redis via host name on Linux
异常是在 System.Net.Sockets.Socket.BeginConnect() 的下面这行代码抛出的:
ThrowIfNotSupportsMultipleConnectAttempts();
它的对应实现是:
private static void ThrowIfNotSupportsMultipleConnectAttempts() { if (!SocketPal.SupportsMultipleConnectAttempts) { throw new PlatformNotSupportedException(SR.net_sockets_connect_multiaddress_notsupported); } }
在 SocketPal.Windows.cs 中 SupportsMultipleConnectAttempts 的值是 true 。
在 SocketPal.Unit.cs 中 SupportsMultipleConnectAttempts 的值是 false 。
异常不也这么说的吗,就是说了不支持的
这个本身就不支持,没什么好说的。。。
这个问题我很久之前就提到过了,见:https://github.com/StackExchange/StackExchange.Redis/issues/454
同一个host可能绑定多个 ip ,所以他们把这个锅退给了CoreCLR。