QT中UDPSocket丢包问题(续)
来源:互联网 发布:odis工程师刷低层数据 编辑:程序博客网 时间:2024/06/02 05:21
之前描述了Qt中编写UDP收发程序的丢包问题,
见http://blog.csdn.net/rabbitjerry/article/details/72674458
后来终于得到了彻底解决,并且在Windows操作系统和Linux操作系统下均得到了验证。
一、解决思路
1.在程序中利用QThread类开辟一个用来接收UDP包的新线程;
2.在Windows操作系统下使用Windows封装的Socket,在Linux下使用Linux的Socket,摒弃了Qt的QSocket;
3.在新线程中使用while死循环,并采用Socket默认的阻塞模式接收数据;
4.为了避免维护多个程序,使用宏控制是使用Windows的Socket还是Linux的Socket,在不同的环境下更改宏定义后重新编译即可,便于使用和维护。
由此一来,不再丢包,且CPU占用率也较低(因为采用了阻塞模式)。
二、核心代码
1.宏定义和头文件的引用
#define _WIN_SOCKET_ 1#define _QT_SOCKET_ 0#define _LINUX_SOCKET_ 0#if _WIN_SOCKET_ // for windows OS #include <stdio.h>#include <winsock2.h>#endif#if _LINUX_SOCKET_ // for Linux OS#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <netdb.h>#endif
2.头文件中相关代码
#if _QT_SOCKET_private: QUdpSocket * p_echo_socket;#endif#if _WIN_SOCKET_ // for windows OSprivate: WSADATA wsaData; WORD sockVersion; SOCKET echo_socket_WIN; sockaddr_in addr_WIN; sockaddr_in src_addr_WIN; int src_addr_len = sizeof(src_addr_WIN);#endif#if _LINUX_SOCKET_private: int socket_len; int socket_descriptor; struct sockaddr_in echo_socket_LINUX;#endif
3. 构造函数中与socket相关的内容
/************* socket **************/#if _QT_SOCKET_ p_echo_socket = new QUdpSocket(this); p_echo_socket->setSocketOption(QAbstractSocket::ReceiveBufferSizeSocketOption, 4*1024*1024);//设置缓存 if(!p_echo_socket->bind(DRY_ECHO_NET_PORT)) // 端口绑定 { qDebug()<<"BIND failed for receiving echo port."; }#endif#if _WIN_SOCKET_ // for windows OS sockVersion = MAKEWORD(2,2); if(WSAStartup(sockVersion, &wsaData) != 0) { printf("winsock initialization FAILED."); } echo_socket_WIN = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if(echo_socket_WIN == INVALID_SOCKET) { printf("winsocket error !"); } addr_WIN.sin_family = AF_INET; addr_WIN.sin_port = htons(DRY_ECHO_NET_PORT); addr_WIN.sin_addr.S_un.S_addr = INADDR_ANY; if(bind(echo_socket_WIN, (sockaddr *)&addr_WIN, sizeof(addr_WIN)) == SOCKET_ERROR) { printf("bind error !"); closesocket(echo_socket_WIN); } // set socket buffer size int optVal = 0; int optLen = sizeof(optVal); optVal = 4*1024*1024; setsockopt(echo_socket_WIN, SOL_SOCKET, SO_RCVBUF, (char*)&optVal, optLen);#endif#if _LINUX_SOCKET_ bzero(&echo_socket_LINUX,sizeof(echo_socket_LINUX)); echo_socket_LINUX.sin_family=AF_INET; echo_socket_LINUX.sin_addr.s_addr=htonl(INADDR_ANY); echo_socket_LINUX.sin_port=htons(DRY_ECHO_NET_PORT); socket_len=sizeof(echo_socket_LINUX); socket_descriptor=socket(AF_INET,SOCK_DGRAM,0); bind(socket_descriptor,(struct sockaddr *)&echo_socket_LINUX,sizeof(echo_socket_LINUX)); int buffer_size_LINUX=0; socklen_t optlen_LINUX; optlen_LINUX = sizeof(buffer_size_LINUX); getsockopt(socket_descriptor,SOL_SOCKET,SO_RCVBUF,&buffer_size_LINUX,&optlen_LINUX); buffer_size_LINUX = 4*1024*1024; if(setsockopt(socket_descriptor, SOL_SOCKET, SO_RCVBUF, &buffer_size_LINUX, optlen_LINUX) < 0) { qDebug()<<"set recv buffer size FAILED."; } getsockopt(socket_descriptor,SOL_SOCKET,SO_RCVBUF,&buffer_size_LINUX,&optlen_LINUX);#endif
4. 接收数据函数中与socket有关的代码
while(1) { net_pack_size = 0;#if _QT_SOCKET_ if( p_echo_socket->hasPendingDatagrams()) // 有数据 { net_pack_size = p_echo_socket->pendingDatagramSize(); p_echo_socket->readDatagram((char*)p_echo_net_pack,net_pack_size); }#endif#if _WIN_SOCKET_ net_pack_size = recvfrom(echo_socket_WIN, (char*)p_echo_net_pack, 1600, 0, (sockaddr *)&src_addr_WIN, &src_addr_len);#endif#if _LINUX_SOCKET_ net_pack_size = recvfrom(socket_descriptor,(char*)p_echo_net_pack,1600,0,(struct sockaddr *)&echo_socket_LINUX,(socklen_t*)&socket_len);#endif...
三、注意事项
1.pro文件中在Windows操作系统下要添加如下库,但在Linux系统下则要注释掉该行代码
LIBS+=-lpthreadlibwsock32libws2_32#forwindowsOS
2.Ubuntu操作系统下,设置缓存大小的上限受到操作系统中某个文件的限制,此时需要手动修改默认的接收缓存最大值:
打开/proc/sys/net/core/rmem_max:改为4194304
Ubuntu 16.0默认是212992
[20170601]
阅读全文
2 0
- QT中UDPSocket丢包问题(续)
- QT中UDPSocket丢包问题
- Qt 使用UDPSocket遇到的丢包问题
- QT下udpsocket一段时间接收不到数据的问题
- udpSocket
- UDPSocket
- Qt 的udpSocket通信及相关
- UdpSocket如何实现通过代理接收多包数据
- linux下使用udpsocket时遇到的问题
- QT tcp粘包问题
- Qt tcp 粘包问题
- qt中 字体问题
- QT 中中文问题
- QT中编译问题
- qt中布局问题
- Qt中中文解码问题
- Qt中使用QtSql问题
- Qt 中遇到的问题
- .net 经常抛出OutOfMemoryException 服务器环境问题
- Linux kernel轮询与等待队列
- application/json 和 application/x-www-form-urlencoded的区别
- c++:explicit 抑制构造函数隐式转换
- 量化交易中VWAP/TWAP算法的基本原理和简单源码实现(C++和python)
- QT中UDPSocket丢包问题(续)
- OpenDaylight开发----建立odlops工程(二)
- 关于cvMatchShape函数的问题 .
- 脚本编程
- 直播系统架构(三)
- Java – 怎样重新将 ArrayList 重新洗牌(How to shuffle an ArrayList)
- iOS之修改BundleIdentifier导致项目中todayExtension和watchExtension中出现的问题及解决方法
- 《Using OpenRefine》翻译~17
- HTTP协议—— 简单认识TCP/IP协议