C++ 为什么在linux上看不到SOCK_Seq数据包的MSG_EOR?

C++ 为什么在linux上看不到SOCK_Seq数据包的MSG_EOR?,c++,c,linux,C++,C,Linux,我有两个进程,它们通过使用socketpair()和SOCK_SEQPACKET创建的一对套接字进行通信。像这样: int ipc_sockets[2]; socketpair(PF_LOCAL, SOCK_SEQPACKET, 0, ipc_sockets); 据我所知,在接收SOCK_SEQPACKET记录时,我应该在“struct msghdr”的MSG_flags成员中看到MSG_EOR。我在sendmsg()中设置MSG_EOR,以确保记录标记为MSG_EOR,但在recvmsg()

我有两个进程,它们通过使用socketpair()和SOCK_SEQPACKET创建的一对套接字进行通信。像这样:

int ipc_sockets[2];
socketpair(PF_LOCAL, SOCK_SEQPACKET, 0, ipc_sockets);
据我所知,在接收SOCK_SEQPACKET记录时,我应该在“struct msghdr”的MSG_flags成员中看到MSG_EOR。我在sendmsg()中设置MSG_EOR,以确保记录标记为MSG_EOR,但在recvmsg()中接收时,我看不到它。在发送记录之前,我甚至尝试在MSG_flags字段中设置MSG_EOR,但没有任何区别

我想我应该看到MSG_EOR,除非记录被信号截断,但我没有。为什么呢

我已经在下面粘贴了我的发送和接收代码

谢谢, 朱尔斯

