听 Winsock 错误 10022

Posted

技术标签:

【中文标题】听 Winsock 错误 10022【英文标题】:Winsock Error 10022 on Listen 【发布时间】:2013-12-27 18:18:17 【问题描述】:

我正在制作一个小型 IRC 服务器,但我遇到了一个问题;在尝试侦听套接字时,我收到错误 10022(无效参数)。

accept() 上也出现错误,但这是因为套接字未在侦听(我发布的问题是关于此问题)。

我没有包含接受功能,因为我觉得它没有必要并且会添加毫无意义的代码。

#include <iostream>
#include <ws2tcpip.h>
#include <winsock2.h>
#include <thread>
#include <string>
#pragma comment(lib, "Ws2_32.lib")
#define maxConnections 10
class Server

        struct sockaddr_storage their_addr;
        struct addrinfo hints, *res;
        struct addrinfo *servinfo;
    int status;
    SOCKET sock;
public:
    void Start(const char *port);
;

void Server::Start(const char *port)

    WSADATA WSAData;
    if (WSAStartup(MAKEWORD(2, 0), &WSAData) != 0)
    
        std::cout << "[ERROR]: " << GetLastError() << ".\n";
    
    memset(&hints, 0, sizeof(hints));
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;
    status = getaddrinfo(NULL, port, &hints, &res);
    sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
    if (sock == SOCKET_ERROR)
    
        std::cout << "[ERROR]: " << WSAGetLastError() << "Bad Socket.\n";
    
    bind(sock, res->ai_addr, res->ai_addrlen);

错误:

    if (listen(sock, maxConnections) == SOCKET_ERROR)
    
        std::cout << "[ERROR]: " << WSAGetLastError() << " Listening Failed.\n";
    

上面的代码详细说明了socket的创建和绑定,都成功了(虽然不一定对)。包括“NULL”在内的套接字创建可能是问题所在。

谢谢:)

【问题讨论】:

你传递给bind 的参数看起来不对——你应该绑定到一个地址和端口。尝试检查该调用的错误返回。 无错误 - WSAGetLastError() 返回 0。 【参考方案1】:

WSAStartup()getaddrinfo() 不使用(WSA)GetLastError(),而是直接返回实际的错误代码。您没有在错误消息中考虑到这一点。

socket() 在失败时返回 INVALID_SOCKET,而不是 SOCKET_ERROR

使用getaddrinfo()创建监听套接字时,应在hints参数的addrinfo.ai_flags字段中指定AI_PASSIVE。这将使用适合传递给bind() 的数据填充输出addrinfo

试试这样的:

class Server

private:
    bool winsockStarted;
    SOCKET sock;
    ...
public:
    Server();
    ~Server();
    bool Start(const char *port);
    void Stop();
    ...
;

Server::Server()
    : sock(INVALID_SOCKET), winsockStarted(false)

    WSADATA WSAData = 0;
    int status = WSAStartup(MAKEWORD(2, 0), &WSAData);
    if (status != 0)
        std::cout << "[ERROR]: " << status << " Unable to start Winsock." << std::endl;
    else
        winsockStarted = true;


Server::~Server()

    Stop();

    if (winsockStarted)
        WSACleanup();


bool Server::Start(const char *port)

    Stop();

    struct addrinfo hints = 0;
    struct addrinfo *res = NULL;

    hints.ai_flags = AI_PASSIVE;
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;

    int status = getaddrinfo(NULL, port, &hints, &res);
    if (status != 0)
    
        std::cout << "[ERROR]: " << status << " Unable to get address info for Port " << port << "." << std::endl;
        return false;
    

    SOCKET newsock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
    if (newsock == INVALID_SOCKET)
    
        std::cout << "[ERROR]: " << WSAGetLastError() << " Unable to create Socket." << std::endl;
        freeaddrinfo(res);
        return false;
    

    if (bind(newsock, res->ai_addr, res->ai_addrlen) == SOCKET_ERROR)
    
        std::cout << "[ERROR]: " << WSAGetLastError() << " Unable to bind Socket." << std::endl;
        freeaddrinfo(res);
        closesocket(newsock);
        return false;
    

    freeaddrinfo(res);

    if (listen(newsock, maxConnections) == SOCKET_ERROR)
    
        std::cout << "[ERROR]: " << WSAGetLastError() << " Unable to Listen on Port " << port << "." << std::endl;
        closesocket(newsock);
        return false;
    

    sock = newsock;
    return true;


void Server::Stop()

    if (sock != INVALID_SOCKET)
    
        closesocket(sock);
        sock = INVALID_SOCKET;
    

【讨论】:

除了能有效回答我的问题的完整、全面的答案外,我还能说些什么。非常感谢:)【参考方案2】:

我重新阅读了我的代码并意识到我需要在这里添加一个检查

status = getaddrinfo(NULL, port, &hints, &res); 

我改成

if (status = getaddrinfo(NULL, port, &hints, &res) != 0)

    std::cout << "[ERROR]: " << WSAGetLastError() << "Get Address Info failed.\n";

并且启动成功。

如果有人能解释原因,我会改进我的答案。

【讨论】:

在同一个表达式中进行赋值和比较时需要使用额外的括号:if ((status = getaddrinfo(NULL, port, &amp;hints, &amp;res)) != 0),否则将它们分成不同的语句:status = getaddrinfo(NULL, port, &amp;hints, &amp;res); if (status != 0)

以上是关于听 Winsock 错误 10022的主要内容,如果未能解决你的问题,请参考以下文章

WinSock2.h 中的重新定义错误 [重复]

send(),返回 Winsock 错误 10038

winsock 的 v8 发布模式链接器错误

MinGW 链接器错误:winsock

VS2008 编译错误 <winsock2.h>

Winsock - 10038 错误 - Win2K3 服务器 - 令人费解的行为