关于WiFi信号的CSI采样率过高导致接收端收数停止问题

monitor模式和AP模式下,一段时间都会停止收数

 

原因:

1、Log_to_file退出并显示错误:“recv:no buffer space available”。由于Log_to_file无法调用了所以停止计数

2、 System call slows down the process which can fill the memory(由于内存原因,系统停止进程)

3、当socket 进行TCP 连接的时候(也就是调用connect 时),一旦网络不通,或者是ip 地址无效,就可能使整个线程阻塞。

解决方法:

1、增加了进程log_to_file的调度优先级

增加了进程log_to_file的调度优先级,让其不间断地连续运行

sudo renice -n -20 -p pid(log_to_file对应的pid)

sudo renice -n -20 -p pid  /……/log_to_file tmp.dat

尝试其它指令:

Linux系统进程的优先级取值:-20 到 19,数越大优先级越低。

命令1:sudo nice -20  /……/log_to_file tmp.dat,还是会出收数停止的情况

命令2:sudo nice --20 /……/log_to_file tmp.dat,还是会出现停止收数的情况

注:查看log_to_file进程的PID方法:

1、让发端和收端都正常运行,收端运行log_to_file不停收数

2、在收端打开一个新的终端,输入下面的指令

pgrep -l XXX,这里第三个参数修改为log_to_file

这时终端中会显示出进程log_to_file的进程号为2357

重新收数,再次查看log_to_file的进程号,此时变为2755

重启主从机运行log_to_file后查看进程号显示为2396

3、运行前log_to_file没有对应的进程号,运行后才有进程号,只能运行后再修改优先级

查看内存及cpu使用情况的命令:top

同样在新的终端下top,只要一直在收数就可以看到 log_to_file对应的一行信息,当收数停止后,这一行信息也会消失

设置优先级我这里不奏效

2、内存

内存的使用情况怎么去查看?

在新终端窗口直接输入 free -m 命令,可使用的mem大概有60M,停止收数时还有大量的可用内存空间

内存和no buffer区别?

3、修改发包长度

从默认值100修改为10,不起作用

3、修改log_to_file.c文件,重编译运行

1、buf[4096]修改为buf[8192],还是出现停止收数的情况

2、MAX_PAYLOSAD修改为4096

3、log_to_file.c中的while(1)循环收数

在while(1)外加了一句printf,停止收数的时候,没有打印任何信息,说明没有退出while(1)循环

停止收数后,隔一段时间后终端会继续打印,count会接着之前的数继续往后打印,不会中断,并且记录数据的文件大小会继续增加(停止的时候,文件大小才自动增加)

	while (1)
	{
		/* Receive from socket with infinite timeout */
		ret = recv(sock_fd, buf, sizeof(buf), 0);
		if (ret == -1)
			exit_program_err(-1, "recv");
		/* Pull out the message portion and print some stats */
		cmsg = NLMSG_DATA(buf);
		if (count % SLOW_MSG_CNT == 0)
			printf("received %d bytes: id: %d val: %d seq: %d clen: %d\n", cmsg->len, cmsg->id.idx, cmsg->id.val, cmsg->seq, cmsg->len);
		/* Log the data to file */
		l = (unsigned short) cmsg->len;
		l2 = htons(l);
		fwrite(&l2, 1, sizeof(unsigned short), out);
		ret = fwrite(cmsg->data, 1, l, out);
		if (count % 100 == 0)
			printf("wrote %d bytes [msgcnt=%u]\n", ret, count);
		++count;
		if (ret != l)
			exit_program_err(1, "fwrite");
	}

①在exit_program_err()和exit_program()子函数 中加入了fprint语句,永远都不会打印出来,程序到底停在那里?

②        fwrite(&l2, 1, sizeof(unsigned short), out);此句含义?
        ret = fwrite(cmsg->data, 1, l, out);向文件写入数据

补充:修改log_to_file.c文件后可以直接运行log_to_file生成带年月日的文件,没必要每次发指令都写文件名

