IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> udp接收队列以及多次初始化的测试 -> 正文阅读

[网络协议]udp接收队列以及多次初始化的测试

这一段时间基于udp的数据重放的过程中图像总是卡死,发现recv Q满了,但是不知道具体原因是啥,这里就先进行了udp的接收测试。

一. 正常测试?

  1. send端每次发送1k,发送频率50hz;

  2. recv端每次接受1k,接受频率5hz;
  3. watch -n 1 netstat -anu 显示recv进程对应8888端口的recv Q在207000到162000之间波动,不会卡死。recv Q 的上限是207000左右。通过分析结果可以发现,当recv q满了之后,recv从队列里面拿出1k后,就会从接收发送端的1k进入队列,而是recv持续从队列里面拿数据,直到recv Q 降到162000左右,也就是队列占用率达到80%之后,才会接受send端发过来的数据。

二. 当recv端cnt==800时,执行socket重新初始化

?if(cnt == 800)

?????? {

?????? ???serfd=socket(AF_INET,SOCK_DGRAM,0);

?????????? printf("serfd = %d\n",serfd);

????????? // ret=bind(serfd,(struct sockaddr *)&seraddr,sizeof(seraddr));

?????? }

  1. socket初始化

? 无论是否执行bind操作,接收端都会卡住,接收队列都会满。同时/proc/pid/fd下面会新增一个socket文件,对应的fd为4。如果执行bind,则会返回绑定失败,端口被占用。

原因:经过上述的if语句后,serfd已经变成了4,对应的是一个新的socket文件,也就是说recv端会有一个新的接收队列,只是没有数据发送到这个新的队列。send端发送的数据依旧发送到serfd=3对应的队列中,但该队列没有人去读取了,造成recv Q 满了。表象就是卡住了,实际上是因为serfd=4对应的队列中没有数据。

? ? 2. socket初始化,同时将recvfrom函数中用到的serfd换成3这个常量

除了上述修改外,如果把recvfrom的serfd换成常量3,则虽然新生成4对应的fd,但是数据依然从3对应的队列中获取,也不会卡住,只是4对应队列中没有数据。

三. 当recv端cnt==800时,执行socket重新初始化

?if(cnt == 800)

?{

if(serfd>0) ret = close(serfd);

?????? printf("close serfd=%d\n",ret);

????????? serfd=socket(AF_INET,SOCK_DGRAM,0);

????????? sleep(1);

?????????? printf("serfd = %d\n",serfd);

????????? ret=bind(serfd,(struct sockaddr *)&seraddr,sizeof(seraddr));

?????? }

原因:

在cnt 为800时,原来的fd会关闭,/proc/pid/fd/下面的文件3也会被删掉;之后,重新执行 serfd=socket(AF_INET,SOCK_DGRAM,0);后,会申请可用的fd,而这个时候因为3号fd已经释放了,所以重新申请到的fd还是3。只不过此时对应的inode号发生了变更,从2130436变成了2132215。而8888端口对应的recv Q中的100多k的数据直接清0,然后开始新的积累数据。

测试程序

  1. send端:
#include <stdio.h>

#include <sys/socket.h>

#include <sys/types.h>

#include <string.h>

#include <unistd.h>

#include <netinet/in.h>

#include <arpa/inet.h>

#include <iostream>

//创建UDP实现服务器和客户端的通信

//创建socket连接

int main()

{

//创建socket连接

int clifd = 0;

int cnt = 0;

clifd = socket(AF_INET, SOCK_DGRAM, 0);

if (clifd < 0)

{

perror("socke failed");

return -1;

}

printf("socket success\n");

//向服务器发送消息

int tolen = 0;

int ret = 0;

char buf[1024] = {0};

while (1)

{



// std::cin.getline(buf,1023);

memset(buf, 0, 1024);

cnt++;

memcpy(buf, &cnt, sizeof(int));

struct sockaddr_in seraddr = {0};

seraddr.sin_family = AF_INET;

seraddr.sin_addr.s_addr = inet_addr("192.168.61.6");

seraddr.sin_port = htons(8888);

tolen = sizeof(seraddr);

ret = sendto(clifd, buf, strlen(buf), 0, (struct sockaddr *)&seraddr, tolen);

if (ret < 0)

{

perror("sendto failed");

close(clifd);

return -1;

}

printf("sendto success, %d\n", cnt);

//接收发送自服务器的消息

// ret=recvfrom(clifd,buf,sizeof(buf),0,NULL,NULL);

usleep(20000);

// if(ret<0)

// {

// perror("recvfrom failed");

// close(clifd);

// return -1;

// }

// printf("recvfrom success\n");

// printf("receive: %s\n",buf);

}

close(clifd);

return 0;

}

  1. recv端
