gpt4 book ai didi

c++ - linux C++ 套接字选择循环

转载 作者:塔克拉玛干 更新时间:2023-11-03 01:47:45 24 4
gpt4 key购买 nike

我在使用套接字时遇到了一些问题,循环时除了第一个循环外我没有接收到数据,每次都超时。如果我关闭并重新打开每个循环的套接字,尽管我似乎正在正确获取数据。关于原因有什么想法吗?

不关闭循环的例子:

int socketHandle = socket(AF_INET,SOCK_DGRAM,0);

sockaddr_in serverAddr;

serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = inet_addr(/*UDP IP ADDRESS*/);
serverAddr.sin_port = htons(/*UDP PORT*/);

struct timeval tv;
fd_set rfds;

FD_ZERO(&rfds);
FD_SET(socketHandle, &rfds);

tv.tv_usec = 0.0;
int recVal = 0;
int sockLen = sizeof(serverAddr);
bind(socketHandle, (struct sockaddr*)&serverAddr, (socklen_t)sockLen);

bool timePassed = false;
time_t startListenTime = time(NULL);

tv.tv_sec = maxUpdateTime;

while(true)
{
recVal = select(socketHandle + 1, &rfds, NULL, NULL, &tv);
switch(recVal)
{
case(0):
{
//Timeout
break;
}
case(-1):
{
//Error
break;
}
default:
{
/*Packet Data Type*/ pkt;
if(recvfrom(socketHandle, &pkt, sizeof(/*Packet Data Type*/), 0, (sockaddr*)&serverAddr, (socklen_t*)&sockLen) < 0)
{
//Failed to Recieve Data
break;
}
else
{
//Recieved Data!!
}
break;
}
}
}

关闭循环的例子:

while(true)
{
int socketHandle = socket(AF_INET,SOCK_DGRAM,0);

sockaddr_in serverAddr;

serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = inet_addr(/*UDP IP ADDRESS*/);
serverAddr.sin_port = htons(/*UDP PORT*/);

struct timeval tv;
fd_set rfds;

FD_ZERO(&rfds);
FD_SET(socketHandle, &rfds);

tv.tv_usec = 0.0;
int recVal = 0;
int sockLen = sizeof(serverAddr);
bind(socketHandle, (struct sockaddr*)&serverAddr, (socklen_t)sockLen);


bool timePassed = false;
time_t startListenTime = time(NULL);

tv.tv_sec = maxUpdateTime;

recVal = select(socketHandle + 1, &rfds, NULL, NULL, &tv);
switch(recVal)
{
case(0):
{
//Timeout
break;
}
case(-1):
{
//Error
break;
}
default:
{
/*Packet Datastructure*/ pkt;
if(recvfrom(socketHandle, &pkt, sizeof(/*Packet Datastructure*/), 0, (sockaddr*)&serverAddr, (socklen_t*)&sockLen) < 0)
{
//Failed to read packet
break;
}
else
{
//Read Packet!!
}
break;
}
}
close(socketHandle);
}

最佳答案

select() 函数使用指定的文件描述符掩码来确定要监视哪些文件描述符的事件(读、写等)。当文件描述符可用于 I/O 事件(读取、写入)时,select() 函数会修改描述符以指示哪些文件已准备好执行给定的 I/O 操作。

请参阅 select function and the macros/functions used with the file descriptors 上的这篇文章.

旧式 Unix 类型的程序通常将文件描述符视为位掩码并只检查位。然而,文件描述符的实际实现可能因编译器而异,因此最好使用标准文件描述符宏/函数来设置、清除和测试各种文件描述符。

所以在使用select()函数的时候需要用到FD_ZERO()FD_SET()这样才能设置具体的select() 函数调用所需的文件描述符。当 select() 返回时,它将指示指定的哪些文件描述符实际上已准备好用于 I/O 操作(读、写等)。

所以你的代码实际上是这样的:

while(true)
{
fd_set rfds;

FD_ZERO(&rfds);
FD_SET(socketHandle, &rfds);
recVal = select(socketHandle + 1, &rfds, NULL, NULL, &tv);
switch(recVal)
{
case(0):
{
//Timeout
break;
}
case(-1):
{
//Error
break;
}
default:
{
/*Packet Data Type*/ pkt;
if(recvfrom(socketHandle, &pkt, sizeof(/*Packet Data Type*/), 0, (sockaddr*)&serverAddr, (socklen_t*)&sockLen) < 0)
{
//Failed to Recieve Data
break;
}
else
{
//Recieved Data!!
}
break;
}
}

然而,您真正应该做的是使用 FD_ISSET() 函数来检查哪些特定文件描述符已准备好使用。在您的情况下,您只有一个,但在有多个描述符的情况下,您还想使用 FD_ISSET() 函数。

关于c++ - linux C++ 套接字选择循环,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25888914/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com