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.

[参考译文] TM4C1294KCPDT:TM4C -如何处理"对等关闭的连接;在 TI NDK 中

Guru**** 2563960 points
Other Parts Discussed in Thread: SYSBIOS

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

https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/873795/tm4c1294kcpdt-tm4c--how-to-handle-connection-closed-by-peer-in-ti-ndk

器件型号:TM4C1294KCPDT
Thread 中讨论的其他器件:SYSBIOS

尊敬的团队:

我正在编写一个函数、使用 TI-NDK (2.25.00.09)通过 TCP 发布 http 请求。 我能够成功地发布 HTTP 请求并在第一次返回响应。

在第二次迭代中,NDK_recv 返回带有错误代码的0 (54 -> 对等连接复位) 。 我一直在讨论如何处理这个问题。 在这种情况下,我再次尝试调用 NDK_Connect(),但它完全与另一组错误代码混淆。

如果我看到"对等连接重置"错误、您能不能帮助您了解正确的处理方式。 是否应该 为每个 http 请求关闭并重新创建完整的套接字?,或者是否有最佳的有效方法来处理此问题。 我在下面放置了我的代码

/******** 代码代码 /


#define ETHERNETHTTP_TXDATASIZE 512 //每次推送到服务器的最大数据大小
#define ETHERNETHTTP_RXDATASIZE 512 //每次从服务器提取的最大数据大小

int EthernetHTTPSendSocket =-1;
int EthernetHTTPRecvSocket =-1;
char EthernetHTTPSendData_1[ETHERNETHTTP_TXDATASIZE]="";
char EthernetHTTPRecvData_1[ETHERNETHTTP_RXDATASIZE]="";
struct sockaddr_in EthernetHTTPSocketAddr_1;

char EthernetHTTPSocket_Restorartrequired = true;//如果需要重新启动套接字、则将位设置为 true

uint32_t 通信 IP = 0x67546006;// www.evergreeninternet.in [103.84.96.6]
char 通信 IP_number[17]="103.84.96.6";

/*从 SYSBIOS 任务调度程序创建的任务。 未动态创建*/

void HTTP_SenddataServer_1_Task ()

内部返回值、错误;
结构时间值 TimeOutValue;
struct sockaddr_in EthernetHTTP_HOSTAddr;
HTTPRESPONSE_TYPE HttpResponse_Socket1;

int HndlSelfTask = TaskSelf();
int optval;
char ReconnectSocket = true;

memset (&EthernetHTTPSocketAddr_1、0、sizeof (EthernetHTTPSocketAddr_1));
memset (&EthernetHTTP_HOSTAddr、0、sizeof (EthernetHTTP_HOSTAddr));

EthernetHTTPSocketAddr_1_1.sin_family = AF_iNet;
EthernetHTTPSocketAddr_1_1.sin_addr.s_addr = htonl (INADDR_ANY);
EthernetHTTPSocketAddr_1_1.sin_port = htons (TcpPort_HTTP);

EthernetHTTP_HOSTAddr.SIN_family = AF_iNet;
EthernetHTTP_HOSTAddr.SIN_addr.s_addr = htonl (INADDR_ANY);//发送前动态更改主机地址
EthernetHTTP_HOSTAddr.SIN_PORT = htons (TcpPort_HTTP);

TimeOutValue.tv_sec = 10;//接收和发送超时(10秒)
TimeOutValue.tv_usec = 0;


while (1)

while (EthernetHTTPSocket _Restartrequired == true)

/*等待获取有效 IP */
while (Ethernet_ETHConnStatus.CurrentIP = 0) Task_sleep (1000);

/*如果已打开,请关闭套接字*/
if (EthernetHTTPSendSocket 1!=-1)

fdClose (EthernetHTTPSendSocket 1);
fdCloseSession (HndlSelfTask);

fdOpenSession (HndlSelfTask);

