SCTP recvmsg返回EFAULT错误地址

问题描述

出于测试目的,我正在尝试构建一个非常简单且基本的STCP一对多服务器,但是由于某些原因,套接字似乎只能接收一条消息。收到一条消息后,对recvmsg的每个后续调用都返回-1,其中errnoEFAULT。这对我来说绝对没有意义,所以也许您可以告诉我我在这里没看到的内容EFAULT应该在以下时间返回

EFAULT
接收缓冲区指针指向进程的地址空间之外。

绝对不是这种情况。

#include <ctype.h>
#include <cstring>
#include <stdio.h>
#include <iostream>
#include <unistd.h>
#include <sys/socket.h> 
#include <arpa/inet.h> 
#include <netinet/in.h> 

int main(int argc,char** argv) {
    struct sockaddr_in bind_address;
    bind_address.sin_family = AF_INET;
    bind_address.sin_port = htons(51338);
    bind_address.sin_addr.s_addr = INADDR_ANY;

    int sock = socket(AF_INET,SOCK_SEQPACKET,IPPROTO_SCTP);
    if (sock == -1) {
        perror("Error while creating socket");
        return 1;
    }

    int rv = bind(sock,(struct sockaddr*)(&bind_address),sizeof(bind_address));
    if (rv != 0 ) {
        perror("Error while binding socket");
        return 1;
    }

    rv = listen(sock,1);
    if (rv != 0 ) {
        perror("Error while listening");
        return 1;
    }

    struct iovec iov[1];
    iov[0].iov_base = malloc(1500);
    iov[0].iov_len = 1500;

    struct sockaddr_in sin = {};
    char control[1000] = { 0 };

    struct msghdr mhdr;
    mhdr.msg_iov = iov;
    mhdr.msg_iovlen = sizeof(iov);
    mhdr.msg_name = &sin;
    mhdr.msg_namelen = sizeof(sin);
    mhdr.msg_control = &control;
    mhdr.msg_controllen = sizeof(control);

    while (true) {
        std::memset(iov[0].iov_base,iov[0].iov_len);
        std::memset(&sin,sizeof(sin));

        int recv_bytes = recvmsg(sock,&mhdr,0);

        if (recv_bytes == -1) {
            if (errno == EAGAIN || errno == EWOULDBLOCK) {
                continue;
            } else {
                perror("Err");
            }
            break;
        }

        std::cout << "Received message: " << std::endl;
        std::cout << (char*)iov[0].iov_base << std::endl;
    }

    return 0;
}

解决方法

错误很可能是因为第一次调用recvmsg()会覆盖堆栈中的某些数据,从而导致mhdr中的一个指针无效。这可能是因为这一行:

mhdr.msg_iovlen = sizeof(iov);

这不应包含数组iov的大小(以字节为单位),而应仅包含该数组中元素的数量,因此:

mhdr.msg_iovlen = sizeof(iov) / sizeof(*iov); // which equals 1 in this case