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.

[参考译文] SIMPLELINK-CC32XX-SDK:使用 Simplelink 功能以 TCP 客户端的方式从套接字接收数据的最快方式

Guru**** 2558250 points
Other Parts Discussed in Thread: CC3235MODSF, SIMPLELINK-CC32XX-SDK

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

https://e2e.ti.com/support/wireless-connectivity/wi-fi-group/wifi/f/wi-fi-forum/1002177/simplelink-cc32xx-sdk-fastest-way-to-receive-data-as-tcp-client-from-a-socket-using-simplelink-functions

器件型号:SIMPLELINK-CC32XX-SDK
主题中讨论的其他器件:CC3235MODSF

大家好、

我正在使用以下组件作为 TCP 客户端开发应用程序:

   具有 CC3235MODSF 的定制硬件
   SIMPLELINK-CC32XX-SDK 版本:5.10.00.02
   Service Pack 版本:4.1.0.28

目的是能够尽快从套接字接收数据。 来自 TCP 服务器的数据大小不是恒定的。 套接字上的通信是全双工的。 因此、来自 TCP 服务器的数据可能会随时接收、TCP 客户端也可以随时发送数据。

由于这些要求、我假设我必须使用一个线程来非常频繁地轮询套接字或阻止套接字、直到接收到1个字节。 如果我根据需要频繁地轮询套接字、则 MCU 延迟处理其他优先级较低的线程内的其他操作。 如果我阻止套接字、只有在收到一个字节后、我才会设置套接字非阻塞并接收其余的数据字节。 但是、这也不够快、我从调试时序中可以看到。

以下是我通过这两种不同方式调用的函数:

/* Create a client socket. */
sl_Socket(SL_AF_INET, SL_SOCK_STREAM, 0);
/* Try to connect to server. */
sl_Connect(sd, (SlSockAddr_t *)&addr, sizeof(SlSockAddr_t));
/* Set socket as non-blocking. */
nonBlocking = TRUE;
rs = sl_SetSockOpt(sd, SL_SOL_SOCKET, SL_SO_NONBLOCKING, &nonBlocking, sizeof(nonBlocking));
/* Begin receiving loop. */
while(1)
{
    /* Try receiving first byte several times. */
    for(i = 0 ; i < 100 ; i++)
    {
        /* Check socket to receive first byte. */
        rs = sl_Recv(sd, gp_buff, 1, SL_MSG_DONTWAIT);
        /* Check if there is no data. */
        if(SL_ERROR_BSD_EAGAIN == rs)
        {
            /* Sleep to try again later. */
            usleep(1000);
        }
        else
        {
            /* Break the for loop. */
            break;
        }
    }
    /* Check if first byte received. */
    if(1 == rs)
    {
        /* Receive rest of data. */
        rs = sl_Recv(sd, &gp_buff[1], 4095, SL_MSG_DONTWAIT);
        
        /* Process data.... */
    }
    /* Check if there is no data. */
    else if(SL_ERROR_BSD_EAGAIN == rs)
    {
        /* Sleep task to try again later. */
        usleep(100000);
    }
    /* Check if there is an error. */
    else
    {
        /* Break the loop. */
        break;
    }
}

/* Create a client socket. */
sl_Socket(SL_AF_INET, SL_SOCK_STREAM, 0);
/* Try to connect to server. */
sl_Connect(sd, (SlSockAddr_t *)&addr, sizeof(SlSockAddr_t));
/* Set socket as non-blocking. */
nonBlocking = TRUE;
rs = sl_SetSockOpt(sd, SL_SOL_SOCKET, SL_SO_NONBLOCKING, &nonBlocking, sizeof(nonBlocking));
/* Begin receiving loop. */
while(1)
{
    /* Block socket to receive first byte. */
    rs = sl_Recv(sd, gp_buff, 1, SL_MSG_DONTWAIT);
    /* Check if first byte received. */
    if(1 == rs)
    {
        /* Receive rest of data. */
        rs = sl_Recv(sd, &gp_buff[1], 4095, SL_MSG_DONTWAIT);
        
        /* Process data.... */
    }
    /* Check if there is an error. */
    else
    {
        /* Break the loop. */
        break;
    }
}

