Страницы

Поиск по вопросам

пятница, 28 февраля 2020 г.

Ошибка при вызове WSAPoll()

#cpp #c #winapi #клиент_сервер #winsock


Пишу простой UDP сервер под Windows, который принимает сообщения от клиентов. По
заданию сокеты должны работать в неблокирующем режиме и обязательно нужно использовать
WSAPoll для параллельного обслуживания клиентов. Написал небольшую обертку для сокета:

class _socket
{
private:
    SOCKET      sock;
    sockaddr_in addr;
public:
    _socket(int port);
    _socket(const _socket & other);
    ~_socket();

    SOCKET GetSocket();
    bool   Generate();
    bool   Bind();
};

_socket::~_socket() 
{
    if (sock != INVALID_SOCKET) 
    {
        closesocket(sock); 
    } 
}

_socket::_socket(int port) : sock(INVALID_SOCKET) 
{
    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_port = htons(port); 
    addr.sin_addr.s_addr = htonl(INADDR_ANY);
}

_socket::_socket(const _socket & other)
{
    this->sock = other.sock;
    this->addr = other.addr;
}

SOCKET _socket::GetSocket()
{
     return (this->sock); 
}
bool _socket::Generate()
{
    sock = socket(AF_INET, SOCK_DGRAM, 0);
    if (sock < 0)
    {
        return false;
    }
    else
    {
        unsigned long mode = 1;
        return (ioctlsocket(sock, FIONBIO, &mode) != SOCKET_ERROR);
    }
}
bool _socket::Bind()
{
    return (bind(sock, (struct sockaddr*)&addr, sizeof(addr)) >= 0);
}


Вот так работаю с ним в main (через argv передаю диапазон портов):

int main(int argc, const char *argv[])
{
    std::vector<_socket>        sockets;
    std::map clients;

    if (argc < 3)
    {
        return ErrorPrint("Too low arguments");
    }
    if (!Init())
    {
        return ErrorPrint("Error starting WSA");
    }

    for (int i = atoi(argv[1]); i <= atoi(argv[2]); i++)
    {
        _socket s(i);
        if (!s.Generate())
        {
            return ErrorPrint("Cannot create socket");
        }
        if (!s.Bind())
        {
            return ErrorPrint("Cannot bind socket");
        }
        sockets.push_back(s);
    }

    WSAPOLLFD *pfd = (WSAPOLLFD*)malloc(sockets.size() * sizeof(WSAPOLLFD));

    for (int i = 0; i < sockets.size(); i++)
    {
        pfd[i].fd      = sockets[i].GetSocket();
        pfd[i].events  = POLLIN | POLLOUT;
        pfd[i].revents = 0;
    }

    while (true)
    {
        int ev_cnt = WSAPoll(pfd, sockets.size(), 1000);
        if (ev_cnt > 0)
        {
            for (int i = 0; i < sockets.size(); i++)
            {
                if (pfd[i].revents & POLLERR)
                {

                }
                if (pfd[i].revents & POLLIN)
                {

                }
                if (pfd[i].revents & POLLOUT)
                {

                }
            }
        }
        else if (ev_cnt == SOCKET_ERROR)
        {
            std::cout << "Error WSAPoll: " << WSAGetLastError() << std::endl; //
Постоянно попадаю сюда
        }
        else
        {
            std::cout << "waiting..." << std::endl;
        }
    }

    return (EXIT_SUCCESS);
}


При вызове WSAPoll постоянно получаю ошибку WSAENOTSOCK (10038), которая говорит
мне, что я пытаюсь выполнить операцию, предназначенную для сокета на чем-то, что им
не является. Прочитал спецификации к WSAPoll - вроде все делаю правильно, никак не
могу понять, что сделал не так.
    


Ответы

Ответ 1



У вас реализован конструктор копирования после выполнения которого в двух экземплярах класса будет хранится один и тот же дескриптор сокета. После разрушения одного из экземпляров второй останется с невалидным дескриптором. Следовало реализовать конструктор перемещения (и перемещающий оператор присваивания): _socket(const _socket & other) = delete; _socket(_socket && other) : sock{other.sock} , addr{other.addr} { other.sock = INVALID_SOCKET; ::std::memset(::std::addressof(other.addr), 0, sizeof(other.addr)); } Сокеты на самом деле можно дублировать используя WSADuplicateSocket, но обычно это не нужно.

Комментариев нет:

Отправить комментарий