【已解决】CME-M7芯片RTT+LWIP求助[遗留一个8小时固定死机问题]

发布于 2015-04-03 12:17:56    浏览:7267
我是一个撸代码的,本职是进行上层软件开发,最近使用RTT+LWIP搭建一个通过FIFO串口、TCP音频网络传输系统。
使用了以下几个方案:
1、建立1个socket,通过2个独立线程对这个socket分别进行发、收。发送实时性好,不定时死机(运行灯闪烁,网络芯片没有挂,推测是RTT挂了),没有任何错误信息打印。
eg:
int sock;
tid_audio = rt_thread_create("audio_recv",
init_tcp_recv,
&sock,
2048,
THREAD_PRIORITY+1,
THREAD_TIME);
tid_audio = rt_thread_create("audio_send",
init_tcp_send,
&sock,
2048,
THREAD_PRIORITY+1,
THREAD_TIME);


问题:进行了2种单线程收,单线程发的测试,没有死机现象。那么我可以认为RTT对多线程操作单个socket读写是有缺陷的?

2、建立2个socket,通过2个独立线程分别进行发、收。暂时没有死机情况,实时性差,音频有卡顿现象。修改建立线程时的优先级和时间,略有改善。
问题:由问题1我进行了程序优化,避免了多线程操作同一个socket的情况,但是音频实时性显著下降(声音有明显的顿感,并不是收发不同步),因为我不了解操作系统对线程的调度方式,从1和2体现的问题来看,我个人已经一头雾水了。


不知道大家有没有遇到过同类的问题?个人觉得RTT是一个不错的操作系统,但是有一些细节上的东西,并没有文档能说明的很详细?

查看更多

27 个回答
aozima
aozima 2015-04-03
拒绝白嫖,拒绝键盘侠!
收发音频不需要buffer吗?
toasun
toasun 2015-04-03
This guy hasn't written anything yet
收发音频不需要buffer吗?

下面这个程序是问题2里的,我个人感觉能用的……其他程序也类似。

#define THREAD_TIME 1
#define THREAD_PRIORITY (RT_THREAD_PRIORITY_MAX - 2)

	tid_audio = rt_thread_create("audio_int",
init_tcp_recv,
RT_NULL,
2048,
THREAD_PRIORITY+1,
THREAD_TIME);

if (tid_audio != RT_NULL)
rt_thread_startup(tid_audio);

//tcp连接线程
static void init_tcp_send(void* parameter)
{
struct sockaddr_in local_addr,server_addr;

int sock_audio_send = -1;
int val = SO_KEEPALIVE;
int keepIdle = 2; // 如该连接在2秒内没有任何数据往来,则进行探测
int keepInterval = 1; // 探测时发包的时间间隔为1 秒
int keepCount = 3;// 探测尝试的次数.如果第1次探测包就收到响应了,则后2次的不再发.

//建立开关socket
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port_audio);
server_addr.sin_addr.s_addr = inet_addr(server_ip); //使用INADDR_ANY 指示任意地址
rt_memset(&(server_addr.sin_zero),0,sizeof(server_addr.sin_zero));