另一方面、如果我尝试虚拟方案、我确切知道 TCP 服务器将发送多少字节、我可以看到通信发生得非常快。

我也尝试过在触发模式下使用 SL_Select、但由于我正在使用 TI-RTOS、我在论坛中读到不建议这样做。

请告诉我是否有更好的方法来处理此 TCP 通信。

最棒的

欧格尔肯

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

    对于流式套接字、不定义有效载荷长度的协议并不常见。  

    我想、如果您使用 RTOS -最好使用阻塞方法(我看到您在两个代码样本中都将套接字定义为非阻塞)。

    您是否在服务器端定义了协议? 如果是这样、则更改它、以便您首先读取标头(有效载荷大小)、然后阻止读取有效载荷。

    BR、

    Kobi

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

    您好、Kobi、

    感谢您的回答。 这是一个没有协议的基本终端仿真器应用。 数据以 ASCII 格式发送、中间有多个控制序列。 因此、没有可用于读取负载的标头。

    您是正确的、我复制了第二段代码、看起来是错误的。 以下是它应该是怎样的:

    /* Create a client socket. */
    sl_Socket(SL_AF_INET, SL_SOCK_STREAM, 0);
    /* Try to connect to server. */
    sl_Connect(sd, (SlSockAddr_t *)&addr, sizeof(SlSockAddr_t));
    /* Begin receiving loop. */
    while(1)
    {
    	/* Set socket as blocking. */
    	nonBlocking = FALSE;
    	rs = sl_SetSockOpt(sd, SL_SOL_SOCKET, SL_SO_NONBLOCKING, &nonBlocking, sizeof(nonBlocking));
        /* Block socket to receive first byte. */
        rs = sl_Recv(sd, gp_buff, 1, 0);
        /* Check if first byte received. */
        if(1 == rs)
        {
    		/* Set socket as non-blocking. */
    		nonBlocking = TRUE;
    		rs = sl_SetSockOpt(sd, SL_SOL_SOCKET, SL_SO_NONBLOCKING, &nonBlocking, sizeof(nonBlocking));
            /* Receive rest of data. */
            rs = sl_Recv(sd, &gp_buff[1], 4095, SL_MSG_DONTWAIT);
            
            /* Process data.... */
        }
        /* Check if there is an error. */
        else
        {
            /* Break the loop. */
            break;
        }
    }

    由于我们无法为此应用定义任何协议、因此您的建议是不可能的。 在这种情况下、您会建议什么? 阻塞式读第一个字节和非阻塞式读操作其他字节是否是处理此套接字的好方法? 还是一次读取一个字节更好?

    最棒的

    欧格尔肯

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

    这取决于交通的性质。

    如果您需要突发数据、则可以尝试非阻塞方法、尽管它也不是最佳方法。  

    如果数据传输速度缓慢(例如来自 人的来源时)、那么一次等待(阻断) 1B 可能会更好。   

    您还可以考虑在 SL_SO_RCVTIMEO 设置为低值时使用分块。

    最后,如果您同时控制服务器端,我仍会在传输每个块之前添加一个长度较短的标头。 如果您无法控制服务器-我无法理解这是不可能的。

    BR、

    Kobi  

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

    您好、Kobi、

    应用程序的每个步骤中的数据大小都不同。 有时它只是几个字节、但有时它可以达到2500字节的突发。

    我还将尝试使用 sl_SO_RCVTIMEO 的低超时。 然后、我将比较每种方法的时序、并希望决定继续使用其中一种方法。

    遗憾的是、我们不控制服务器端。 服务器由我们的客户控制、其目的是将我们的器件集成到他们的系统中、同时尽可能减少他们的更改。 我会向他们提出这项改变,但我不能确定即使他们愿意,是否可以作出改变。

    非常感谢你的帮助。

    最棒的

    欧格尔肯