嵌入式技术论坛
直播中

风来吴山

8年用户 1414经验值
擅长:电源/新能源
私信 关注
[问答]

如何去解决TCP客户端断开重练的问题呢

最近小菜菜我又要做RTT连接远程服务器的项目,也是最近搞的一头雾水,情况是这样的:

我用RTT创建俩线程一个是TCP连接线程优先级是13,一个是TCP心跳包的线程优先级是14,
1.TCP连接线程优先级高先运行,先分配一块内存作为TCP数据接收,然后建socket,然后对远端IP连接,连接之后先发送一串数据,紧接着挂起到LWIP_RECV上,等待服务器数据,无数据此线程挂起,
2.TCP心跳包线程开始运行,他主动用上一个线程建立的SOCKRT发送一个心跳包LWIP——send();然后他就延时挂起了时间是10秒,也就是说这个线程是每十秒运行一次发送心跳包,
3.网络连接成正常数据都正常,但是实际并不是这样的要考虑断网或者服务器异常的情况,那么我就模拟服务器异常,我希望只要服务器一上线我RTT既可以连接上,所以我在远程服务器用了网络调试助手,我只要点击监听/断开就好了,就可以模拟出来,OK下面说现象。

当远程服务器断开之后,那么优先级为13的TCP链接线程挂起在邮箱上就会返回错误,这时先销毁socket,然后再重复创建链接,如果不成功一直重复创建链接销毁的过程,如果成功就发送一串数据,继续挂起在RECV上等待,实际情况是这样的,他会从新连接,会执行,但是。。。。。
但是当服务器端监听/断开很频繁的时候最多可以自动重连4次-6次不等,就进入TCP/IP的断言里面void sys_arch_assert(const char* file, int line)

这个函数,

如果服务器端监听/断开不频繁,控制在10秒以外,就可以一直的有重练接,不会进入断言,

也就是说又一个未知的时间内做了一些什么事情,让他进入了断言,
我初步考虑是TCP/IP和APP程序之间的优先级问题,或者是NET_TX,NET_RX线程优先级问题,
目前我的TCPIP处理线程优先级是12,TXRX是优先级是15.TCP 连接线程优先级是13,心跳线程是14,
如果调整为TCPIP处理线程优先级是10,TXRX是优先级是11.TCP 连接线程优先级是13,心跳线程是14,也就是说抬高TCP/IP的优先级,会不会好呢?我想这个应该大问题没有,那个细节忽略了,

这是TCP连接线程的代码:

_> ```void tcpclient_SC(const char *url, int port)
{
while(1)
{
char *recv_data;
struct hostent host;
rt_uint32_t bytes_received;
struct sockaddr_in server_addr;
recv_data = rt_malloc(BUF);
if (recv_data == RT_NULL)
{
rt_kprintf("No memory
");
return;
}
start:
// rt_thread_delay(300);
//rt_thread_delay(1000);
/
通过函数入口参数url 获得host 地址(如果是域名,会做域名解析) /
// host = gethostbyname(url);
/
分配用于存放接收数据的缓冲 /
/
创建一个socket,类型是SOCKET_STREAM,TCP 类型 /
if ((tcp_clint_sock = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
/
创建socket 失败 /
rt_kprintf("Socket error
");
/
释放接收缓冲 /
rt_free(recv_data);
return;
}
/
初始化预连接的服务端地址 */
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port);
server_addr.sin_addr = *((struct in_addr )host->h_addr);
rt_memset(&(server_addr.sin_zero), 0,sizeof(server_addr.sin_zero));
/
连接到服务端 */
if (connect(tcp_clint_sock, (struct sockaddr )&server_addr,sizeof(struct sockaddr)) == -1)
{
/
连接失败 */
rt_kprintf("Connect error
");
lwip_close(tcp_clint_sock );
/*释放接收缓冲 /
// rt_free(recv_data);
goto start;
}
send(tcp_clint_sock, send_data, strlen(send_data), 0);
//链接建立
while (1)
{
/
从sock 连接中接收最大BUFSZ - 1 字节数据 /
bytes_received = recv(tcp_clint_sock, recv_data, BUF - 1, 0);
if (bytes_received <= 0)
{
/
接收失败,关闭这个连接 */
lwip_close(tcp_clint_sock);
break;
}
rt_sem_take(tcp_sem_lock, RT_WAITING_FOREVER); //取得信号量锁死
recv_data[bytes_received] = '�';
send(tcp_clint_sock, "ok
", strlen("ok
"), 0); //回复服务器已经收到数据
memcpy(Tcp_Buf, recv_data, bytes_received); //复制接收缓存到暂存BUF
rt_sem_release(tcp_sem_lock);//释放信号锁
rt_mb_send(&tcp2si_mbox, bytes_received); //接收到数据发送邮箱
}
}
}

回帖(3)

陈丽

2022-11-2 11:10:09
试一试下面的代码:

#define BUF_SIZE    512
static char buffer[BUF_SIZE];
static int socket;
void tcp_client_thread(void *p)
{
    while(1)
    {
        while((socket = lwip_socket(AF_INET, SOCK_STREAM, 0)) == -1)
        {
            rt_thread_delay(RT_TICK_PER_SECOND/5);
            continue;
        }
        lwip_setsockopt( socket, IPPROTO_TCP, TCP_NODELAY, &optval, sizeof(optval));
        ServerAddr.sin_family = AF_INET;            
        ServerAddr.sin_port = htons(devInfo.server_port);
        ServerAddr.sin_addr.s_addr = devInfo.server_ip.addr;
        rt_memset(&(ServerAddr.sin_zero),0, sizeof(ServerAddr.sin_zero));
        if(connect(socket, (struct sockaddr *)&ServerAddr, sizeof(struct sockaddr)) == -1)
        {
            rt_thread_delay(RT_TICK_PER_SECOND/5);
            lwip_close(socket);
            continue;
        }
        lwip_send(socket, buffer, 10, MSG_DONTWAIT);
        printf("连接到服务器!
");
        memset(buffer, 0, sizeof(buffer));
        time.tv_sec = 300;   
        time.tv_usec = 0;   
        while(1)
        {
            FD_ZERO(&readset);
            FD_SET(socket, &readset);
            ret = lwip_select(socket + 1, &readset, 0, 0, &time);
            if(ret > 0 && FD_ISSET(socket, &readset))
            {
                len = lwip_recv(socket, buffer,  sizeof(buffer), 0);
                if(len > 0)
                {
                    rt_hw_led_on(LED4);
                    data_handler(buffer, len);
                    memset(buffer, 0, sizeof(buffer));
                    rt_thread_delay(RT_TICK_PER_SECOND/10);
                    rt_hw_led_off(LED4);
                }
                else
                {
                    lwip_close(socket);
                    printf("连接关闭!
");
                    break;
                }
            }
            else
            {    //心跳包
                char ch = 0xAB;
                if(lwip_send(socket, &ch, 1, MSG_DONTWAIT) == -1)
                {
                    printf("连接异常!
");
                    lwip_close(socket);
                    break;
                }
            }
        }
    }
}
举报

刘娟

2022-11-2 11:10:17
多线程操作同一个socket !!!
举报

刘娟

2022-11-2 11:10:23
用select,TCP编程是有些地方需要注意的,否则容易陷进去
举报

更多回帖

发帖
×
20
完善资料,
赚取积分