//接收客户端
while(1)
{
//通道没有全部退出不接收客户端
if (lock_send_audio == 1)
{
rt_thread_delay(DELAY_TIME);
continue;
}
else if (lock_send_audio == 0)
{
#ifdef DBG
rt_kprintf("set up send!
");
#endif
//通道全部退出,释放已结束的socket
if ( sock_audio_send!= -1)
{
#ifdef DBG
rt_kprintf("close sock_audio_send socket!
");
#endif
lwip_close(sock_audio_send);
sock_audio_send = -1;
}

//建立新socket
sock_audio_send = socket(AF_INET, SOCK_STREAM, 0);
if(sock_audio_send == -1)
{
rt_kprintf("sock_audio_send error
");
rt_thread_delay(DELAY_TIME);
continue;
}

//心跳帧

setsockopt(sock_audio_send, SOL_SOCKET, SO_KEEPALIVE, &val, 4);
setsockopt(sock_audio_send, IPPROTO_TCP, TCP_KEEPIDLE, (void *)&keepIdle, sizeof(keepIdle));
setsockopt(sock_audio_send, IPPROTO_TCP,TCP_KEEPINTVL, (void *)&keepInterval, sizeof(keepInterval));
setsockopt(sock_audio_send,IPPROTO_TCP, TCP_KEEPCNT, (void *)&keepCount, sizeof(keepCount));

//打开开关量发送线程
while (1)
{
if (connect(sock_audio_send, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1)
{
rt_kprintf("connect sock_audio_send faild!
");
rt_thread_delay(DELAY_TIME);
continue;
}
break;
}

rt_kprintf("sock_audio_send: %d!
",sock_audio_send);
lock_send_audio = 1;
//hl_thread_start(&sock_audio_send,SEND_AUDIO);

send_audio_thread(&sock_audio_send);

}
}
}


//音频发送线程
static void send_audio_thread(void* parameter)
{
int sock = *(int *)parameter;
int i;
int ret;
rt_err_t result;
uint32_t *buf_audio;
uint8_t buf[(BUFF_AUDIO_LEN+4)*4];
uint8_t signal;
lock_send_audio = 1;

buf_audio = (uint32_t *)buf;
#ifdef DBG
rt_kprintf("send_audio_thread enter: %d
",sock);
#endif

buf_audio[0] = 0x01eeeeee;
buf_audio[1] = 0x00000004;//保留2开关量1数量1
buf_audio[2] = 0x00000000;//时间2保留2
buf_audio[BUFF_AUDIO_LEN+3] = 0xdddddd00;
while(1)
{
buf_audio[2] += (0x0001<<16);//时间累加
signal = GPIO_getBits(KGL_IN_0)
+ GPIO_getBits(KGL_IN_1)*2
+ GPIO_getBits(KGL_IN_2)*4
+ GPIO_getBits(KGL_IN_3)*8;

buf[8] = signal;


//连接服务器
fp0_int_enable();
result=rt_sem_take(&sem_fifo_a,RT_WAITING_FOREVER);
if(result==RT_EOK)
{
for(i = 3;i < BUFF_AUDIO_LEN+3;i+=2)
{
buf_audio
    = FIFO_AHB_a->fifo_data;
    buf_audio[i+1] = FIFO_AHB_c->fifo_data;
    //test
    //FIFO_AHB_b->fifo_data = fifo_ram_a
      ;
      }

      ret = send(sock,(uint8_t*)buf,(BUFF_AUDIO_LEN+4)*4,0);
      if(ret < 0)
      {
      rt_kprintf("send_audio_thread lost connection!
      ");
      break;
      }
      }
      fp0_int_enable();//开FIFO中断
      }

      #ifdef DBG
      rt_kprintf("send_audio_thread.....leave.
      ");
      #endif
      lock_send_audio = 0;
      };
bernard
bernard 2015-04-03
This guy hasn't written anything yet
"通过2个独立线程对这个socket分别进行发、收。" 这个就不对了,lwIP不支持多线程操作一个socket。
toasun
toasun 2015-04-03
This guy hasn't written anything yet
"通过2个独立线程对这个socket分别进行发、收。" 这个就不对了,lwIP不支持多线程操作一个socket。


是的,所以我在第二种情况也说了我的问题……网络是没有问题了,感觉线程的执行效率出问题了?
bernard
bernard 2015-04-03
This guy hasn't written anything yet
可以用select来操作,不是类似你这样去使用。
toasun
toasun 2015-04-03
This guy hasn't written anything yet
可以用select来操作,不是类似你这样去使用。

好的,我正想尝试一下。
toasun
toasun 2015-04-07
This guy hasn't written anything yet
可以用select来操作,不是类似你这样去使用。

现在非阻塞操作基本完成了,问题的原因有几个:
1、接收的时候
recv(sock,buf_recv,BUFF_MAX_RECV,MSG_DONTWAIT);

如果我实际发送的数据长度为400(没有强制不拼包),BUFF_MAX_RECV如果没有足够大,在没有强制不拼包的时候会出错,具体原因我也没有再仔细研究,这里会让系统直接跑飞。不知道有教主能给我解释一下吗?
2、处理异常断线的时候,我采用下面的方法
ret = send(sock,buf_send,(BUFF_AUDIO_LEN+4)*4,MSG_DONTWAIT);
if(ret != (BUFF_AUDIO_LEN+4)*4)//发送数据长度错误
{
#ifdef DBG
rt_kprintf("send_audio: send len %d
",ret);
#endif

fail_count ++;
//错误100次认为断开连接
if (fail_count > 100)
{
#ifdef DBG
rt_kprintf("send_audio: send %d times
",fail_count);
#endif
lock_audio_recv = 0;
}
}
else
{
fail_count = 0;
}


然后调用lwip_close()函数,但是我发现每次成功断开,建立新的socket重连的时候产生了如下错误(警告?),但是仍然成功建立了连接并可以成功收发了:
memp_malloc: out of memory in pool TCP_SEG
我看了半天,没有具体看到这里是socket建立时申请套接字资源的内存错误还是程序中申请接收发送buffer的错误?
好像并不是个错误,是我打开了lwip的dbg信息~

好了,接下来进行压力测试看看~
amsl
amsl 2015-04-08
This guy hasn't written anything yet
判断链接是否断了,是否使用心跳机制较好,就像人的心跳停了,这个人可能死了。断开链接后还要回收所有资源。
小ARM菜菜
小ARM菜菜 2015-04-13
This guy hasn't written anything yet
这个多线程操作一个socket并非一定使用selcet.我就讨厌这个风格。后来采取了世纪华联的建议。开启TCPIP的LOCK。目前测试比较OK。这个收发主要是阻塞在一个信号量上,加锁后相当于互斥了。就不死了。
不是RTT死掉。可能是LWIP挂了吧,再查查
小ARM菜菜
小ARM菜菜 2015-04-13
This guy hasn't written anything yet
断线检测这个最好用keepalive我认为的

撰写答案

请登录后再发布答案,点击登录
关注者
0
被浏览
7.3k

发布
问题

分享
好友

手机
浏览

扫码手机浏览