int
发送fd(内部fd,
void*数据,
康斯特32_t len,
int fd_至_发送,
uint32_t*常量字节(已发送)
{
(三);
结构msghdr msg;
结构iovec iov;
memset(&msg,0,sizeof(struct-msghdr));
memset(&iov,0,sizeof(struct iovec));
#ifdef具有MSGHDR MSG控制
联合{
结构cmsghdr-cm;
字符控制[CMSG_SPACE_SIZEOF_INT];
}控制联合国;
结构cmsghdr*cmptr;
msg.msg_control=控制_un.control;
msg.msg\u controllen=sizeof(control\u un.control);
memset(msg.msg_control,0,sizeof(control_un.control));
cmptr=CMSG_FIRSTHDR(&msg);
cmptr->cmsg_len=cmsg_len(sizeof(int));
cmptr->cmsg_level=SOL_插座;
cmptr->cmsg\U类型=SCM\U权限;
*((int*)CMSG_DATA(cmptr))=fd_to_send;
#否则
msg.msg\u accrights=(caddr\u t)和fd\u to\u send;
msg.msg_ackrightslen=sizeof(int);
#恩迪夫
msg.msg_name=NULL;
msg.msg_namelen=0;
iov.iov_base=数据;
iov.iov_len=len;
msg.msg_iov=&iov;
msg.msg_iovlen=1;
#ifdef_uuuLinux__
msg.msg_flags=msg_EOR;
n=发送消息(fd和msg,msg_EOR);
#elif定义的苹果__
n=sendmsg(fd,&msg,0);/*msg_EOR在Mac上不受支持
*OSX由于缺少
*SOCK_seq上的数据包支持
*袜子对()*/
#恩迪夫
开关(n){
外壳尺寸:
返回EMSGSIZE;
案例1:
返回1;
违约:
*发送的字节数=n;
}
返回0;
}
int
recv_fd(内部fd,
无效*buf,
康斯特32_t len,
int*recvfd,
uint32_t*常量字节(u recv)
{
结构msghdr msg;
结构iovec iov;
ssize_t n=0;
#如果NDEF拥有MSGHDR MSG控制权
int-newfd;
#恩迪夫
memset(&msg,0,sizeof(struct-msghdr));
memset(&iov,0,sizeof(struct iovec));
#ifdef具有MSGHDR MSG控制
联合{
结构cmsghdr-cm;
字符控制[CMSG_SPACE_SIZEOF_INT];
}控制联合国;
结构cmsghdr*cmptr;
msg.msg_control=控制_un.control;
msg.msg\u controllen=sizeof(control\u un.control);
memset(msg.msg_control,0,sizeof(control_un.control));
#否则
msg.msg_accrights=(caddr_t)和newfd;
msg.msg_ackrightslen=sizeof(int);
#恩迪夫
msg.msg_name=NULL;
msg.msg_namelen=0;
iov.iov_base=buf;
iov.iov_len=len;
msg.msg_iov=&iov;
msg.msg_iovlen=1;
如果(recvfd)
*recvfd=-1;
n=recvmsg(fd和msg,0);
if(msg.msg_flags){//cmsg_len==cmsg_len(sizeof(int))){
if(SOL_插座!=cmptr->cmsg_电平){
返回0;
}
if(SCM\U权限!=cmptr->cmsg\U类型){
返回0;
}
如果(recvfd)
*recvfd=*((int*)CMSG_数据(cmptr));
}
#否则
if(recvfd&(sizeof(int)=msg.msg\u accrowtslen))
*recvfd=newfd;
#恩迪夫
返回0;
}

这不是味精EOR的用途

请记住,套接字API是对许多不同协议的抽象,包括UNIX文件系统套接字、socketpairs、TCP、UDP和许多不同的网络协议,包括X.25和一些完全被遗忘的协议

MSG_EOR是在对底层协议有意义的地方发出记录结束信号。也就是说,它是向下一层传递一条消息,“这就完成了一个记录”。这可能会影响缓冲,导致缓冲区刷新。但是如果协议本身没有“记录”的概念没有理由期望传播该标志

其次,如果使用SEQPACKET,则必须立即阅读整个消息。如果不这样做,剩余的消息将被丢弃。这是有记录的。特别是,MSG_EOR是not一个标志,告诉您这是数据包的最后一部分


建议:很明显,您正在编写一个非SEQPACKET版本供MacOS使用。我建议您卸载SEQPACKET版本,因为它只会使维护和编码负担翻倍。SOCK_STREAM适用于所有平台。

对于SOCK_SEQPACKET unix域套接字,缩短消息的唯一方法是如果您给recvm的缓冲区sg()不够大(在这种情况下,您将得到MSG_TRUNC)

POSIX说SOCK_SEQPACKET套接字必须在记录的末尾设置MSG_EOR,但Linux unix域套接字不能

(参考文献:POSIX 2008 2.10.10说SOCK_Seq数据包必须支持记录,2.10.6说记录边界通过MSG_EOR标志对接收器可见。)

“记录”对于给定协议的含义取决于实现定义

如果Linux确实为unix域套接字实现MSG_EOR,我认为唯一明智的方法是
int
send_fd(int fd,
        void *data,
        const uint32_t len,
        int fd_to_send,
        uint32_t * const bytes_sent)
{
    ssize_t n;
    struct msghdr msg;
    struct iovec iov;

    memset(&msg, 0, sizeof(struct msghdr));
    memset(&iov, 0, sizeof(struct iovec));

#ifdef HAVE_MSGHDR_MSG_CONTROL
    union {
        struct cmsghdr cm;
        char control[CMSG_SPACE_SIZEOF_INT];
    } control_un;
    struct cmsghdr *cmptr;

    msg.msg_control = control_un.control;
    msg.msg_controllen = sizeof(control_un.control);
    memset(msg.msg_control, 0, sizeof(control_un.control));

    cmptr = CMSG_FIRSTHDR(&msg);
    cmptr->cmsg_len = CMSG_LEN(sizeof(int));
    cmptr->cmsg_level = SOL_SOCKET;
    cmptr->cmsg_type = SCM_RIGHTS;
    *((int *) CMSG_DATA(cmptr)) = fd_to_send;
#else
    msg.msg_accrights = (caddr_t) &fd_to_send;
    msg.msg_accrightslen = sizeof(int);
#endif
    msg.msg_name = NULL;
    msg.msg_namelen = 0;

    iov.iov_base = data;
    iov.iov_len = len;
    msg.msg_iov = &iov;
    msg.msg_iovlen = 1;

#ifdef __linux__
    msg.msg_flags = MSG_EOR;
    n = sendmsg(fd, &msg, MSG_EOR);
#elif defined __APPLE__
    n = sendmsg(fd, &msg, 0); /* MSG_EOR is not supported on Mac                                                                                                                                                                        
                               * OS X due to lack of                                                                                                                                                                                    
                               * SOCK_SEQPACKET support on                                                                                                                                                                              
                               * socketpair() */
#endif
    switch (n) {
    case EMSGSIZE:
        return EMSGSIZE;
    case -1:
        return 1;
    default:
        *bytes_sent = n;
    }

    return 0;
}

int
recv_fd(int fd,
        void *buf,
        const uint32_t len,
        int *recvfd,
        uint32_t * const bytes_recv)
{
    struct msghdr msg;
    struct iovec iov;
    ssize_t n = 0;
#ifndef HAVE_MSGHDR_MSG_CONTROL
    int newfd;
#endif
    memset(&msg, 0, sizeof(struct msghdr));
    memset(&iov, 0, sizeof(struct iovec));

#ifdef HAVE_MSGHDR_MSG_CONTROL
    union {
        struct cmsghdr  cm;
        char control[CMSG_SPACE_SIZEOF_INT];
    } control_un;
    struct cmsghdr *cmptr;

    msg.msg_control = control_un.control;
    msg.msg_controllen = sizeof(control_un.control);
    memset(msg.msg_control, 0, sizeof(control_un.control));
#else
    msg.msg_accrights = (caddr_t) &newfd;
    msg.msg_accrightslen = sizeof(int);
#endif
    msg.msg_name = NULL;
    msg.msg_namelen = 0;

    iov.iov_base = buf;
    iov.iov_len = len;
    msg.msg_iov = &iov;
    msg.msg_iovlen = 1;

    if (recvfd)
        *recvfd = -1;

    n = recvmsg(fd, &msg, 0);
    if (msg.msg_flags) { // <== I should see MSG_EOR here if the entire record was received
        return 1;
    }
    if (bytes_recv)
        *bytes_recv = n;
    switch (n) {
    case 0:
        *bytes_recv = 0;
        return 0;
    case -1:
        return 1;
    default:
        break;
    }

#ifdef HAVE_MSGHDR_MSG_CONTROL
    if ((NULL != (cmptr = CMSG_FIRSTHDR(&msg))) 
        && cmptr->cmsg_len == CMSG_LEN(sizeof(int))) {
        if (SOL_SOCKET != cmptr->cmsg_level) {
            return 0;
        }
        if (SCM_RIGHTS != cmptr->cmsg_type) {
            return 0;
        }
        if (recvfd)
            *recvfd = *((int *) CMSG_DATA(cmptr));
    }
#else
    if (recvfd && (sizeof(int) == msg.msg_accrightslen))
        *recvfd = newfd;
#endif
    return 0;
}