/*创建套接字*/
EthernetHTTPSendSocket 1 = NDK_socket (AF_iNet、SOCK_STREAM、IPPROTO_TCP);
if (EthernetHTTPSendSocket 1 =-1)

/*此处的错误处理*/
ERR = fdError();

/*绑定套接字*/
返回值= NDK_BIND (EthernetHTTPSendSocket _1、(struct sockaddr *)&EthernetHTTPSocketAddr_1、sizeof (EthernetHTTPSocketAddr_1));
IF (返回值=-1)

/*此处的错误处理*/
ERR = fdError();

/*设置套接字选项*/
返回值= NDK_setsockopt (EthernetHTTPSendSocket 1、SOL_Socket、SO_keepalive、&optval、sizeof (optval));
返回值= NDK_setsockopt (EthernetHTTPSendSocket _1、SOL_Socket、SO_SNDTIMEO、&TimeOutValue、sizeof (TimeOutValue));
返回值= NDK_setsockopt (EthernetHTTPSendSocket _1、SOL_Socket、SO_RCVTIMEO、&TimeOutValue、sizeof (TimeOutValue));

/*以太网重新启动完成*/
EthernetHTTPSocket 恢复所需= false;
ReconnectSocket flg = true;

/*重新连接套接字*/
if (reconnectSocket _flg =true)

EthernetHTTP_HOSTAddr.SIN_addr.s_addr = htonl (CommunicationIP);//设置目标主机
返回值= NDK_CONNECT (EthernetHTTPSendSocket _1、(struct sockaddr *)&EthernetHTTP_HOSTAddr、sizeof (EthernetHTTP_HOSTAddr));
IF (返回值=-1)

/*此处的错误处理*/
ERR = fdError();
如果(err =ECONNREFUSED || err =EHOSTDOWN || err =EHOSTUNREACH)

EthernetHTTPSocket 恢复= true;

否则、如果(err =EISCONN)

/*已建立连接->套接字已连接*/
ReconnectSocket flg = false;


其他

/*已建立连接*/
ReconnectSocket flg = false;

/ /
/******** 发送/接收数据到套接字********* /

/*等待数据就绪信号量*///完成//
HTTP_GetConstruct (CommunicationIP_number、"/"、EthernetHTTPSendData_1);  //要测试的数据样本

返回值= NDK_SEND (EthernetHTTPSendSocket _1、EthernetHTTPSendData_1、strlen (EthernetHTTPSendData_1)、0);
IF (返回值=-1)

ERR = fdError();
if (err =ENOTCONN)/* 57 ->套接字未连接*/

ReconnectSocket flg = true;


其他

/* TX 成功、获取响应*/
返回值= NDK_recv (EthernetHTTPSendSocket _1、EthernetHTTPRecvData_1、ETHERNETHTTP_RXDATASIZE-1、0);
ERR = fdError();
if (err =ECONNRESET)/* 54 ->对等设备的连接复位*/

