stm32f429+rtthread,想实现的功能是,can收到的消息通过网口发出去,tcp client收到的信息通过can发出去。
rtt的msh里运行的程序是运行在msh线程里吧?我是在msh线程里初始化了can、tcp client。在msh线程的的主循环里,阻塞读取tcp信息,读取到以后通过can发送出去。到这里能正常执行,pc端通过tcp servier发送信息后,can监视端口能看到信息。
msh线程初始化时,同时新建了个can读线程。can读线程里等待can中断发送的信号量,等到后通过lwip_send()发送出去。
lwip用到的sock,我是在该.c文件里进行了全局定义。结果pc端的tcp servier程序收不到东西。
之前测试时,在msh线程里,tcp client收到信息后立刻返回一段信息,pc端是能正常收到的。
离线
if((sock=socket(AF_INET,SOCK_STREAM,0))==-1)
{
rt_kprintf("Socket error\n");
rt_free(tcp_recv_data);
return;
}
在线程里调用socket()函数创建socket,过程中创建的都是在线程里,返回的整形sock,即时定义为全局变量,在其它线程调用这个sock也不能直接用来tcp发送。
现在改变想法,can接收线程里不在直接tcp发送了,而是通过消息队列发送给tcp线程。
现在tcp线程的主循环里需要做的是,阻塞等待tcp接收,收到后,通过can发送出去。等待消息队列,等到后读取然后通过tcp发送出去。
又遇到了问题,电脑端打开了tcp server和can监控,tcp server发送消息后,can软件能收到。
can软件发送后,tcp server没有立刻收到消息。而是下次tcp server发送消息时,同时收到了之前的消息。
while (1)
{
bytes_received=recv(sock,tcp_recv_data,BUFSZ-1,0);
if (bytes_received<0)
{
closesocket(sock);
rt_kprintf("\nreceived error-1, close the socket.\r\n");
rt_free(tcp_recv_data);
break;
}
else if(bytes_received==0)
{
closesocket(sock);
rt_kprintf("\nreceived error0, close the socket.\r\n");
rt_free(tcp_recv_data);
break;
}
tcp_recv_data[bytes_received]='\0';
{
rt_kprintf("thread1: recv msg from msg queue, the content:%c\n", tcp_recv_data[0]);
can_msg.data[0]=tcp_recv_data[0];
can_msg.data[1]=tcp_recv_data[1];
can_msg.data[2]=tcp_recv_data[2];
can_msg.data[3]=tcp_recv_data[3];
can_msg.data[4]=tcp_recv_data[4];
can_msg.data[5]=tcp_recv_data[5];
can_msg.data[6]=tcp_recv_data[6];
can_msg.data[7]=tcp_recv_data[7];
can_size=rt_device_write(can_dev,0,&can_msg,sizeof(can_msg));
}
/* 从消息队列中接收消息 */
if (rt_mq_recv(&can_rx_mq, &can_recv_data, 8, 1000) == RT_EOK)
{
rt_kprintf("thread1: recv msg from msg queue, the content:%c\n", can_recv_data[0]);
send(sock,&can_recv_data,8,0);
// send(sock,"hahahaha",8,0);
}
/* 延时 50ms */
rt_thread_mdelay(50);
}
rt_kprintf("thread1: detach mq \n");
rt_mq_detach(&can_rx_mq);
离线
想了想,tcp线程的主循环里,有两个等待。
一个是lwip的recv()函数,这个是阻塞读取。
另一个是消息队列的等待。
现在应该是lwip的阻塞读取一直卡住了,消息队列接收只能等Lwip读取到消息后才能执行。
那么lwip的读取改成不阻塞呢?
离线
我将tcp线程的接收改为非阻塞模式,
bytes_received=recv(sock,tcp_recv_data,BUFSZ-1,MSG_DONTWAIT)
结果仍一样。
应该还死卡在tcp接收这里,甚至阻塞了can线程的运行。直到tcp线程接收到tcp信息后,can线程才执行can读取操作及消息队列的发送。
离线
现在改用select方式,不再阻塞can线程了,但是tcp线程还是阻塞在tcp接收这里。
tcp线程主循环里,现在执行的是,用select方式读取tcp消息,还有等待消息队列。
现在现象是,能看到can线程收到can信息,大概也能通过消息队列把信息发出去,而tcp线程是要等到tcp接收后才能执行消息队列的接收。
离线
maxfdp1 = sock+1;
tim.tv_sec=0;
tim.tv_usec=100000;
while (1)
{
FD_ZERO(&readset);
FD_SET(sock,&readset);
i=select(maxfdp1,&readset,0,0,&tim);
if(i==0)
continue;
if(FD_ISSET(sock,&readset))
{
bytes_received=recv(sock,tcp_recv_data,BUFSZ-1,MSG_DONTWAIT);
if(bytes_received==-1)
{...}
else if (bytes_received<0)
{...}
else if(bytes_received==0)
{...}
tcp_recv_data[bytes_received]='\0';
{...}
}
/* 从消息队列中接收消息 */
if (rt_mq_recv(&can_rx_mq, &can_recv_data, 8, 100) == RT_EOK)
{
rt_kprintf("thread1: recv msg from msg queue, the content:%c\n", can_recv_data[0]);
send(sock,&can_recv_data,8,0);
}
改成这样了,接收时间也改了。但还是阻塞在接收这里。
最近编辑记录 Gentlepig (2021-06-25 16:50:30)
离线
tcp循环里更改了下顺序,先等待消息队列,然后在进行tcp的select接收。这样就可以了。
之前是在select()以后,根据返回结果进行判断,有的直接continue,跳过了后面的等待消息队列。
离线
send可以在另一个线程里使用。
我之前在其它线程里send不成功,有两个问题,一个是tcp线程没有用select,recv阻塞了其它线程。另一个是send里第三个参数写错了...
现在收发过程正常了,还有2个问题需要考虑。
1,can总线上只有1个设备时,can初始化无法成功,我靠在can初始化这里while一直等待can初始化成功?
2,网络断了的话,如何进行tcp重连?我是在FDISSET()里,进行recv()接收后,判断返回的数,如果是<=0,则执行connect(),然后continu,跳到下次循环。结果目前现象是,一旦断网就卡住了。
离线
Socket函数没有配置选项吗 感觉应该是创建在heap里 然后返回句柄 感觉这种经典问题应该是早被解决了
离线
有重试了几次,发现些现像。
我现在在tcp线程里,有两个while循环,外层里有socket(),connect()函数,内层执行select接收。
select接收出错后,关闭soket,跳出内层循环。在外层循环里重新建立socket及连接。
实验时,上电后正常,可以can和tcp相互转发。
我将pc的tcp server断开后再重连,然后板子can接收tcp发送正常,tcp接收转can发送第一次正常,第二次就报错了。
(rt_object_get_type(&mb->parent.parent) == RT_Object_Class_MailBox) assertion failed at function:rt_mb_send_wait, line number:
(rt_object_get_type(&mb->parent.parent) == RT_Object_Class_MailBox) assertion failed at function:rt_mb_send_wait, line number:
最近编辑记录 Gentlepig (2021-06-28 17:18:23)
离线
目前tcp线程大致是这样的,在tcp client线程里写了里外两个while(1)循环。外层循环了,调用的是socket(),connect()函数,内层循环里是调用select()根据结果来决定是否接收,出错后关闭socket,然后跳到外层循环。
想的是这样的,可实际操作后,上电通讯成功后,关闭tcp server然后再打开,发现打印出重新重建了socket和重新连接了。电脑端通过can发送信息后,设备接收后也可以通过tcp发送到tcp server.多次发送也没问题。
但电脑端第一次发送tcp消息后,设备接收后可以通过can发过来。电脑端再次发送,接报错了...
while(1)
{
...
sock=-1;
while(sock==-1)
{
sock=socket(AF_INET,SOCK_STREAM,0);
}
rt_kprintf("socke is created.\r\n");
...
if (connect(sock,(struct sockaddr*)&server_addr,sizeof(struct sockaddr))==-1)
{
rt_kprintf("Connect fail!\n");
closesocket(sock);
rt_free(tcp_recv_data);
return;
}
else
{
rt_kprintf("Connect successful\n");
}
...
while (1)
{
FD_ZERO(&readset);
FD_SET(sock,&readset);
i=select(maxfdp1,&readset,0,0,&tim);
if(i==0)
continue;
if(FD_ISSET(sock,&readset))
{
bytes_received=recv(sock,tcp_recv_data,BUFSZ-1,MSG_DONTWAIT);
if (bytes_received<0)
{
closesocket(sock);
rt_kprintf("\nreceived error-1, close the socket.\r\n");
rt_free(tcp_recv_data);
break;
}
else if(bytes_received==0)
{
closesocket(sock);
rt_kprintf("\nreceived error0, close the socket.\r\n");
rt_free(tcp_recv_data);
break;
}
...
}
}
msh终端是这样提示的
\ | /
- RT - Thread Operating System
/ | \ 4.0.3 build Jun 26 2021
2006 - 2020 Copyright by rt-thread team
lwIP-2.0.2 initialized!
[I/sal.skt] Socket Abstraction Layer initialize success.
msh />ifconfig
network interface device: e0 (Default)
MTU: 1500
MAC: 00 80 e1 05 37 2b
FLAGS: UP LINK_UP INTERNET_DOWN DHCP_ENABLE ETHARP BROADCAST IGMP
ip address: 0.0.0.0
gw address: 0.0.0.0
net mask : 0.0.0.0
dns server #0: 192.168.1.1
dns server #1: 0.0.0.0
msh />can2tcp
socke is created.
Connect successful
tcp_thread: recv data = aabbccdd
tcp_thread: recv data = aabbccdd
tcp_thread: recv data = aabbccdd
ID:1 0 0 0 0 0 0 0 0
can_rx_thread: send message -
ID:1 0 0 0 0 0 0 0 0
can_rx_thread: send message -
ID:1 0 0 0 0 0 0 0 0
can_rx_thread: send message -
ID:1 0 0 0 0 0 0 0 0
can_rx_thread: send message -
received error0, close the socket.
socke is created.
Connect successful
tcp_thread: recv data = aabbccdd
(rt_object_get_type(&mb->parent.parent) == RT_Object_Class_MailBox) assertion failed at function:rt_mb_send_wait, line number:
离线
我的程序。断开tcpserver后再打开,tcp第一次接收没问题,第二次接收就报错了。
#include <rtthread.h>
#include "rtdevice.h"
#include <lwip/api.h>
#include <lwip/sockets.h>
#include <lwip/netdb.h>
// #include <sys/select.h>
// #include <sys/socket.h>
// #include <netdb.h>
#include <string.h>
#include <finsh.h>
#define BUFSZ 1024
#define CAN_DEV_NAME "can1"
static int sock;
ALIGN(RT_ALIGN_SIZE)
static char thread1_stack[1024];
static struct rt_thread thread1;
static struct rt_semaphore rx_sem;
static rt_device_t can_dev;
static rt_err_t can_rx_call(rt_device_t dev, rt_size_t size)
{
rt_sem_release(&rx_sem);
return RT_EOK;
}
static void can_rx_thread(void *parameter)
{
int i;
rt_err_t res;
struct rt_can_msg rxmsg={0};
char tcp_send_data[]="hahaha\r\n";
rt_device_set_rx_indicate(can_dev, can_rx_call);
while(1)
{
rt_sem_take(&rx_sem,RT_WAITING_FOREVER);
rt_device_read(can_dev,0,&rxmsg,sizeof(rxmsg));
rt_kprintf("ID:%x",rxmsg.id);
for(i=0;i<8;i++)
{
rt_kprintf("%2x",rxmsg.data[i]);
}
rt_kprintf("\n");
res = send(sock, rxmsg.data, rxmsg.len, 0);
rt_kprintf("can_rx_thread: send message - %c\n", rxmsg.data[0]);
/* 延时 50ms */
rt_thread_mdelay(50);
}
}
/* 线程 1 入口函数 */
void can2tcp(int argc,char *argv[])
{
int i;
struct rt_can_msg can_msg = {0};
rt_err_t res;
rt_size_t can_size;
rt_thread_t thread_can_rx;
char can_name[RT_NAME_MAX];
char *tcp_recv_data;
struct hostent *host;
// int sock, bytes_received;
int bytes_received;
struct sockaddr_in server_addr;
const char *url;
int port;
int maxfdp1;
fd_set readset;
struct timeval tim;
uint8_t can_recv_data[8];
char sendData[]="hahahaha";
url = "192.168.1.143";
port = 5000;
/*-------------初始化tcp client---------------------*/
host = gethostbyname(url);
tcp_recv_data = rt_malloc(BUFSZ);
if(tcp_recv_data==RT_NULL)
{
rt_kprintf("No memory\n");
return;
}
// if((sock=socket(AF_INET,SOCK_STREAM,0))==-1)
// {
// rt_kprintf("Socket error\n");
// rt_free(tcp_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(sock,(struct sockaddr*)&server_addr,sizeof(struct sockaddr))==-1)
// {
// rt_kprintf("Connect fail!\n");
// closesocket(sock);
// rt_free(tcp_recv_data);
// return;
// }
// else
// {
// rt_kprintf("Connect successful\n");
// }
/*-------------打开can线程----------------*/
rt_strncpy(can_name,CAN_DEV_NAME,RT_NAME_MAX);
can_dev = rt_device_find(can_name);
if(!can_dev)
{
rt_kprintf("find %s failed!\n",can_name);
return;
}
rt_sem_init(&rx_sem,"rx_sem",0,RT_IPC_FLAG_FIFO);
can_msg.id=0x78;
can_msg.ide=RT_CAN_STDID;
can_msg.rtr=RT_CAN_DTR;
can_msg.len=8;
res=rt_device_open(can_dev,RT_DEVICE_FLAG_INT_TX|RT_DEVICE_FLAG_INT_RX);
RT_ASSERT(res==RT_EOK);
thread_can_rx=rt_thread_create("can_rx",can_rx_thread,RT_NULL,1024,25,10);
if(thread_can_rx!=RT_NULL)
{
rt_thread_startup(thread_can_rx);
}
else
{
rt_kprintf("creat can_rx thread failed!\n");
}
/*-------------tcp client主循环-------------------*/
uint8_t buf[8] = {0,0,0,0,0,0,0,0};
rt_uint8_t cnt = 0;
maxfdp1 = sock+1;
tim.tv_sec=0;
tim.tv_usec=100;
while(1)
{
sock=-1;
while(sock==-1)
{
sock=socket(AF_INET,SOCK_STREAM,0);
int mode = 0; //阻塞模式
ioctlsocket(sock, FIONBIO, &mode);
}
rt_kprintf("socket is created.\r\n");
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));
// i=-1;
// while(i==-1)
// {
// i=connect(sock,(struct sockaddr*)&server_addr,sizeof(struct sockaddr));
// }
// rt_kprintf("tcp is connected.\r\n");
if (connect(sock, (struct sockaddr*)&server_addr, sizeof(struct sockaddr))==-1)
{
rt_kprintf("Connect fail!\n");
closesocket(sock);
// rt_free(tcp_recv_data);
// return;
continue;
}
else
{
rt_kprintf("Connect successful\n");
}
while (1)
{
FD_ZERO(&readset);
FD_SET(sock,&readset);
i=select(maxfdp1,&readset,0,0,&tim);
if(i==0)
continue;
if(FD_ISSET(sock,&readset))
{
bytes_received=recv(sock,tcp_recv_data,BUFSZ-1,MSG_DONTWAIT);
if (bytes_received<0)
{
closesocket(sock);
rt_kprintf("\nreceived error-1, close the socket.\r\n");
rt_free(tcp_recv_data);
break;
}
else if(bytes_received==0)
{
closesocket(sock);
rt_kprintf("\nreceived error0, close the socket.\r\n");
rt_free(tcp_recv_data);
break;
}
tcp_recv_data[bytes_received]='\0';
{
// rt_kprintf("thread1: recv msg from msg queue, the content:%c\n", tcp_recv_data[0]);
rt_kprintf("tcp_thread: recv data = %s\n", tcp_recv_data);
can_msg.data[0]=tcp_recv_data[0];
can_msg.data[1]=tcp_recv_data[1];
can_msg.data[2]=tcp_recv_data[2];
can_msg.data[3]=tcp_recv_data[3];
can_msg.data[4]=tcp_recv_data[4];
can_msg.data[5]=tcp_recv_data[5];
can_msg.data[6]=tcp_recv_data[6];
can_msg.data[7]=tcp_recv_data[7];
can_size=rt_device_write(can_dev,0,&can_msg,sizeof(can_msg));
}
}
/* 延时 50ms */
rt_thread_mdelay(50);
}
}
}
/*--------------------------------------*/
/* 导出到 msh 命令列表中 */
MSH_CMD_EXPORT(can2tcp, can to tcp client sample);
can2tcp.zip
现在是不是下载任何文件都要积分了?
还好,我的这层回复里,引用的就是整个.c文件了,没必要单独下载附件。
最近编辑记录 Gentlepig (2021-07-03 09:23:18)
离线
群里好心的朋友帮我修改的程序,可以实现tcp重连。但是每次上电后一开始tcp不能接收,只有tcp断开重连一次后才正常。
#include <rtthread.h>
#include "rtdevice.h"
#include <lwip/api.h>
#include <lwip/sockets.h>
#include <lwip/netdb.h>
// #include <sys/select.h>
// #include <sys/socket.h>
// #include <netdb.h>
#include <string.h>
#include <finsh.h>
#define CAN_DEV_NAME "can1"
/* 邮箱控制块 */
static struct rt_mailbox can_mb;
/* 用于放邮件的内存池 */
static char can_mb_pool[256] = {0};
/* 消息队列控制块 */
static struct rt_messagequeue tcp2can_mq;
/* 消息队列中用到的放置消息的内存池 */
static rt_uint8_t tcp2can_msg_pool[2048];
char can_name[RT_NAME_MAX];
static rt_device_t can_dev;
int can_msg_send(uint8_t *data,uint16_t len)
{
rt_uint32_t mailbox_rx_data = 0x20000000;
uint8_t send_len = 0;
rt_err_t res;
while(len > 0 )
{
if(len > 8)
{
send_len = 8;
}else
{
send_len = len;
}
res = rt_mq_send(&tcp2can_mq, data, send_len);//数据存入 tcp2can_mq
rt_mb_send(&can_mb,mailbox_rx_data); //通知线程处理
data += send_len;
len -= send_len;
}
}
static rt_err_t can_rx_call(rt_device_t dev, rt_size_t size)
{
rt_uint32_t mailbox_rx_data = 0x10000000;
rt_mb_send(&can_mb,mailbox_rx_data); //通知线程处理
return RT_EOK;
}
extern int tcp_msg_send(uint8_t *data,uint16_t len);
static void can_thread(void *parameter)
{
rt_err_t result;
/* 初始化一个 mailbox */
result = rt_mb_init(&can_mb,
"can_mb", /* 名称是 can_mb */
&can_mb_pool[0], /* 邮箱用到的内存池是 mb_pool */
sizeof(can_mb_pool) / 4, /* 邮箱中的邮件数目,因为一封邮件占 4 字节 */
RT_IPC_FLAG_FIFO); /* 采用 FIFO 方式进行线程等待 */
/* 初始化消息队列 */
result = rt_mq_init(&tcp2can_mq,
"tcp2can_mq",
&tcp2can_msg_pool[0], /* 内存池指向 msg_pool */
8, /* 每个消息的大小是 8 字节 */
sizeof(tcp2can_msg_pool), /* 内存池的大小是 msg_pool 的大小 */
RT_IPC_FLAG_FIFO); /* 如果有多个线程等待,按照先来先得到的方法分配消息 */
/*-------------打开can线程----------------*/
rt_strncpy(can_name,CAN_DEV_NAME,RT_NAME_MAX);
can_dev = rt_device_find(can_name);
if(!can_dev)
{
rt_kprintf("find %s failed!\n",can_name);
return;
}
rt_thread_mdelay(3000);
rt_device_open(can_dev, RT_DEVICE_FLAG_INT_TX|RT_DEVICE_FLAG_INT_RX);
rt_device_set_rx_indicate(can_dev, can_rx_call);
int rc = 0;
int size = 0;
struct rt_can_msg can_rx_msg = {0};
struct rt_can_msg can_tx_msg = {0};
rt_int8_t i;
rt_uint32_t mailbox_rx_data = 0;
while(1)
{
/* 从邮箱中收取邮件 */
if (rt_mb_recv(&can_mb, (rt_uint32_t *)&mailbox_rx_data, RT_WAITING_FOREVER) == RT_EOK)
{
if(mailbox_rx_data == 0x10000000)//表示CAN接受
{
can_rx_msg.hdr = -1; /* hdr 值为 - 1,表示直接从 uselist 链表读取数据 */
rc = rt_device_read(can_dev,0,&can_rx_msg,sizeof(can_rx_msg));
if(rc > 0)
{
rt_kprintf("ID:%x",can_rx_msg.id);
for(i=0;i<8;i++)
{
rt_kprintf("%2x",can_rx_msg.data[i]);
}
rt_kprintf("\n");
tcp_msg_send(can_rx_msg.data,8); //发送给tcp
}
}
if(mailbox_rx_data == 0x20000000)//表示CAN发送
{
/* 从消息队列中接收消息 */
if (rt_mq_recv(&tcp2can_mq, (void*)can_tx_msg.data, 8, 0) == RT_EOK) //不堵塞接收
{
can_tx_msg.id = 0x78; /* ID 为 0x78 */
can_tx_msg.ide = RT_CAN_STDID; /* 标准格式 */
can_tx_msg.rtr = RT_CAN_DTR; /* 数据帧 */
can_tx_msg.len = 8; /* 数据长度为 8 */
/* 发送一帧 CAN 数据 */
size = rt_device_write(can_dev, 0, &can_tx_msg, sizeof(can_tx_msg));
if (size == 0)
{
rt_kprintf("can dev write data failed!\n");
}
}
}
}
}
}
#define HOST "192.168.1.143"
#define PORT "5000"
static int socketfd = -1;
int tcp_msg_send(uint8_t *data,uint16_t len)
{
if(socketfd > 0)
{
send(socketfd, data, len, 0);
}
}
int tcp_connect1(const char *host, const char *port)
{
int socket_fd = -1;
struct addrinfo hints, *addr_list, *cur;
/* Do name resolution with both IPv6 and IPv4 */
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
//hints.ai_protocol = PROTOCOL_TLS;
rt_err_t ret;
ret = getaddrinfo(host, port, &hints, &addr_list);
if (ret != 0)
{
rt_kprintf("getaddrinfo fail [%d]\n",ret);
return ret;
}
for (cur = addr_list; cur != NULL; cur = cur->ai_next)
{
socket_fd = socket(cur->ai_family,SOCK_STREAM, IPPROTO_TCP);
if (socket_fd < 0)
{
continue;
}
int mode = 0; //阻塞模式
ioctlsocket(socket_fd, FIONBIO, &mode);
ret = connect(socket_fd, cur->ai_addr, cur->ai_addrlen);
rt_kprintf("socket:%d ret:%d\n",socket_fd,ret);
if (ret == 0)
{
break;//连接成功
}
closesocket(socket_fd);
}
freeaddrinfo(addr_list);
return socket_fd;
}
static void tcp_rx_thread(void *parameter)
{
int maxfdp1;
fd_set readset;
struct timeval timeout;
int rc = 0;
uint8_t *tcp_recv_data = rt_malloc(1024);
/*-------------tcp client主循环-------------------*/
while (1)
{
socketfd = tcp_connect1(HOST,PORT); //tcp
while(socketfd > 0)
{
FD_ZERO(&readset);
FD_SET(socketfd,&readset);
maxfdp1 = socketfd+1;
timeout.tv_sec=1;
timeout.tv_usec=1000;
rc = select(maxfdp1,&readset,0,0,&timeout);
if(rc==0)
continue;
if(FD_ISSET(socketfd,&readset))
{
rt_kprintf("开始接受\r\n");
rc = recv(socketfd,tcp_recv_data,1024,MSG_DONTWAIT);
if(rc <= 0)
{
rt_kprintf("接受出错\r\n");
if(!(errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN))
{
rt_kprintf("socket recv err :%d\n",rc);
closesocket(socketfd);
socketfd = -1;
break;
}else
{
rt_kprintf("socket recv timeout :%d\n",rc);
}
}else
{
rt_kprintf("socket recv :%d\n",rc);
// can_msg_send(tcp_recv_data,rc);
}
}
}
rt_thread_mdelay(5000); //断线5s后重连
}
rt_free(tcp_recv_data);
}
/* 线程 1 入口函数 */
void can2tcp(int argc,char *argv[])
{
// rt_thread_t can_tid;
// can_tid = rt_thread_create("can_task",can_thread,RT_NULL,1024,25,10);
// if(can_tid!=RT_NULL)
// {
// rt_thread_startup(can_tid);
// }
// else
// {
// rt_kprintf("create can_task thread failed!\n");
// }
rt_thread_t tcp_tid;
tcp_tid = rt_thread_create("tcp_task",tcp_rx_thread,RT_NULL,1024,25,10);
if(tcp_tid!=RT_NULL)
{
rt_thread_startup(tcp_tid);
}
else
{
rt_kprintf("create tcp_task thread failed!\n");
}
}
/*--------------------------------------*/
/* 导出到 msh 命令列表中 */
MSH_CMD_EXPORT(can2tcp, can to tcp client select sample);
希望大家帮分析下为什么这位朋友的程序可以实现tcp重连,而我的程序不能?
最近编辑记录 Gentlepig (2021-07-03 09:22:03)
离线
@Gentlepig
是的,还望理解,不过只要正常发过帖子的朋友基本都不会受到影响。
来都来了,帮我分析下啊。
离线
Gentlepig 说:(rt_object_get_type(&mb->parent.parent) == RT_Object_Class_MailBox) assertion failed
这个是比较明确的内存写穿,进入仿真调试,给这个变量下个写断点,应该一下就能把肇事者找出来。
不知道该监控哪个变量,看这个提示mb应该是mailbox,但我没用mailbox,可能lwip接收自动用了mailbox吧。
离线
我的程序中,接收出错,就释放了tcp_recv_data。
rt_free(tcp_recv_data);
不应该这么早释放。屏蔽这句就没那个错误了。
离线
大部分问题解决了。
群里朋友帮我改的那个程序,有个while(socketfd>0)判断,实际上socketfd第一次创建往往是0,也是创建成功的。改成while(socketfd>=0)后,基本没问题了。
我的程序修改那个变量释放的位置后,tcp断线重连没问题了。
但是又遇到这么个问题,之前是在msh里手动启动程序的,正常。现在设为启动后自动运行程序,则一直connect失败,然后按我的程序逻辑,就会新建socket然后再次尝试connect,但会一直连接失败。在tcp线程创建前加了个10秒延迟,正常。改成5秒延迟,则还是不行。
离线
应该找到问题了,host = gethostbyname(url)这句之前至少在程序里执行了一次。我改到重连的循环里后,就可以了。
感觉是执行connect()函数时,将host变量指向的内容修改了。
离线
现在测试can和tcp互相转发,在pc端手动点击can软件和tcp server端,能正常收发。
pc端通过can软件向板子自动发送几百条信息,间隔时间设为几微秒,结果tcp server端收到的倒是正确,就是慢...
网上搜了下,将socket设为tcp_nodelay,但还是没效果。
const char chOpt=1;
int nErr=setsockopt( m_socket, IPPROTO_TCP, TCP_NODELAY, &chOpt, sizeof(char));
离线
之前测试,tcp发送慢的原因找到了,是can线程里加了个延时,结果can接收慢了。
现在将can线程里的延时去掉,再次尝试,发送数据少时没事,pc端通过can每隔2ms发送100万条指令完成后,tcp server接收要晚3分钟左右才收完。
网上搜,一般说是tcp_write()后调用tcp_output()可以立即发送。我追踪lwip_send,发现lwip_netconn_do_writemore(struct netconn *conn WRITE_DELAYED_PARAM)
函数里,执行了tcp_write()后,是立即调用了tcp_output()的。
那么,只能有这样的延迟了吗?
最近编辑记录 Gentlepig (2021-07-13 11:46:41)
离线
if (connect(sock,(struct sockaddr*)&server_addr,sizeof(struct sockaddr))==-1)
{
rt_kprintf("Connect fail!\n");
closesocket(sock);
rt_free(tcp_recv_data);
return;
}
离线
if (connect(sock,(struct sockaddr*)&server_addr,sizeof(struct sockaddr))==-1)
{
rt_kprintf("Connect fail!\n");
closesocket(sock);
rt_free(tcp_recv_data);
return;
}
我一开始是这么写的,后来把rt_free(tcp_recv_data);放到最外层了。
现在的问题是can接收大量信息然后通过tcp发出去时,有延迟。
想了想,延迟可能是can接收造成的。
离线
延迟问题找到了,can接收线程里有打印语句,将打印语句屏蔽掉,就同步了。
但不明白为什么打印语句会造成延迟。
离线