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.

[参考译文] TM4C129XNCZAD:EWOULDBLOCK 关闭以太网连接

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

https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/1134684/tm4c129xnczad-ethernet-connection-closed-by-ewouldblock

器件型号:TM4C129XNCZAD

大家好。

我有一个重要的用例、用来证明 TCP/IP 连接上的一种奇怪行为。

方案是:

  • CPU#1板、带 TIVAC129XNCZAD (客户端)、IP 192.168.0.100
  • CPU#2板、带 TIVAC129XNCZAD (客户端)、带 IP 192.168.0.103
  • 具有 IP 192.168.0.2的 PC Dell W10 (服务器)
  • 专用协议通信,例如使用“SEND”和“recv”(来自 NDK/socket.h)进行命令响应以传输文件
  • 编译器 TI v.18.12.7.LTS
  • TI RTOS 2.16.1.14
  • NDK v.2.25.00.09
  • XDC 3.32.00.06
  • TivaWare C_Series 2.1.4.178
  • CCS 9.3.0.00012
  • Wireshark 3.6.7 (安装在 PC Dell W10上)

 

在 TCP/IP 会话的正常运行期间,客户端发送的每个数据包都由服务器通过响应进行验证,有时两个 CPU 板中的一个会收到错误代码35 (EWOULDBLOCK)。

专用应用程序尝试使用一个 DO-while 循环恢复此情况,在此循环中,客户端尝试进行另一个接收,但在应用程序超时周期后,套接字将关闭,因为未接收到有效数据。

以下分析是使用 Wireshark 完成的。

