这一段时间基于udp的数据重放的过程中图像总是卡死,发现recv Q满了,但是不知道具体原因是啥,这里就先进行了udp的接收测试。
if(cnt == 800)
{
serfd=socket(AF_INET,SOCK_DGRAM,0);
printf("serfd = %d\n",serfd);
// ret=bind(serfd,(struct sockaddr *)&seraddr,sizeof(seraddr));
}
无论是否执行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对应队列中没有数据。

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,然后开始新的积累数据。



- #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;
-
- }
- #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保持高位运行。
