C++ msghdr结构体

msghdr结构体是在C++中用于存储和传递消息的结构体。它定义在<sys/socket.h>头文件中,包含以下字段:

struct msghdr {
    void         *msg_name;       // 指向目标地址结构体的指针 
    socklen_t     msg_namelen;    // 目标地址结构体的大小 
    struct iovec *msg_iov;        // 指向数据缓冲区的指针 
    size_t        msg_iovlen;     // 数据缓冲区的数量 
    void         *msg_control;    // 指向辅助数据缓冲区的指针 
    size_t        msg_controllen; // 辅助数据缓冲区的大小 
    int           msg_flags;      // 消息标志 
};

下面是一个使用msghdr结构体的示例代码:

#include <sys/socket.h>
#include <iostream>
#include <cstring>
#include <arpa/inet.h>
#include <unistd.h>

using namespace std;

int main() {
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd == -1) {
        cout << "socket创建失败" << endl;
        return -1;
    }

    sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = inet_addr("121.43.36.60");
    addr.sin_port = htons(8888);

    char buffer[1024];
    memset(buffer, 0, sizeof(buffer));
    strcpy(buffer, "hello, world");

    struct iovec iov;
    iov.iov_base = buffer;
    iov.iov_len = strlen(buffer);

    struct msghdr msg;
    msg.msg_name = &addr;
    msg.msg_namelen = sizeof(addr);
    msg.msg_iov = &iov;
    msg.msg_iovlen = 1;
    msg.msg_control = NULL;
    msg.msg_controllen = 0;
    msg.msg_flags = 0;

    ssize_t n = sendmsg(sockfd, &msg, 0);
    if (n == -1) {
        cout << "发送消息失败" << endl;
        close(sockfd);
        return -1;
    }

    close(sockfd);
    return 0;
}

上述代码创建了一个UDP套接字,将数据“hello, world”发送到121.43.36.60:8888。使用了msghdr结构体来指定目标地址和数据缓冲区。其中,msg_name指向目标地址结构体的指针,msg_namelen指定目标地址结构体的大小,msg_iov指向数据缓冲区的指针,msg_iovlen指定数据缓冲区的数量,其他字段均为0或默认值。最后,sendmsg函数将消息发送出去。

在C++中,cmsghdr结构体是用于控制消息的头部结构体,它包含了一些控制信息,如文件描述符、IP地址等。其中,msg_control字段是一个指向存储控制信息的缓冲区的指针。

使用msg_control字段的示例代码如下:

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

#define CONTROLLEN CMSG_LEN(sizeof(int))

int main() {
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) {
        std::cerr << "Failed to create socket: " << strerror(errno) << std::endl;
        return -1;
    }

    struct sockaddr_in server_addr;
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    server_addr.sin_port = htons(8080);

    if (connect(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
        std::cerr << "Failed to connect to server: " << strerror(errno) << std::endl;
        close(sockfd);
        return -1;
    }

    char buf[1024];
    memset(buf, 0, sizeof(buf));
    strcpy(buf, "Hello, server!");

    struct iovec iov[1];
    iov[0].iov_base = buf;
    iov[0].iov_len = strlen(buf);

    struct msghdr msg;
    memset(&msg, 0, sizeof(msg));
    msg.msg_iov = iov;
    msg.msg_iovlen = 1;

    char controlbuf[CONTROLLEN];
    memset(controlbuf, 0, sizeof(controlbuf));
    struct cmsghdr* cmptr;
    cmptr = (struct cmsghdr*)controlbuf;
    cmptr->cmsg_level = SOL_SOCKET;
    cmptr->cmsg_type = SCM_RIGHTS;
    cmptr->cmsg_len = CONTROLLEN;
    int fd = 12345;
    *(int*)CMSG_DATA(cmptr) = fd;
    msg.msg_control = cmptr;
    msg.msg_controllen = CONTROLLEN;

    if (sendmsg(sockfd, &msg, 0) < 0) {
        std::cerr << "Failed to send message: " << strerror(errno) << std::endl;
        close(sockfd);
        return -1;
    }

    close(sockfd);

    return 0;
}