您看到的奇怪现象是,有时,在客户端发送数据包(#1006)后,客户端(#1008)不会接收到从服务器发送的响应,因此在超时周期之后(由“setsockopt”指定) “recv”函数返回-1并使用“fdError”函数分析原因您可以看到代码 EWOULDBLOCK。

通过在串行调试接口中使用时间戳参考、我们可以将此行为发生的时间关联到另一个奇怪的事情:最后一个未验证的数据包(#1009)的 TCP 虚假重传。

TI 的 TCP /IP 协议栈似乎会自动重新发送最后一个未经验证的数据包(#1009)、并且服务器正在使用重复的 ACK 进行响应(请参阅#1010)。 我非常确信这一点,因为在我的专用应用程序中,发送计数器会停止到发送的最后一个数据包。

问题是:是否有特殊原因、因为应用程序将获得错误 EWOULDBLOCK?

 

在撰写本论坛之前,我已经阅读了几篇文章,并尝试了几个建议的修复程序。

 

我尝试过的修复程序包括:

  • 配置具有阻塞和 NO_BLOCKING 的套接字
  • 提高任务的堆栈和优先级
  • 将错误管理为我的应用程序中无故障(灾难…)
  • 增加应用程序超时和“setsockopt”超时

我已阅读的论坛包括:

https://e2e.ti.com/support/processors-group/processors/f/processors-forum/883343/tmdxice110-ndk-questions?tisearch=e2e-sitesearch&keymatch=EWOULDBLOCK#

https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/946237/tm4c129enczad-udp-recvfrom-stops-working-after-some-time/3496778?tisearch=e2e-sitesearch&keymatch=EWOULDBLOCK#3496778

https://e2e.ti.com/support/processors-group/processors/f/processors-forum/342555/meet-with-ewouldblock-error-when-use-recvnc-socket-command?tisearch=e2e-sitesearch&keymatch=EWOULDBLOCK#

https://e2e.ti.com/support/processors-group/processors/f/processors-forum/875639/ccs-processor-sdk-omapl138-continuous-callling-ndk_send-will-return--1-with-error-code-ndk_ewouldblock/3239065?tisearch=e2e-sitesearch&keymatch=EWOULDBLOCK#3239065

https://e2e.ti.com/support/processors-group/processors/f/processors-forum/771714/rtos-tms320c6678-how-to-config-recv-to-non-blocking-mode-in-ndk?tisearch=e2e-sitesearch&keymatch=EWOULDBLOCK#

https://e2e.ti.com/support/processors-group/processors/f/processors-forum/343124/how-to-tune-the-ndk-to-be-able-to-finish-one-time-of-send-and-receive-in-1ms?tisearch=e2e-sitesearch&keymatch=EWOULDBLOCK#

https://e2e.ti.com/support/processors-group/processors/f/processors-forum/422233/ti-rtos-socket-udp-non-blocking

https://e2e.ti.com/support/wireless-connectivity/wi-fi-group/wifi/f/wi-fi-forum/1011175/cc3235modsf-tcpecho/3777487?tisearch=e2e-sitesearch&keymatch=SO_NONBLOCKING#3777487

https://e2e.ti.com/support/processors-group/processors/f/processors-forum/333013/problem-with-sending-data-through-non-blocking-socket?tisearch=e2e-sitesearch&keymatch=EWOULDBLOCK#

static Bool CommNetRemote_Receive( void )
{
    Bool ret = TRUE;
    Bool bFinish = TRUE;
	
	uint16_t pckt_size = 0;
    int16_t chunk_received = 0;
    int rc = 0;
	
    commNetRemoteHeaderS header;
	CommNetRemotePktDataS *payload = (CommNetRemotePktDataS*)&commNetRemoteBuffer[SESSION_HEADER_COUNT];


    commNetRemoteCtrl.recvErr = COMM_NET_REMOTE_REQ_ACK_GENERIC_OK;
    commNetRemoteCtrl.flags.recvErr = FALSE;
    commNetRemoteCtrl.flags.timeout = FALSE;

    // uncomment if want blocking mode
	//setsockopt( commNetRemoteCtrl.clientfd, SOL_SOCKET, SO_BLOCKING, &rc, sizeof(rc));

    do {

        rc = recv( commNetRemoteCtrl.clientfd, (BYTE*)commNetRemoteBuffer, REMOTE_BUFFER_LEN, 0);
        if (rc > 0) {

            ret = TRUE;

            // fill-up the header structure, due to aligned with 3 bytes
            header.IC = commNetRemoteBuffer[0];
            header.PS_low = commNetRemoteBuffer[1];
            header.PS_high = commNetRemoteBuffer[2];

            pckt_size = (header.PS_high << 8) + header.PS_low;

            // First check, if size of packet is the same of the one declared into header
            if( rc != (pckt_size + SESSION_HEADER_COUNT) ) {
                commNetRemoteCtrl.recvErr = COMM_NET_REMOTE_SEND_ERR_PACKET_SIZE;
                OS_Error("Receive: error packet size");
                ret = FALSE;
            }
            else {

                switch( header.IC )
                {
                case SESSION_ACK_IC:
                    
                    if( CommNetRemote_CompareData( payload->sessionAck.serial, (BYTE*)appMain.config.serialNumber, 10 ) == FALSE )
                    {
                        commNetRemoteCtrl.recvErr = COMM_NET_REMOTE_SEND_ERR_SERIAL_WRONG;
                        OS_Error("Receive: serial number wrong");
                        ret = FALSE;
                    }
                    else {
						// Header ok
                    }
                    break;

                case SESSION_REQACK_IC:
                    commNetRemoteCtrl.chunk_resp++;
                    commNetRemoteCtrl.recvErr = payload->requestAck.retCode;
                    break;

                case SESSION_ABORT_IC:
                    commNetRemoteCtrl.recvErr = payload->abortReturn.retCode;
                    break;

                case SESSION_SEND_CHUNK_IC:
                    if( CommNetRemote_CompareData( (BYTE*)payload->sendChunk.GUID, (BYTE*)commNetRemoteCtrl.GUID, REMOTE_GUID_LEN) == TRUE ) {

                        chunk_received = payload->sendChunk.chunk_index[1];
                        chunk_received *= 256;  // equivale *** di 8 bit
                        chunk_received += payload->sendChunk.chunk_index[0];

                        if( chunk_received == commNetRemoteCtrl.chunk_index ) {

                            // Packet OK
                            commNetRemoteCtrl.iBytesToSend = pckt_size - (SESSION_SEND_CHUNK_PAYLOAD_COUNT - 1);
                        }
                        else {
                            // Packet KO 
                            commNetRemoteCtrl.iBytesToSend = 0;
                            commNetRemoteCtrl.recvErr = COMM_NET_REMOTE_SEND_ERR_WRONG_CHUNK;
                        }
                    }
                    else {
                        commNetRemoteCtrl.iBytesToSend = 0;
                        commNetRemoteCtrl.recvErr = COMM_NET_REMOTE_SEND_ERR_WRONG_GUID;
                    }
                    break;

                default:
                    commNetRemoteCtrl.iBytesToSend = 0;
                    commNetRemoteCtrl.recvErr = COMM_NET_REMOTE_SEND_ERR_UNDEFINED;
                    break;
                }
            }
        }
        else {
            bFinish = TRUE;
            ret = FALSE;
            rc = fdError();

            if( rc == 0 ) {
			
                // close communication: error managed by upper layer
				//
                commNetRemoteCtrl.recvErr = COMM_NET_REMOTE_SEND_ERR_RECV_ZERO_BYTE;
            }
            else {
                commNetRemoteCtrl.recvErr = rc;

                if( (rc == EWOULDBLOCK) || (rc == EAGAIN) ) {

                    // The timeout is started by upper layer. when the time is reached the flag commNetRemoteCtrl.flags.timeout is updated
					//
                    if( commNetRemoteCtrl.flags.timeout == FALSE ) {

                        bFinish = FALSE;
                        OS_Sleep( OS_HUNDRED_MILLISECONDS );
                    }
                    else {
					
                        // Timeout reached : error managed by upper layer
                    }
                }
                else {
				
                    // Other error codes: error managed by upper layer
                }
            }
			
            OS_Error( "Receive: err socket (%ld) @ %ld.", rc, OS_GetTimerTick() );
        }

    } while ( bFinish != TRUE );

    return (ret);
}



void CommNetRemote_ClientProcess(TASK_ARG_T arg0, TASK_ARG_T arg1)
{
    int  status = 0;
    int32_t err = 0;
    int16_t iWaitCount = 0;
    struct timeval to;
    CommNetRemotePktDataS *payload = (CommNetRemotePktDataS*)&commNetRemoteBuffer[SESSION_HEADER_COUNT];


    commNetRemoteCtrl.enabled = TRUE;
    commNetRemoteCtrl.state = COMM_NET_REMOTE_STS_INIT_WAIT;
    commNetRemoteCtrl.flags.all = 0;
    commNetRemoteCtrl.recvErr = COMM_NET_REMOTE_REQ_ACK_GENERIC_OK;
    commNetRemoteCtrl.sendErr = COMM_NET_REMOTE_REQ_ACK_GENERIC_OK;

    // Create a TCP stream socket.
    commNetRemoteCtrl.clientfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (commNetRemoteCtrl.clientfd < 0) {

        commNetRemoteCtrl.flags.quit = TRUE;
        OS_Error("CommNet_RemoteClientProcess: socket failed.");
    }
    else {

        // Setup the Server IP address and port
        memset((char *) &commNetRemoteCtrl.servAddr, 0, sizeof(commNetRemoteCtrl.servAddr));
        commNetRemoteCtrl.servAddr.sin_family = AF_INET;
        commNetRemoteCtrl.servAddr.sin_port = htons(REMOTE_SERVER_PORT);
        commNetRemoteCtrl.servAddr.sin_addr.s_addr = inet_addr(REMOTE_SERVER_IP );

        to.tv_sec  = REMOTE_SOCKET_TIMEOUT;
        to.tv_usec = 0;
        setsockopt( commNetRemoteCtrl.clientfd, SOL_SOCKET, SO_RCVTIMEO, &to, sizeof( to ) );
        setsockopt( commNetRemoteCtrl.clientfd, SOL_SOCKET, SO_SNDTIMEO, &to, sizeof( to ) );

        // Connect to the server
        status = connect(commNetRemoteCtrl.clientfd, (struct sockaddr *) &commNetRemoteCtrl.servAddr, sizeof(commNetRemoteCtrl.servAddr));
        if (status < 0) {

            fdClose( commNetRemoteCtrl.clientfd );
            commNetRemoteCtrl.flags.quit = TRUE;
            OS_Error("CommNet_RemoteClientProcess: client connect failed. (%d).",fdError() );
        }
        else {
            // Init the Error_Block
            Error_init(&commNetRemoteCtrl.eb);
            commNetRemoteCtrl.state = COMM_NET_REMOTE_STS_OPEN_SESSION;
            commNetRemoteCtrl.flags.quit = FALSE;
            OS_SysDbg( "RemoteControlClientProcess: start clientfd = 0x%x.", commNetRemoteCtrl.clientfd );
        }
    }

    // Loop while we receive data
    while( commNetRemoteCtrl.flags.quit == FALSE )
    {
        switch( commNetRemoteCtrl.state )
        {
        case COMM_NET_REMOTE_STS_IDLE:
            //
            // controlla le condizioni di uscita
            if( appMain.diagnostic.general.flags.cableDisconnected == TRUE ) {
                commNetRemoteCtrl.flags.quit = TRUE;
            }
            else {
                if( Network_IsLANConfigured() == FALSE) {
                    commNetRemoteCtrl.flags.quit = TRUE;
                }
            }

            if( commNetRemoteCtrl.flags.close == TRUE ) {
                commNetRemoteCtrl.flags.quit = TRUE;
            }

            // Check if request flag is active , then close session
            if( commNetRemoteCtrl.flags.quit == FALSE ) {

                if( commNetRemoteCtrl.flags.request == TRUE ) {

                    commNetRemoteCtrl.state = COMM_NET_REMOTE_STS_CLOSE_SESSION;
                }
                else {
                    OS_Sleep(OS_TEN_MILLISECONDS);
                }
            }
            break;

        case COMM_NET_REMOTE_STS_WAIT_RESP:
            if( CommNetRemote_Receive() == FALSE ) {

                commNetRemoteCtrl.state = COMM_NET_REMOTE_STS_RECV_ERROR;
            }
            else {
                commNetRemoteCtrl.state = COMM_NET_REMOTE_STS_IDLE;
            }
            break;

        case COMM_NET_REMOTE_STS_OPEN_SESSION:
            // Compose header

            // Compose payload

            OS_SysDbg("Open session: %ld ", OS_GetTimerTick() );

            if( CommNetRemote_Send( commNetRemoteBuffer, SESSION_OPEN_HEADER_PAYLOAD) == TRUE ) {
                // decide il prossimo stato
                commNetRemoteCtrl.state = COMM_NET_REMOTE_STS_WAIT_RESP;
            }
            else {
                commNetRemoteCtrl.recvErr = COMM_NET_REMOTE_SEND_ERR_NONE;
                commNetRemoteCtrl.state = COMM_NET_REMOTE_STS_SEND_ERROR;
                iWaitCount = 0;
            }
            break;

        case COMM_NET_REMOTE_STS_CLOSE_SESSION:
            // Compose the header

            // Compose payload

            // Get return code
            CommNetRemote_GetLastErr(&err);
            payload->sessionClose.retcode = err;

            OS_SysDbg("Close session: %ld ", OS_GetTimerTick() );

            CommNetRemote_Send( commNetRemoteBuffer, SESSION_CLOSE_HEADER_PAYLOAD);

            // decide il prossimo stato
            OS_SetPeriodicTask(commNetRemoteCtrl.timer, OS_ONE_SECOND);
            OS_StartPeriodicTask(commNetRemoteCtrl.timer);
            commNetRemoteCtrl.flags.request = FALSE;
            commNetRemoteCtrl.state = COMM_NET_REMOTE_STS_IDLE;
            break;

        case COMM_NET_REMOTE_STS_PUBLISH_FILE:
            // Compose the header

            // Compose payload

            if( CommNetRemote_Send( commNetRemoteBuffer, SESSION_PUBLISH_HEADER_PAYLOAD) == TRUE ) {

                commNetRemoteCtrl.state = COMM_NET_REMOTE_STS_WAIT_RESP;
            }
            else {
                commNetRemoteCtrl.recvErr = COMM_NET_REMOTE_SEND_ERR_NONE;
                commNetRemoteCtrl.state = COMM_NET_REMOTE_STS_SEND_ERROR;
                iWaitCount = 0;
            }
            break;

        case COMM_NET_REMOTE_STS_PUBLISH_CHUNK:
            // Compose the header

            // Compose payload

            if( CommNetRemote_Send( commNetRemoteBuffer, (commNetRemoteCtrl.iBytesToSend + SESSION_HEADER_COUNT) ) == TRUE ) {

                commNetRemoteCtrl.state = COMM_NET_REMOTE_STS_WAIT_RESP;
            }
            else {
                commNetRemoteCtrl.recvErr = COMM_NET_REMOTE_SEND_ERR_NONE;
                commNetRemoteCtrl.state = COMM_NET_REMOTE_STS_SEND_ERROR;
                iWaitCount = 0;
            }
            break;

        case COMM_NET_REMOTE_STS_GET_FILE:
            // Compose the header
 
            // Compose payload

            if( CommNetRemote_Send( commNetRemoteBuffer, SESSION_GET_HEADER_PAYLOAD) == TRUE ) {

                commNetRemoteCtrl.state = COMM_NET_REMOTE_STS_WAIT_RESP;
            }
            else {
                commNetRemoteCtrl.recvErr = COMM_NET_REMOTE_SEND_ERR_NONE;
                commNetRemoteCtrl.state = COMM_NET_REMOTE_STS_SEND_ERROR;
                iWaitCount = 0;
            }
            break;

        case COMM_NET_REMOTE_STS_GET_CHUNK:
            // Compose the header

            if( CommNetRemote_Send( commNetRemoteBuffer, SESSION_GET_CHUNK_HEADER_PAYLOAD ) == TRUE ) {

                commNetRemoteCtrl.state = COMM_NET_REMOTE_STS_WAIT_RESP;
            }
            else {
                commNetRemoteCtrl.recvErr = COMM_NET_REMOTE_SEND_ERR_NONE;
                commNetRemoteCtrl.state = COMM_NET_REMOTE_STS_SEND_ERROR;
                iWaitCount = 0;
            }
            break;

        case COMM_NET_REMOTE_STS_SEND_ERROR:
            // Wait for error management with flag commNetRemoteCtrl.flags.sendErr in order to be sncronized with upper layer 
			//
            // Starvation avoid: after 200 times return idle.
            //
            iWaitCount++;

            if( iWaitCount > 200 ) {
                iWaitCount = 0;
                commNetRemoteCtrl.state = COMM_NET_REMOTE_STS_IDLE;
            }
            else {
                if( TRUE == commNetRemoteCtrl.flags.sendErr ) {
                    commNetRemoteCtrl.state = COMM_NET_REMOTE_STS_IDLE;
                }
                else {
                    OS_Sleep(OS_HUNDRED_MILLISECONDS);
                }
            }
            break;

        case COMM_NET_REMOTE_STS_RECV_ERROR:
            commNetRemoteCtrl.flags.recvErr = TRUE;
            commNetRemoteCtrl.state = COMM_NET_REMOTE_STS_IDLE;
            break;

        default:
            commNetRemoteCtrl.state = COMM_NET_REMOTE_STS_IDLE;
            break;
        }

    }  // while( commNetRemoteCtrl.flags.quit == FALSE )

    // The process is closed
    //
    if( commNetRemoteCtrl.clientfd ) {
        fdClose( commNetRemoteCtrl.clientfd );
        OS_SysDbg("Close socket.");
    }

    // Clean all variables
    OS_SysDbg("CommNetRemote_ClientProcess: quit.");

    commNetRemoteCtrl.enabled = FALSE;
    commNetRemoteCtrl.flags.all = 0;

    OS_DeleteTask(commNetRemoteCtrl.taskHandle);
    commNetRemoteCtrl.taskHandle = OS_TASK_ERROR;

    return;
}

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

    抱歉、我无法上传 Wireshark 捕获的清晰图像。 我正在处理这个。

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

    尊敬的 Marco:

    [引用 userid="177852" URL"~/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/1134684/tm4c129xnczad-ethernet-connection-closed-by-ewouldblock "]

    问题是:是否有特殊原因、因为应用程序将获得错误 EWOULDBLOCK?

    [/报价]

    我想 EWOULDBLOCK 是因为您使用的是非阻塞模式。 这是正确的理解吗?

    [引用 userid="177852" URL"~/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/1134684/tm4c129xnczad-ethernet-connection-closed-by-ewouldblock "]

    我尝试过的修复程序包括:

    • 配置具有阻塞和 NO_BLOCKING 的套接字
    • 提高任务的堆栈和优先级
    • 将错误管理为我的应用程序中无故障(灾难…)
    • 增加应用程序超时和“setsockopt”超时
    [/报价]

    是否有任何修复可解决此问题? 例如、如果您更改为 no_blocking、它是否会起作用?

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

    你(们)好,查尔斯

    很遗憾、我 获得 了具有阻塞和无阻塞设置的 EWOULDBLOCK。

    上述任何修复均无法解决问题。

    此外、我还在 send 和 recv 之间添加了一个延迟、睡眠时间约为100ms、但我仍然看到相同的行为。

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

    尊敬的 Marco:

     您能否使用客户端导入并运行 tcpecho 服务器? 您是否会看到相同的问题?

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

    它需要更多的时间、但我可以进行此尝试。

    在我完成后通知您。

    此致

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

    您好、Charles、

    从我的角度来看、我需要一个恰好相反的示例:CPU 板是客户端、PC 是服务器。

    TCPecho 示例将板置于服务器中... 是否有上述示例?

    提前感谢、

    Marco

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

    您好!

     请参阅此应用手册。 https://www.ti.com/lit/pdf/spma080。应用手册中有一个客户端示例。