UDP组播客户端套接字奇怪的行为

时间:2015-07-09 09:45:58

标签: c++ c sockets udp multicast

我有一个程序,它从远程服务器接收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();
}

0 个答案:

没有答案