This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] CC3220SF:关闭并重新启动 TCP 连接的正确顺序

Guru**** 2586405 points
Other Parts Discussed in Thread: CC3220SF

请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/wireless-connectivity/wi-fi-group/wifi/f/wi-fi-forum/891816/cc3220sf-proper-sequence-to-close-and-restart-tcp-connection

器件型号:CC3220SF

您好!  

我正在设计一个系统、在该系统中、我们将有许多服务器连接到单个客户端(PC 应用程序)。 在一些边缘情况下、我认为我在服务器上执行的顺序错误、因此我正在寻找反馈。  

要进行连接、我们具有以下序列:  

  1. 加入网络:
    1. 进入站点模式(sl_WlanSetMode (Role_STA))
    2. sl_WlanConnect()
  2. 加入后、打开 TCP 端口:
    1. tcp_handle = sl_Socket (sl_AF_iNet、sl_sock_stream、0)
    2. sl_Bind(TCP_Handle,… )
    3. sl_listen (tcp_handle、...)
    4. comms_handle = sl_accept (tcp_handle,...) -阻止,直到 PC 建立连接  
  3. 连接后,使用 sl_recv (comms_handle,...) 接收数据包、直到返回0、指示 PC 已关闭连接
  4. 然后、我们调用 sl_close (tcp_handle、...)  这是需要的吗?
  5. 从步骤2.d 开始、等待下一个连接

此序列在许多连接-发送数据-断开周期中重复工作正常。  

但是、如果我在数据传输过程中关闭热点、sl_recv 永远不会返回0、因为 PC 应用程序无法正常关闭 TCP 连接。 不过,我们会检测网络的丢失,并调用 sl_close(),它将返回而不会出现错误。

此时、我们重新启动热点并成功重新加入网络。

然后、我们转到步骤2D 并调用 sl_accept (tcp_handle)、后者返回 sl_error_bsd_EBADF。 我想知道,如果 tcp_handle 资源由 sl_close()释放,则该句柄不再有效,我们应该从步骤2a 开始。 但是,当我尝试这样做时,我从 sl_Bind()中获得 sl_error_BSD_EADDRINUSE。  

删除 sl_close()可以解决该问题。 但是、我担心这会导致我们尚未发现的不同问题。  

如果您对该序列的错误位置有任何意见、我将不胜感激。  

谢谢、