4、在log_to_file.c中修改log_to_file的进程优先级

5、通过PS指令发现进程停止

ps -s -p 进程pid查看log_to_file的状态,发现运行时为s+,停止计数是仍为s+(出现过S<+)

重新唤醒进程

6、修改socket

recv函数:如果recv函数在等待协议接收数据时网络断开了,那么调用recv的进程会接收到一个SIGPIPE信号,进程对该信号的默认处理是进程终止。(停止计数后出现断网的解释https://blog.csdn.net/a4150902/article/details/7399578

设置为非阻塞:https://blog.csdn.net/zwg739424406/article/details/80006234(阻塞和非阻塞的理解)

先理一下阻塞和非阻塞的概念:

  • 阻塞就是让当前调用线程一直处于停止等待当中,挂起的状态,线程函数会被卡住。
  • 非阻塞则是不管运行结果如何,都会继续往下执行(往往都要处理很多返回结果),线程函数里一般都是一个循环,不停的轮询。

再理一下发送接收函数:

  • send/sendto函数,只是把应用层的数据拷贝到内核发送缓冲区,并不保证数据一定会被发送到对端,真正执行发送及什么时候发送是由系统(协议栈)决定的,所以send/sendto函数返回成功,只能说明拷贝成功了,如果在还未发送之前网络断开,则发送失败。
  • recv/recvform函数,,将内核接收缓冲区的数据拷贝到应用层的buffer中,真正执行接收数据也是由系统层决定的。

套接字默认是阻塞状态,因此发送及接收也是阻塞状态,所以调用不会立即返回,而是进入睡眠等待操作完成。

1.在阻塞模式下,recv/recvfrom会一直阻塞到接收缓冲区里有一个字节或一个完整的UDP数据报为止,然后再返回

  • recv的原型:int recv(SOCKET sd, char *buffer, int len, int 
    flag),注意到系统并不会等待buffer被填满了再返回,而是一旦有数据被接收到,就立刻返回,因此不要期望实际收到的数据长度就等于len。

2.在非阻塞模式下,recv/recvfrom会立即返回

  • 如果接收缓冲区,有至少一个字节或UDP数据报,则会返回接收到的数据大小,如果没有,则返回错误EWOULDBLOCK
SOCKET s; 
unsigned long ul = 1; 
int  ret; 
s = socket(AF_INET, SOCK_STREAM, 0); 
ret = ioctlsocket(s, FIONRIO, (unsigned long)&ul); 
if(SOCKET_ERROR==ret) 
{ 
  //未能将套接字设置为非阻塞模式 
} 

①FIONBIO编译不过:加上头文件#include <asm/ioctls.h>

②nRet = ioctlsocket(s, FIONBIO, (unsigned long*)&ul);  设置套接字非阻塞模式,函数ioctlsocket不存在?

修改方法:WSAAsyncselect()和WSAEventselect()函数

参数区别:https://blog.csdn.net/bigjacky/article/details/51622185

7、修改recv函数

ssize_t recvfrom(int sockfd,void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen)

windows版本:

int recvfrom(IN SOCKET s, OUT char FAR * buf, IN int len, IN int flags, OUT struct sockaddr FAR * from,IN OUT int FAR * fromlen)

着重强调参数:

       sockfd:接收端套接字描述

       buf:用于接收数据的应用缓冲区地址

       len:指名缓冲区大小

       flags:通常为0

       src_addr:数据来源端的地址

       addrlen:src_addr地址的长度

注意后两个参数是输出参数,其中addrlen既是输入又是输出参数,即值-结果参数,需要在调用时,指明src_addr的长度。另外,如果不关心数据发送端的地址,可以将后两者均设置为NULL

GitHub上有人解决了,真的不知道你是咋解决的....

关于缓存超过的解决方法:https://github.com/dhalperi/linux-80211n-csitool-supplementary/issues?q=


终止进程

sudo kill 3545(进程PID)

 

猜你喜欢

转载自blog.csdn.net/qq_20386411/article/details/86074832