#include <stdio.h>

#include <sys/socket.h>

#include <sys/types.h>

#include <string.h>

#include <unistd.h>

#include <netinet/in.h>

#include <arpa/inet.h>

#include <iostream>

//创建UDP实现服务器和客户端的通信

int main()

{

//创建socket连接

int serfd = 0;

int cnt = 0;

serfd = socket(AF_INET, SOCK_DGRAM, 0);

printf("serfd = %d\n", serfd);

if (serfd < 0)

{

perror("socke failed");

return -1;

}

printf("socket success\n");

//绑定IP地址和端口信息

int ret = 0;

struct sockaddr_in seraddr = {0};

seraddr.sin_family = AF_INET;

seraddr.sin_addr.s_addr = inet_addr("192.168.61.6");

seraddr.sin_port = htons(8888);

ret = bind(serfd, (struct sockaddr *)&seraddr, sizeof(seraddr));

if (ret < 0)

{

perror("bind failed");

close(serfd);

return -1;

}

printf("bind success\n");

//接收发送自客户端的消息

unsigned int addrlen = 0;

char buf[1024] = {0};

struct sockaddr_in clientaddr = {0};

addrlen = sizeof(clientaddr);

while (1)

{

memset(buf, 0, 1024);



ret = recvfrom(serfd, buf, sizeof(buf), 0, (struct sockaddr *)&clientaddr, &addrlen);

if (ret < 0)

{

perror("recvfrom failed");

close(serfd);

return -1;

}

memcpy(&cnt, buf, sizeof(int));

printf("IP=%s,port=%u\n", inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port));

printf("recvfrom success\n");

printf("receive: %d\n", cnt);

if (cnt == 800)

{

if (serfd > 0)

ret = close(serfd);

printf("close serfd=%d\n", ret);

sleep(5);

serfd = socket(AF_INET, SOCK_DGRAM, 0);

sleep(1);

printf("serfd = %d\n", serfd);

ret = bind(serfd, (struct sockaddr *)&seraddr, sizeof(seraddr));

}

//向客户端发送消息

memset(buf, 0, sizeof(buf));

//gets(buf);

// std::cin.getline(buf,1023);

//cnt++;

//memcpy(buf,&cnt,sizeof(int));

// ret=sendto(serfd,buf,strlen(buf),0,(struct sockaddr *)&clientaddr,addrlen);

// if(ret<0)

// {

// printf("%ret = %d\n",ret);

// perror("sendto failed");

// close(serfd);

// return -1;

// }

// printf("sendto success\n");

usleep(200000);

}

close(serfd);

return 0;

}

编译:

g++ recv.cpp -o recv

g++ send.cpp -o send

五. 运行顺序

1. 准备工作

启动6个命令窗口,进入到上述文件目录下;

2. 先在terminal#1运行recv程序,可以将之重定向到其它文件;

./recv > r3.txt

3. 在terminal#2运行send程序

./send

4. 在terminal#3查看rtxt的最后10行,每秒更新一次,主要用于确认cnt=800大概在什么时候;

watch -n 1 tail -n10 r3.txt

?5. 在terminal#4查看recv对应的pid,然后进入到/proc/pid/fd查看socket文件,并每秒更新一次,查看socket文件是否变化;

6.?查看udp丢包情况以及socket对应的文件的inode是否变化;

watch -n 1 "cat /proc/net/udp |grep 22B8" 其中22B8是端口8888的十六进制表示。

目前看丢包6121个;2705799就是目前8888端口对应socket文件的inode号。和/proc/pid/fd下面的文件一致;

?7.?查看udp的接收队列情况

watch -n 1 netstat -anu

可以看到目前recv Q保持高位运行。

  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2022-07-03 11:09:04  更:2022-07-03 11:09:51 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/6 10:14:38-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码