Katie

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好 Katie、

    感谢您的详细步骤。 您的假设是正确的,在调用 sl_close()后,您应该从2a 重新打开一个新的套接字。 首先、您是否可以尝试将其作为所有情况的默认值、并验证其是否有效?

    如果可能、您可以在故障期间获取 NWP 日志吗?

    最后、您在 AP 断开连接上描述的内容听起来像是错误。 请给我一些时间来重新创建和深入挖掘。

    BR、

    Vince

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 Vince:

    在我们关闭/打开 TCP 套接字的典型用例中、它失败了。 我没有禁用此测试的热点。 我将代码更改为具有以下序列、这是我们典型用例的开始:

    1. 加入网络:
      1. 进入站点模式(sl_WlanSetMode (Role_STA))
      2. sl_WlanConnect()
    2. 加入后、打开 TCP 端口:
      1. tcp_handle = sl_Socket (sl_AF_iNet、sl_sock_stream、0)-> tcp_handle = 1
      2. sl_Bind(TCP_Handle,… )
      3. sl_listen (tcp_handle、...)
      4. comms_handle = sl_accept (tcp_handle,...) -阻止,直到 PC 建立连接  
    3. 连接后,使用 sl_recv (comms_handle,...) 接收数据包、直到返回0、指示 PC 已关闭连接
    4. 然后、我们调用 sl_close (tcp_handle、...)   
    5. 打开新的 TCP 端口:
      1. tcp_handle = sl_Socket (sl_AF_iNet、sl_sock_stream、0)->tcp_handle = 4
      2. sl_Bind(TCP_Handle,...) -->返回-98 = SL_ERROR_BSD_EADDRINUSE

    我不确定的几个细节是否相关:

    • SO_LINGER 设置为0。  
    • 对于上述两个调用,local_address 都传递给 sl_Bind()
      • local_address.sin_addr.s_addr = 0
      • local_address.sin_port = 32781
    • 我还尝试根据其他一些帖子在 sl_close 之后添加100ms 延迟、但它没有更改上述行为。  

    我以前没有使用 NWP 日志、我只能找到有关它的旧帖子。 您能否向我发送指向说明的链接? (我有一个 Launch-CC3220MODASF、我可以在上面运行它、尽管我们已经相对于示例项目更改了 GPIO)

    谢谢、

    Katie

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好 Katie、

    快速评论:

    • 第3点。 不正确。 如果从 sl_recv (comms_handle、...)返回错误代码(负值),则需要关闭客户端套接字。 也是如此。 在这种情况下、也可以使用 linger 选项(不带超时)。
    •  您使用的是什么 SDK 版本和 ServicePack?
    • 我认为您的问题是由于未正确关闭客户端套接字。
    • 请注意,sl_close()在没有使用 linger 选项的情况下具有硬编码的10秒内部超时。

    此处介绍了如何获取 NWP 日志

    1月

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    SDK:SDK_2_40_02_00
    服务包:sp_3.10.0.5_2.0.0.0_2.2.0.6.bin

    关于客户端不当关闭、我可以考虑许多正常原因、例如 PC 应用崩溃、网络丢失等、但我们仍应能够在服务器端继续。 此外、我无法控制或查看握手的那个端、无法知道它是否出错。   

    我还没有成功获得 NWP。 当我将以下行添加到 CC3220SF_LAUNCHXL_initGeneral()时,我的程序根本无法运行。  

    MAP_PRCMPeripheralClkEnable (PRCM_UARTA0、PRCM_RUN_MODE_CLK);
    //多路复用器 Pin62至模式1、用于输出 NWP 日志
    MAP_PinTypeUART (PIN_62、PIN_MODE_1); 

    奇怪的是、它甚至不会进入应该执行上述代码的 main。 它甚至无法执行的第一行  

    void localProgramStart (void)
    {
    uint32_t * BS;
    uint32_t * be;
    uint32_t * dl;
    uint32_t * ds;
    
    ...} 

    当我步入 localProgramStart 时、我只会得到以下内容:  

    谢谢、

    Katie

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好 Katie、

    是的、如果客户端套接字出现问题、您应该能够继续使用服务器套接字。 在这种情况下,有 TCP 服务器可以处理多个客户端 TCP 套接字,而不关闭服务器套接字,这是有意义的。 但是如果您不想这样使用,您仍然可以使用 sl_close()和 linger 选项,并设置一些合理的超时。 在更糟糕的情况下、您仍然可以重新启动 NWP 以使所有 sokt 句柄无效。

    您使用的 ServicePack 和 SDK 版本似乎略显过时。 也许您应该考虑更新到最新版本。 但我很确信、这可能不会影响您的问题。

    我不知道为什么您无法捕获 NWP 日志。 我不确定这在某种程度上是否与 IAR、TI 驱动器或其他相关。 我将 CCS 与 TI 驱动程序和 drivelib API 结合使用、捕捉 NWP 日志没有问题。 请等待 Vince 就本主题提供建议。

    1月

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    那么,你说不调用 sl_close()是可以的吗? 在其他一些情况下、这不会导致问题吗?

    我将 CCS 与我自己的 makefile 一起使用。 我怀疑它与构建有关。 我在调用 CC3220SF_LAUNCHXL_initGeneral()后立即将这两行移动到 main 中,该行有效。 这一变化不应产生任何影响,并使我感到非常紧张。  

    但无论如何、我认为能够获得下面所附的 NWP 日志。   

    我确实计划在某个时候更新到最新的 SDK、但我希望先确定正确的过程、以避免更改过多的变量。   

    谢谢、

    Katie

    使用新日志进行了更新、因为我可能没有正确配置它。  

    /cfs-file/__key/communityserver-discussions-components-files/968/teraterm2.log

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好 Katie、

    否 我想说的是、如果您想关闭套接字、您需要调用 sl_close()。 但是、例如服务器套接字、您不需要始终关闭。 这取决于您的应用代码。

    您似乎拥有正确的 NWP 日志格式。 很遗憾、我没有用于分析此日志的工具、因此您需要等待 TI 的回答。

    1月

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    我一直使用 recv 返回0作为触发来关闭连接。 但应用程序开发人员说、在其他时候也会关闭连接。 因此,我怀疑我没有在 SimpleLinkSockEventHandler()中处理适当的事件,因为我没有检测套接字何时关闭。 我看到一些 TI 示例、例如开箱即用、有一些处理方式、但它们看起来并不完整。 是否有处理服务器端异步套接字事件的示例?

    谢谢、

    Katie

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好 Katie、

    我个人不会在关闭套接字的情况下使用套接字异步处理程序。 我认为这是不必要的。 如果要确保套接字已正确关闭、您可以选择:

    • 关闭套接字时使用 linger 选项
    • 使用不带 linger 的 Close 选项、但在调用套接字关闭 API 后等待10秒
    • 在本例中、我不确定如何使用套接字异步处理程序、我从未研究过这种方法

    我个人使用这种方法...

    • 我使用手动连接程序。 在我管理 WLAN 的任务中、如果重新连接、我会重新启动 NWP。 与 NWP 配合工作的其他任务可以检测此 WLAN 断开并阻止其自身、直到再次准备好连接。
    • 我对套接字使用多个任务(基于 UDP 的 Zero-CONF、多套接字 Modbus TCP 服务器、电子邮件分离、多套接字 Web 服务器、专有通信协议服务器、HTTP POST 客户端、SNMP)。 实际上、我有19个不同的任务。 如果关闭 TCP 套接字、我有两个选项。 如果出现错误、如果从另一侧关闭套接字、则使用 linger 选项、但不使用此选项。

    >我一直使用 recv 返回0作为触发来关闭连接。

    负错误代码呢? 您也关闭插座吗?

    如果您谈到关闭套接字、您还谈到关闭客户端和服务器套接字?

    也许您应该看看 Wireshark 监听器如何关闭套接字握手。

    1月

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    客户端(我未写入的 PC 应用)启动套接字关闭。 服务器端(我在 CC3220SF 上运行的代码)需要检测套接字是否已关闭,以便服务器可以使用 sl_close()关闭其端。 服务器如何检测到客户端已关闭 TCP 套接字? 我最初以为 recv 返回0表示客户已关闭、但我怀疑这是真的。

    目前我尚未实现 SimpleLinkSockEventHandler(),但我正在寻找一种方法来检测客户端是否已关闭套接字。  

    当 recv 返回负时、我们当前声明并重新启动、因为我没有确定可以从哪些错误中恢复(或如何恢复)。 我还没有看到从 recv 中出现负返回值、因此它不是我当前问题的一部分。  

    Wireshark 是个好主意、因此我可以更好地了解 PC 应用程序的功能。

    谢谢、
    Katie

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好 Katie、

    >服务器如何检测到客户端已关闭 TCP 套接字?

    是的,从 sl_Recv()中检测到0是检测另一侧关闭的正确方法。

    也许我可以用不同的方式来回答我的问题。 如果您有 TCP 服务器、则您有一个侦听(服务器)和一个客户端(由接受创建)套接字。 如果与客户端的连接已关闭、您是否关闭两个套接字? 还是保持打开的侦听(服务器)套接字?

    1月

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Jan、

    啊、是的、现在我明白了您的意思。 没有、我没有关闭第二个插座。 我已经完成了、它几乎可以正常工作、谢谢! 现在、我想我已经讨论了我在其他论坛主题上看到的时序问题。 如果我在调用 close 函数后中断、然后运行、它就会起作用。 如果我不中断、它将失败、在 sl_Bind()上获取 SL_ERROR_BSD_EADDRINUSE。  

    如果我将 linger 设置为0、即使这会导致 TCP 连接中止、 我仍会在 sl_Bind()上获得-98=SL_ERROR_BSD_EADDRINUSE。   是否应该立即释放资源以便打开新连接?  

    我真的不希望在关闭后有10秒的延迟。 我需要准备好接受下一个连接、因为客户端可以立即重新启动它。  

    谢谢、

    Katie

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好 Katie、

    >如果我在调用 close 函数后中断、然后运行、它就会起作用。 如果我不中断、它将失败、在 sl_Bind()上获取 SL_ERROR_BSD_EADDRINUSE。

    很抱歉、我不明白你的意思。 您能否提供伪代码之类的功能?

    >如果我将 linger 设置为0,即使这会导致 TCP 连接中止, 我仍会在 sl_Bind()上获得-98=SL_ERROR_BSD_EADDRINUSE。   是否应该立即释放资源以便打开新连接?

    使用 linger 选项关闭哪个插槽? 它是由接受创建的客户端套接字吗? 如果使用 linger 选项关闭客户端套接字、则应立即通过释放套接字 RST 和套接字句柄来关闭套接字。 您可以通过 Wireshark 进行检查。  

    BTW... 如何在关闭之前设置 linger 选项。 它是这样的吗?

    Slsocklinger_t lingerOpt;
    lingerOpt.l_onoff = 1;
    lingerOpt.l_linger = 0;
    RetVal = sl_SetSockOpt (socket、sl_SOL_socket、 sl_SO_linger、&lingerOpt、sizeof (lingerOpt); 

    1月

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Jan、

    我只是用 linger 关闭了服务器端插槽。 在客户端使用 ling=0似乎解决了问题! 但是、应用程序开发人员(也是我的客户)不认为我必须使用 ling=0、因为他有一个工作中的服务器端 Raspberry PI 实现、根本不设置它。 您是否看到使用 ling=0而不是添加10秒延迟的任何原因会导致问题?

    我使用的是软件热点、因此很遗憾、Wireshark 对我不起作用。 但是、由于在客户端套接字上将 linger 设置为0似乎可以正常工作、因此我现在正在继续。  

    非常感谢您的帮助。   

    -Katie

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好 Katie、

    使用具有较短超时的套接字 linger 选项可能是更好的方法(l_linger = 1或 l_linger = 2)。 在每个套接字关闭时发送 RST 肯定不是最干净的方法。

    但是、如果不使用 Wireshark、很难说出您的案例中发生了什么。 我认为您应该考虑获取硬件以便能够捕获网络数据包。 因此、任何能够运行 OpenWRT 的路由器都能正常工作。 兼容的旧路由器、您可能会在任何地方都能免费找到。 您不需要任何昂贵的硬件来实现此目的。

    1月