0

我正在尝试在 iOS Kotlin/Native 通用模块中使用 TCP 套接字。

根据Apple 的文档,要打开nw_connection_t,您只需:

val connection = 
    nw_parameters_create_secure_tcp(
        NW_PARAMETERS_DISABLE_PROTOCOL,      // No TLS
        NW_PARAMETERS_DEFAULT_CONFIGURATION  // Default TCP config
    )

但是,当我在 iOS 应用程序中运行此模块时,我收到以下错误:

_nw_parameters_configure_protocol_disable_block_invoke _nw_parameters_configure_protocol_disable called directly, dumping backtrace:
[x86_64] libnetcore-1880.120.4
    0   libnetwork.dylib                    0x00007fff5118d1f8 __nw_create_backtrace_string + 120
    1   libnetwork.dylib                    0x00007fff5100a898 _nw_parameters_configure_protocol_disable_block_invoke + 120
    2   PhoenixShared                       0x00000001099af1b5 _70686f656e69783a70686f656e69782d736861726564_knbridge41 + 37
    3   PhoenixShared                       0x0000000109972eac kfun:fr.acinq.phoenix.io.BlockFunctionImpl16.invoke#internal + 220
    4   PhoenixShared                       0x0000000109972fbf kfun:fr.acinq.phoenix.io.BlockFunctionImpl16.$<bridge-UNNN>invoke(platform.darwin.NSObject?){}#internal + 95
    5   PhoenixShared                       0x000000010997342b _70686f656e69783a70686f656e69782d736861726564_knbridge47 + 251
    6   libnetwork.dylib                    0x00007fff5100d7b6 nw_parameters_create_secure_tcp + 342
...

parameters.hApple 的 Network.framework 中的标头包含:

#define NW_PARAMETERS_DISABLE_PROTOCOL (_nw_parameters_configure_protocol_disable)

...所以当然_nw_parameters_configure_protocol_disable 是直接调用的。

知道我做错了什么吗?

4

1 回答 1

2

因此,事实证明,既不NW_PARAMETERS_DISABLE_PROTOCOL也不NW_PARAMETERS_DEFAULT_CONFIGURATION应该被调用。即使它们是块类型^(nw_protocol_options_t),该nw_parameters_create_secure_tcp函数也使用它们的指针地址作为特殊标记,并且从不实际调用它们。

这是一个问题,因为 Kotlin/Native ObjC 互操作层:

  1. 转换NW_PARAMETERS_DISABLE_PROTOCOLNW_PARAMETERS_DEFAULT_CONFIGURATION阻塞成 Kotlin lambdas。
  2. 在将 lambdas 作为参数传递时包装 lambda 以将它们转换回 ObjC 块(正如我们在问题的堆栈跟踪行编号为 3 和 4 中所见)。

结果,这些特殊块的实际指针地址丢失,块被调用(它们不应该),并且发生故障。

在 Kotlin 中没有办法解决这个问题,因为 Kotlin 版本的nw_parameters_create_secure_tcp请求 lambda 参数(而不是指针)。

一个非常简单的解决方法是使用我们自己的 C-interop def 文件创建我们自己的互操作层:

package = fr.acinq.phoenix.io.network_framework
language = Objective-C

---

#include <Network/Network.h>

NW_RETURNS_RETAINED nw_parameters_t nw_k_parameters_create_secure_tcp(bool withTls) {
    return nw_parameters_create_secure_tcp(
        withTls ? NW_PARAMETERS_DEFAULT_CONFIGURATION : NW_PARAMETERS_DISABLE_PROTOCOL,
        NW_PARAMETERS_DEFAULT_CONFIGURATION
    );
}

这将创建一个 Objective-Cnw_k_parameters_create_secure_tcp函数(注意nw_k_前缀),它直接使用正确的参数调用原始nw_parameters_create_secure_tcp函数,没有 Kotlin 的 block-to-lambda-to-block 层,可以从 Kotlin 正确调用。

于 2020-07-23T09:12:10.423 回答