/*
*对 TI 的注释:在第二次发送 HTTP GET 时、while 循环的第二次干预在此结束
*

ReconnectSocket flg = true;

if (err =0){HTTP_ResponseDeconstruct (EthernetHTTPRecvData_1、&HttpResponse_Socket1);}


/*
*函数从数据创建 HTTP GET 请求
*
* data -> Raw Data to construct.(要构建的原始数据。
*数据长度->数据长度
* outputdat ->禁忌 HTTP GET 数据
*
*
void HTTP_GetConstruct (char* host、char* data、char* outputdat)

strcpy (outputdat、"get ");
strcat (outputdat、data);
strcat (outputdat、" HTTP/1.1");

strcat (outputdat、"\r\n 主机:");
strcat (outputdat、host);

strcat (outputdat、"\r\n 用户代理:HTTPCli (ARM;TI-RTOS)");
strcat (outputdat、"\r\n 连接:保持活动");
strcat (outputdat、"\r\n\r\n);

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

    您好 Surya、

    工程师将在今天晚些时候对此进行探讨。 同时、您能告诉我们您使用的 TI-RTOS 版本是什么吗?

    Todd

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

    你(们)好

    感谢您的关注。

    我正在使用

    TI-RTOS -> 2.16.1.14

    XDCTool -> 3.32.2.25

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

    您好 Surya、

    我可以在这里运行您的代码、但我没有遇到您所说的问题。 我不得不注释掉调用 HTTP_ResponseDeconstruct ()的行,但我怀疑这会导致任何问题。  

    尽管我确实注意到您使用 NDK_socket()调用时不正确。 NDK_socket ()将返回 sock 数据类型而不是 int 类型。 如果 NDK_socket ()失败、它将返回 INVALID_socket。  您应该具有 sock 类型的 EthernetHTTPSendSocket 1。 您拥有的内容仍将运行、但它依赖于隐式转换为 sock 类型、因此最好避免这种情况。  

    您是否有故障案例的 Wireshark 日志?

    此外、您还可以尝试使用 SDK 提供的 HTTP 客户端 API 来执行 http 请求。 相关示例、请参见 SDK_INSTALL_DIR/packages/examples/source/HttpGet。

    此致、

    达尔顿

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

    您好、Dalton、

    感谢您查看并快速响应:)

    我注意到我们的服务器连接保持活动时间默认为5秒、正如您刚才所说的、由于在超时之前发送了下一个数据、因此我在连续运行时也看不到问题、 但是、当我在每个 NDK_recv 超过5秒后放置一个断点时、我注意到了这一点、导致了这个问题(对等器件的连接复位)。 现在、我已将此默认值从5秒增加到100秒、现在非常完美。

    感谢您的建议、我现在更改了插座类型。 我从 Tcpecho 示例中获取了 int 类型、其中套接字定义为 int。 如果它也在那里得到纠正、可能会很好、或者它可能会导致误导性示例。 关于 HTTP 客户端 API 示例、它确实非常适合我、但我希望尽可能简单、以减少开销和处理时间、因为我的应用将不断地向服务器推送数据。

    我要问的下一个问题是、如果我们面临该错误、我们如何真正处理该错误。 是否应重新创建套接字? 我尝试了以下2项

    试用1:

    在此错误情况下,我尝试在同一套接字上再次调用 NDK_Connect(),但以错误响应结束,即套接字已连接

    尝试2:

    关闭套接字并重新创建它(在同一任务上)、这符合限制条件

    -我关闭了套接字并像下面的代码一样重新打开,但随着内存溢出快速运行。 在关闭会话和打开会话之间增加100ms 的延迟可以解决溢出问题、但直到我真正怀疑它是否是处理溢出问题的最佳方法。

    if (EthernetHTTPSendSocket 1!=-1)

    fdClose (EthernetHTTPSendSocket 1);
    fdCloseSession (HndlSelfTask);

    fdOpenSession (HndlSelfTask);(后跟 NDK_Socket、BIND、OPTIONS)。

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

    尊敬的 Prakash95先生:

    作为一名同事(外部人员)、我和我的小员工必须称赞您的"关心、细节和完整性"-您的快速响应中都很明显。   很棒!

    您的努力也可能会使他人受益-这很好地增强了本论坛的优势和价值。   做得非常好...

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

    来自我身边的问候! )

    从您的角度听到这种确认真的很好。

    它使我有极大的信心,我正按照每个人的期望,正确地行事。  

    非常感谢:)。 期待对查询的响应。

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

    您好 Surya、

    从任何套接字操作中获取 ECONNRESET 时、正确的过程是关闭套接字并使用新套接字开始流程。 使用同一套接字重新连接将不起作用、因为 ECONNRESET 错误指示服务器正在关闭此连接、并且不接受其上的进一步通信。  

    您也不需要再次调用 fdOpenSession()。 这只需要在任务内调用一次、因此我建议将其放置在 while (1)循环之前。 由于从不退出 while (1)循环、因此也不需要再次关闭会话。  

    您遇到的内存溢出问题到底是什么? 是堆栈溢出、还是套接字调用返回 ENOMEM? 这可能是由于重复的 fdCloseSession/fdOpenSession 调用引起的、因此您可以查看是否修复了它。

    最后、这有点令人困惑、但 tcpEcho 示例实际上也正确使用了套接字返回类型。 该示例包括 它是 NDK 中的 BSD 层。 使用该头文件、您可以调用不带 NDK_前缀的 BSD 套接字调用、这些调用会像 BSD 套接字一样返回 int FDS。 在涵盖这些调用 NDK_套接字调用的下面、但会进行一些转换以使其工作。 总之、如果您的套接字调用使用 NDK_前缀、它们将接受套接字类型、否则它们将接受 int 类型。

    很抱歉让您感到困惑、但我确实是说我第一次回答时、退货类型应该是套接字。 NDK 中有一个 sock 类型、但它仅在堆栈内部使用。  

    此致、

    达尔顿

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

    您好 、Dalton、

    感谢您的建议。 我尝试了以下方法

    -在 while 循环的开头只调用一次 fdOpenSession()。 您是对的,多次调用 fdOpenSession()和 fdCloseSession()导致错误"ENOMEM"。 另一方面、在两者之间没有延迟的情况下调用打开和关闭会话会导致堆栈溢出问题。 为了解决堆栈溢出问题、需要100ms 的最小延迟。

    - 如果出现"ECONNRESET"错误、我尝试关闭套接字并重新创建它。 我只调用 fdlose (socket)来关闭套接字。 在重新创建时,我在 NDK_BIND()处遇到一个新错误,即"48 -> EADDRINUSE"。 请您帮助我正确关闭插槽或缺少什么? (INFO:之前的命令 NDK_Socket ()不会导致任何错误,并且套接字已创建。)

    关于套接字类型:我在示例中从这里获取了它。 不过,尽管如此,感谢您提供的信息,我现在对代码进行了更改,以引用建议的正确类型,同时也感谢您的解释:)

    此致  

    Surya

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

    您好 Surya、

    NDK_BIND()之所以失败,是因为您正在尝试绑定到已在使用的地址。 fdClose ()(这是关闭套接字的正确方法)可能会释放该地址,但 TCP 会另行指示。 当您调用 fdClose ()时,TCP 协议将进入 time_wait 状态,并在2分钟后真正关闭套接字。

    不过不用担心、您无需等待2分钟。 每次创建套接字时、只应使用不同的地址。 我看到您正在设置:

    EthernetHTTPSocketAddr_1_1.sin_port = htons (TcpPort_HTTP);

    这不需要完成。 设备上的端口可以是任何端口、只需确保要发送到的端口是正确的 HTTP 端口即可。 如果您将代码更改为:

    EthernetHTTPSocketAddr_1_sin 端口= 0;

    然后、每当您调用与该 sockaddr 结构绑定时、NDK 都会为您选择任何可用的端口。  

    您正在运行的任务的堆栈大小是多少? 它可能需要更大。

    此致、

    达尔顿

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

    您好、Dalton、

    谢谢、这是一个很好的解释。  

    根据您的建议、我将端口设置为0、我现在没有问题。 它的工作很完美 关闭:)我模拟了近10次尝试以“对等错误的连接重置”结束,并重新创建了套接字。 在这些情况中,我现在没有在重新创建套接字时累积任何错误:)

    我的堆栈大小为4096。 希望这应该足够了?

    此致

    Surya

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

    您好 Surya、

    4096应该足够满足您的工作要求。 移动 fdOpenSession()后是否不再需要延迟? 如果是、我认为溢出只是打开和关闭会话的重复调用的产物。

    此致、

    达尔顿