【问题标题】:winsock2: RAW SOCKET recvfrom() returns Error 10022 (Invalid Argument)winsock2:RAW SOCKET recvfrom() 返回错误 10022(无效参数)
【发布时间】:2020-08-25 07:25:44
【问题描述】:

我正在尝试在 Windows 10 中使用 RAW SOCKET 处理传入的网络数据包。

当我调用 recvfrom() 函数时,它返回 -1 值。 WSAGetLastError 是 10022。

Microsoft Docs 页面给我以下描述:

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

我曾尝试使用setsockopt()IP_HDRINCL 设置为1,但是当我调用recvfrom() 时它返回相同的错误。

我的源代码:

#include "stdio.h"
#include "winsock2.h"
#include "ws2tcpip.h"


int main(){
    SOCKET s;
    char* buff = malloc(256);
    int optval = 1;
    struct sockaddr_in adr;
    int adr_length = sizeof(adr);
    int i;
    int rcv_len;
    WSADATA wsa;

    memset(buff, 0, 256);

    if(WSAStartup(MAKEWORD(2,2), &wsa) != 0){
        printf("Error in WSAStartup: %d\n", WSAGetLastError());
        getch();
        return 0;
    }

    s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
    if(s == SOCKET_ERROR){
        printf("Error in socket creation: %d\n", WSAGetLastError());
        getch();
        return 0;
    }

    if(setsockopt(s, IPPROTO_IP, IP_HDRINCL, (char *)&optval, sizeof(optval)) == -1){
        printf("Error in setsockopt(): %d\n", WSAGetLastError());
        getch();
        closesocket(s);
        return 0;
    }

    while(1){
        rcv_len = recvfrom(s, buff, 256, 0, (struct sockaddr*)&adr, &adr_length);

        if(rcv_len == -1){
            printf("Error in recvfrom(): %d\n", WSAGetLastError());
            getch();
            break;
        }

        for(i = 0; i < 256; i ++){
            printf("%c", *(buff + i));
        }
    }

    closesocket(s);

    return 1;
}

返回:

Error in recvfrom(): 10022

【问题讨论】:

  • 你真的需要一个原始套接字吗?微软一直在逐渐限制在 Windows 中使用原始套接字可以做什么。事实上,我不确定他们是否真的像某些 *nix 操作系统那样完全支持它。
  • 如果你将addraddrLen都设置为NULL,你会一直得到错误吗?
  • @jwdonahue,我正在研究RAW SOCKET,这个项目仅用于学习目的。我也将尝试研究 winpcap,但我之前尝试使用 RAW SOCKET 处理数据包。用这种方式处理 IP PACKETS 可能不会成功?
  • @RobertoCaboni,如果没有初始化 adr 和 adr_length,或者在所有结构的变量中初始化为 0,或者使用 AF_INET、INADR_ANNY、port = 0 和 adr_length = sizeof(adr) 初始化,也会发生同样的错误。当我使用 bind() 时,recvfrom() 调用不会返回错误,但我没有收到任何数据包。

标签: c windows sockets winsock2 recvfrom


【解决方案1】:

我已经解决了这个问题。

缺少什么:

  1. 使用您正在处理的接口的 IP 使用bind() 打开 SOCKET
  2. 使用WSAIoctl() 将 opt SO_RCVALL 设置为 1

所以,现在代码正在使用这个源:

#include "stdio.h"
#include "winsock2.h"
#include "ws2tcpip.h"

int main(){
    SOCKET s;
    unsigned char* buff = malloc(32768);
    int optval = 1;
    struct sockaddr_in adr;
    struct sockaddr_in sadr;
    int adr_length = 0;
    int i;
    int in;
    int rcv_len;
    WSADATA wsa;

    memset(buff, 0, 32768);

    if(WSAStartup(MAKEWORD(2,2), &wsa) != 0){
        printf("Error in WSAStartup: %d\n", WSAGetLastError());
        getch();
        return 0;
    }

    s = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
    if(s == SOCKET_ERROR){
        printf("Error in socket creation: %d\n", WSAGetLastError());
        getch();
        return 0;
    }

    sadr.sin_family = AF_INET;
    sadr.sin_addr.s_addr = inet_addr("127.0.0.1");
    sadr.sin_port = htons(0);

    bind(s, (struct sockaddr*)&sadr, sizeof(sadr));

    if(setsockopt(s, IPPROTO_IP, IP_HDRINCL, (char *)&optval, sizeof(optval)) == -1){
        printf("Error in setsockopt(): %d\n", WSAGetLastError());
        getch();
        closesocket(s);
        return 0;
    }

    optval = 1;
    WSAIoctl(s, SIO_RCVALL, &optval, sizeof(optval), 0, 0, (LPDWORD) &in, 0, 0);

    while(1){
        adr_length = sizeof(adr);
        rcv_len = recvfrom(s, buff, 32768, 0, (struct sockaddr*)&adr, &adr_length);

        if(rcv_len == -1){
            printf("Error in recvfrom(): %d\n", WSAGetLastError());
            getch();
            break;
        }

        for(i = 0; i < rcv_len; i ++){
            printf("%d ", *(buff + i));
        }
    }

    closesocket(s);

    return 1;
}

谢谢大家!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-22
    • 2013-12-25
    • 1970-01-01
    • 1970-01-01
    • 2015-12-07
    • 1970-01-01
    相关资源
    最近更新 更多