winsock错误10022在听

时间:2017-05-31 21:27:43

标签: c++ sockets server winsock listen

这是我在这个伟大网站上的第一个问题。

我正在编写一个简单的服务器,从用户那里获取端口号:

#include <winsock2.h>
#include <ws2tcpip.h>
#include <iostream>
#include <string>
#include <cstring>

class socketConexion { 
private: 
    WSADATA wsaData; 
    int iResultado; 
    SOCKET socketServidor = INVALID_SOCKET;  socket servidor 
    SOCKET socketCliente = INVALID_SOCKET; 
    struct sockaddr *clienteSockaddr;
    struct addrinfo *socketResultado = NULL;
    struct addrinfo datosServidor;
    std::string puertoUsuario;
    char clienteIPV4[LONG_IPV4];
public:
    int iniciarWinsock () { 
        iResultado = WSAStartup(MAKEWORD(2,2), &wsaData);
        printf ("Inicializando Winsock2 \n");
        if (iResultado != 0) { 
            printf ("Error al iniciar Winsock2: %d\n", iResultado);
            return 1;
        else {
            printf ("Winsock2 Inicializado\n");
            return 0;
        }
    }
    int obtenerDirServidor () {
        printf ("Introduzca puerto: ");
        std::cin >> puertoUsuario;
        printf ("Obteniendo datos de servidor.\n");
        ZeroMemory(&datosServidor, sizeof(datosServidor));
        datosServidor.ai_family = AF_INET;
        datosServidor.ai_socktype = SOCK_STREAM;
        datosServidor.ai_protocol = IPPROTO_TCP;
        datosServidor.ai_flags = AI_PASSIVE;
        iResultado = getaddrinfo(NULL, (const char*)puertoUsuario.c_str(), &datosServidor, &socketResultado);
        if (iResultado != 0) {
            printf ("Error al obtener dirección de servidor: %d\n", iResultado);
            WSACleanup();
            return 1;
        }
        else {
            printf ("Dirección de servidor obtenida.\n");
            return 0;
        }
    }
    int socketBind () {
        socketServidor = socket(socketResultado->ai_family, socketResultado->ai_socktype, socketResultado->ai_protocol);
        if (socketServidor == INVALID_SOCKET) {
            printf ("Error al crear socket: %d\n", WSAGetLastError ());
            freeaddrinfo (socketResultado);
            WSACleanup();
            return 1;
        }
        else {
            printf ("Socket creado correctamente.\n");
            return 0;
        }
        iResultado = bind(socketServidor, socketResultado->ai_addr, (int)socketResultado->ai_addrlen);
        if (iResultado == SOCKET_ERROR) {
            printf ("Error al direccionar socket: %d\n", WSAGetLastError());
            freeaddrinfo (socketResultado);
            closesocket(socketServidor);
            WSACleanup();
            return 1;
        }
        else {
            printf ("Socket direccionado correctamente. \n");
            return 0;   
        }
        freeaddrinfo (socketResultado);
    }
    int socketListen (){
        iResultado = listen(socketServidor, SOMAXCONN);
        if (iResultado == SOCKET_ERROR) {
            printf ("Error al poner socket a la escucha socket: %d\n", WSAGetLastError());
            closesocket(socketServidor);
            WSACleanup();
            return 1;
        }
        else {
            printf ("Esperando conexión..... %d\n");
            return 0;
        }
         .....

调用listen函数时出现错误10022,我看不到传递给函数的无效参数。

1 个答案:

答案 0 :(得分:1)

错误代码10022是WSAEINVAL

  

参数无效。
  提供了一些无效参数(例如,为setsockopt函数指定无效级别)。 在某些情况下,它还引用套接字的当前状态 - 例如,在未侦听的套接字上调用accept

根据listen() documentation

  

返回值

     

如果没有错误发生,listen将返回零。否则,返回SOCKET_ERROR的值,并且可以通过调用WSAGetLastError来检索特定的错误代码。

     

...

     

<强> WSAEINVAL
  套接字尚未与bind

绑定

socketBind()方法中,如果socket()成功,则在调用return之前调用bind(),因此套接字永远不会绑定。您需要删除第一个return块中的else语句。此外,如果bind()成功,则第二个else块在调用return之前正在调用freeaddrinfo(),因此您也需要修复它。

试试这个:

int socketBind () {
    socketServidor = socket(socketResultado->ai_family, socketResultado->ai_socktype, socketResultado->ai_protocol);
    if (socketServidor == INVALID_SOCKET) {
        printf ("Error al crear socket: %d\n", WSAGetLastError ());
        freeaddrinfo (socketResultado);
        WSACleanup();
        return 1;
    }

    printf ("Socket creado correctamente.\n");

    iResultado = bind(socketServidor, socketResultado->ai_addr, (int)socketResultado->ai_addrlen);
    if (iResultado == SOCKET_ERROR) {
        printf ("Error al direccionar socket: %d\n", WSAGetLastError());
        freeaddrinfo (socketResultado);
        closesocket(socketServidor);
        WSACleanup();
        return 1;
    }

    printf ("Socket direccionado correctamente. \n");

    freeaddrinfo (socketResultado);
    return 0;   
}

话虽这么说,你的班级一般都没有做好清理工作。我会建议更多类似C ++的东西(使用RAII,在错误上抛出异常等):

#include <winsock2.h>
#include <ws2tcpip.h>
#include <iostream>
#include <string>
#include <system_error>  
#include <memory>

class socketError : public std::system_error
{
public:
    explicit socketError(int err, const std::string &msg)
        : std::system_error(err, std::system_category(), msg + ": " + std::to_string(err))
    {
    }
};

void throwSocketError(int err, const std::string &msg)
{
    std::cout << msg << ": " << err << std::endl;
    throw socketError(err, msg);
}

class wsaInit
{
public:
    wsaInit() {
        int iResultado = WSAStartup(MAKEWORD(2,2), &wsaData);
        printf ("Inicializando Winsock2 \n");
        if (iResultado != 0)
            throwSocketError(iResultado, "Error al iniciar Winsock2");
        printf ("Winsock2 Inicializado\n");
    }

    ~wsaInit() {
        WSACleanup();
    }

    wsaInit(const wsaInit &) = delete;
    wsaInit& operator=(const wsaInit &) = delete;
};

class socketWrapper
{
private:
    SOCKET sckt;

public:
    socketWrapper() : sckt(INVALID_SOCKET) {}
    explicit socketWrapper(SOCKET initialSocket) : sckt(initialSocket) {}
    ~socketWrapper() { reset(); }

    socketWrapper(const socketWrapper &) = delete; 
    socketWrapper& operator=(const socketWrapper &) = delete; 

    void reset(SOCKET newSocket = INVALID_SOCKET) { if (sckt != INVALID_SOCKET) closesocket(sckt); sckt = newSocket; }

    operator SOCKET() const { return sckt; }
    bool operator !() const { return (sckt == INVALID_SOCKET); }
};

class socketConexion { 
private: 
    wsaInit wsa; 
    socketWrapper socketServidor;
    socketWrapper socketCliente; 
    std::unique_ptr<struct addrinfo> socketResultado;
    ...

public:
    socketConexion(const socketConexion &) = delete; 
    socketConexion& operator=(const socketConexion &) = delete; 

    void obtenerDirServidor() {
        socketResultado.reset();

        printf ("Introduzca puerto: ");

        std::string puertoUsuario;
        std::cin >> puertoUsuario;

        printf ("Obteniendo datos de servidor.\n");

        struct addrinfo datosServidor;
        ZeroMemory(&datosServidor, sizeof(datosServidor));
        datosServidor.ai_family = AF_INET;
        datosServidor.ai_socktype = SOCK_STREAM;
        datosServidor.ai_protocol = IPPROTO_TCP;
        datosServidor.ai_flags = AI_PASSIVE;

        struct addrinfo *pResultado;

        int iResultado = getaddrinfo(NULL, puertoUsuario.c_str(), &datosServidor, &pResultado);
        if (iResultado != 0)
            throwSocketError(iResultado, "Error al obtener dirección de servidor");

        socketResultado.reset(pResultado);

        std::cout << "Dirección de servidor obtenida." << std::endl;
    }

    void socketBind () {
        socketServidor.reset();

        if (!socketResultado)
            obtenerDirServidor();

        socketServidor.reset(socketResultado->ai_family, socketResultado->ai_socktype, socketResultado->ai_protocol));
        if (!socketServidor) {
            int iError = WSAGetLastError();
            socketResultado.reset();
            throwSocketError(iError, "Error al crear socket");
        }

        printf("Socket creado correctamente.\n");

        int iResultado = ::bind(socketServidor, socketResultado->ai_addr, (int)socketResultado->ai_addrlen);
        if (iResultado == SOCKET_ERROR) {
            iResultado = WSAGetLastError();
            socketResultado.reset();
            throwSocketError(iResultado, "Error al direccionar socket");
        }

        socketResultado.reset();

        printf ("Socket direccionado correctamente. \n");
    }

    void socketListen() {
        if (!socketServidor)
            socketBind();

        int iResultado = listen(socketServidor, SOMAXCONN);
        if (iResultado == SOCKET_ERROR)
            throwSocketError(WSAGetLastError(), "Error al poner socket a la escucha socket");

        printf ("Esperando conexión.....\n");
    }

    ...
};