我有一个程序,它从远程服务器接收UDP源特定的多播数据包。我使用非阻塞套接字,有时我有一个错误:11,从暂停套接字读取数据时“资源暂时不可用”。我知道使用非阻塞套接字是正常的行为,这意味着套接字上没有任何数据。但有时我有这个错误,当我知道套接字上有数据时,当我重新启动我的应用程序时,这个错误消失了,为什么会这样呢?
此行为出现在夜晚之后,当套接字上没有任何数据时(因为服务器没有发送任何内容)并且我经常重新打开套接字,但是当数据出现时我一直收到错误11。 如果我在10分钟内有任何读取错误,我关闭套接字并再次打开它,当我用3秒替换10分钟时,我经常会有这种奇怪的行为,即我只有在重新启动应用程序后才有新消息,但我知道那里有是新消息。
我使用的是CentOS 6.5 linux。
以下是我的源代码的一部分:
feed::feed(const char* source_ip, const char* ip, int port, UDPSocketGroup* socket_group)
{
this->source_ip = std::string(source_ip);
this->ip = std::string(ip);
this->port = port;
this->decodert = NULL;
this->socket_group = socket_group;
sd = -1;
}
// Connect data feed ONLY if is disconnected
void feed::connect()
{
if (sd >= 0) return;
last_seq_num = 0;
sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if(sd < 0)
{
std::stringstream buff;
buff << "Openning feed with src_ip=" << source_ip << ", ip=" << ip << ", port=" << port << " error, err_code=" << sd;
log_err(buff.str());
}
else
{
std::stringstream buff;
buff << "Feed with src_ip=" << source_ip << ", ip=" << ip << ", port=" << port << " was succesfully opened";
log_info(buff.str());
}
int reuse = 1;
if(setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, (char*)&reuse, sizeof(reuse)) < 0)
{
std::stringstream buff;
buff << "Setting SO_REUSEADDR for feed with src_ip=" << source_ip << ", ip=" << ip << ", port=" << port << " error";
log_err(buff.str());
close(sd);
sd = -1;
}
else
{
std::stringstream buff;
buff << "SO_REUSEADDR for feed with src_ip=" << source_ip << ", ip=" << ip << ", port=" << port << " was succesfully set";
log_info(buff.str());
}
struct sockaddr_in localSock;
memset((char*) &localSock, 0, sizeof(localSock));
localSock.sin_family = AF_INET;
localSock.sin_port = htons(port);
localSock.sin_addr.s_addr = INADDR_ANY;
if(bind(sd, (struct sockaddr*)&localSock, sizeof(localSock)))
{
std::stringstream buff;
buff << "Binding feed with src_ip=" << source_ip << ", ip=" << ip << ", port=" << port << " error";
log_err(buff.str());
close(sd);
sd = -1;
}
else
{
std::stringstream buff;
buff << "Binding for feed with src_ip=" << source_ip << ", ip=" << ip << ", port=" << port << " was succesfully set";
log_info(buff.str());
}
struct ip_mreqn group;
group.imr_multiaddr.s_addr = inet_addr(ip.c_str());
group.imr_address.s_addr = INADDR_ANY;
group.imr_ifindex = 0;
if(setsockopt(sd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&group, sizeof(group)) < 0)
{
std::stringstream buff;
buff << "Adding multicast group for feed with src_ip=" << source_ip << ", ip=" << ip << ", port=" << port << " error";
log_err(buff.str());
close(sd);
sd = -1;
}
else
{
std::stringstream buff;
buff << "Multicast group for feed with src_ip=" << source_ip << ", ip=" << ip << ", port=" << port << " was succesfully added";
log_info(buff.str());
}
int flags;
if (-1 == (flags = fcntl(sd, F_GETFL, 0))) flags = 0;
if (fcntl(sd, F_SETFL, flags | O_NONBLOCK) < 0)
{
std::stringstream buff;
buff << "Setting nonblock for feed with src_ip=" << source_ip << ", ip=" << ip << ", port=" << port << " error";
log_err(buff.str());
close(sd);
sd = -1;
}
else
{
std::stringstream buff;
buff << "Nonblock for feed with src_ip=" << source_ip << ", ip=" << ip << ", port=" << port << " was succesfully set";
log_info(buff.str());
}
// get_sec_date_time - returns current date and time in epoch format
last_good_time = (double)get_sec_date_time();
}
// Refresh data feed and reconnect if there are errors or time limit is exceeded
bool feed::refresh()
{
int r = recv(sd, databuf, sizeof (databuf) - 1, 0);
if (r < 0)
{
// HEARTBEAT_FREQ = 600, i.e. 10 minutes
if (-1 != sd && ((double) get_sec_date_time() - last_good_time) > HEARTBEAT_FREQ)
{
int errsv = errno;
std::stringstream buff;
buff << "Error reading datagram message from src_ip=" << source_ip << ", ip=" << ip << ", port=" << port << ", err=" << errsv << ", \"" << std::string(strerror(errsv)) << "\"";
log_warn(buff.str());
disconnect();
connect();
return false;
}
}
else
{
last_good_time = (double) get_sec_date_time();
return socket_group->decode(databuf, r, this) > 0;
}
return false;
}
// Disconnect data feed
void feed::disconnect()
{
if (sd >= 0)
{
close(sd);
}
sd = -1;
std::stringstream buff;
buff << "Feed with src_ip=" << source_ip << ", ip=" << ip << ", port=" << port << " was succesfully closed";
log_info(buff.str());
}
以下是我使用 feed 类的方法:
feed f = ...;
f.connect();
while (true)
{
f.refresh();
}