在上述代码中,我们创建了一个socket连接到服务器,然后构造了一个消息msg,其中包含了一个数据缓冲区iov和一个控制信息cmptr。在构造控制信息cmptr时,我们将一个文件描述符fd放入CMSG_DATA(cmptr)中,然后将cmptr赋值给msg.msg_control。最后,我们通过sendmsg函数将这个消息发送给服务器。

需要注意的是,在接收端需要使用recvmsg函数来接收消息,并从msg.msg_control中提取出控制信息。具体实现可以参考以下代码:

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

#define CONTROLLEN CMSG_LEN(sizeof(int))

int main() {
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) {
        std::cerr << "Failed to create socket: " << strerror(errno) << std::endl;
        return -1;
    }

    struct sockaddr_in server_addr;
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    server_addr.sin_port = htons(8080);

    if (connect(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
        std::cerr << "Failed to connect to server: " << strerror(errno) << std::endl;
        close(sockfd);
        return -1;
    }

    char buf[1024];
    memset(buf, 0, sizeof(buf));
    strcpy(buf, "Hello, server!");

    struct iovec iov[1];
    iov[0].iov_base = buf;
    iov[0].iov_len = strlen(buf);

    struct msghdr msg;
    memset(&msg, 0, sizeof(msg));
    msg.msg_iov = iov;
    msg.msg_iovlen = 1;

    char controlbuf[CONTROLLEN];
    memset(controlbuf, 0, sizeof(controlbuf));
    msg.msg_control = controlbuf;
    msg.msg_controllen = CONTROLLEN;

    if (sendmsg(sockfd, &msg, 0) < 0) {
        std::cerr << "Failed to send message: " << strerror(errno) << std::endl;
        close(sockfd);
        return -1;
    }

    close(sockfd);

    int listenfd = socket(AF_INET, SOCK_STREAM, 0);
    if (listenfd < 0) {
        std::cerr << "Failed to create listen socket: " << strerror(errno) << std::endl;
        return -1;
    }

    struct sockaddr_in listen_addr;
    memset(&listen_addr, 0, sizeof(listen_addr));
    listen_addr.sin_family = AF_INET;
    listen_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    listen_addr.sin_port = htons(8081);

    if (bind(listenfd, (struct sockaddr*)&listen_addr, sizeof(listen_addr)) < 0) {
        std::cerr << "Failed to bind listen socket: " << strerror(errno) << std::endl;
        close(listenfd);
        return -1;
    }

    if (listen(listenfd, 10) < 0) {
        std::cerr << "Failed to listen on listen socket: " << strerror(errno) << std::endl;
        close(listenfd);
        return -1;
    }

    int connfd = accept(listenfd, NULL, NULL);
    if (connfd < 0) {
        std::cerr << "Failed to accept connection: " << strerror(errno) << std::endl;
        close(listenfd);
        return -1;
    }

    struct msghdr msg2;
    memset(&msg2, 0, sizeof(msg2));
    iov[0].iov_base = buf;
    iov[0].iov_len = sizeof(buf);
    msg2.msg_iov = iov;
    msg2.msg_iovlen = 1;
    msg2.msg_control = controlbuf;
    msg2.msg_controllen = CONTROLLEN;

    if (recvmsg(connfd, &msg2, 0) < 0) {
        std::cerr << "Failed to receive message: " << strerror(errno) << std::endl;
        close(connfd);
        close(listenfd);
        return -1;
    }

    int* fdptr = (int*)CMSG_DATA((struct cmsghdr*)controlbuf);
    int fd = *fdptr;
    std::cout << "Received file descriptor: " << fd << std::endl;

    close(fd);
    close(connfd);
    close(listenfd);

    return 0;
}

在上述代码中,我们先创建一个socket连接到服务器,然后发送一个带有控制信息的消息。接着,我们创建一个监听socket,等待客户端连接。当客户端连接成功后,我们使用recvmsg函数从客户端接收消息,并从msg.msg_control中提取出控制信息。最后,我们从控制信息中获取到文件描述符,并关闭它。

需要注意的是,在实际使用中,我们还需要对msg.msg_control中的控制信息进行合法性检查,以避免安全漏洞。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_WAWA鱼_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值