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

154
14 августа 2018, 16:30

Пишу простой 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<uint32_t, _client> 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 - вроде все делаю правильно, никак не могу понять, что сделал не так.

Answer 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, но обычно это не нужно.

READ ALSO
Visual Studio Code Директива #include [закрыт]

Visual Studio Code Директива #include [закрыт]

Мне нужно сделать проект под линукс на плюсах, не когда ранее не программировал под негоСейчас вот поставил Visual Studio Code на Ubuntu установил все...

126
Как прокручивать окно при помощи WS_VSCROLL(C++ WINAPI)

Как прокручивать окно при помощи WS_VSCROLL(C++ WINAPI)

В своем оконном приложении на WINAPI решил использовать вертикальный скролл(Естественно, прописав в аргументах окна)Сам скролл появился, однако...

142
Firebase под Eclipse

Firebase под Eclipse

Как подружить Firebase FCM с Eclipse?

101
Почему на странице загрузки Java до сих пор рекомендуют скачать 8 версию?

Почему на странице загрузки Java до сих пор рекомендуют скачать 8 версию?

Я разрабатываю приложение на JavaFx и доступен уже редактор основанный на 10 Java, а до сей поры приходится все делать на 8, только потому что нет...

158