linux recvmsg,sendmsg()与recvmsg()函数

在前面我们介绍了UNIX域套接字编程,更重要的一点是UNIX域套接字可以在同一台主机上各进程之间传递文件描述符。

下面先来看两个函数:

#include #include

ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);

ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);

它们与sendto 和 recvfrom 函数相似,只不过可以传输更复杂的数据结构,不仅可以传输一般数据,还可以传输额外的数据,即文件描述符。下面来看结构体msghdr :

struct msghdr {

void         *msg_name;       /* optional address */

socklen_t     msg_namelen;    /* size of address */

struct iovec *msg_iov;        /* scatter/gather array */

size_t        msg_iovlen;     /* # elements in msg_iov */

void         *msg_control;    /* ancillary data, see below */

size_t        msg_controllen; /* ancillary data buffer len */

int           msg_flags;      /* flags on received message */

};

如下图所示:

uid-97185-id-4449608.html

1、msg_name :即对等方的地址指针,不关心时设为NULL即可;

2、msg_namelen:地址长度,不关心时设置为0即可;

3、msg_iov:是结构体iovec 的指针。

struct iovec {

void  *iov_base;    /* Starting address */

size_t iov_len;     /* Number of bytes to transfer */

};

成员iov_base 可以认为是传输正常数据时的buf,iov_len 是buf 的大小。

4、msg_iovlen:当有n个iovec 结构体时,此值为n;

5、msg_control:是一个指向cmsghdr 结构体的指针

struct cmsghdr {

socklen_t cmsg_len;    /* data byte count, including header */

int       cmsg_level;  /* originating protocol */

int       cmsg_type;   /* protocol-specific type */

/* followed by unsigned char cmsg_data[]; */

};

6、msg_controllen :参见下图,即cmsghdr 结构体可能不止一个;

7、flags : 一般设置为0即可;

为了对齐,可能存在一些填充字节,跟每个系统的实现有关,但我们不必关心,可以通过一些函数宏来获取相关的值,如下:

#include struct cmsghdr *CMSG_FIRSTHDR(struct msghdr *msgh);

struct cmsghdr *CMSG_NXTHDR(struct msghdr *msgh, struct cmsghdr *cmsg);

size_t CMSG_ALIGN(size_t length);

size_t CMSG_SPACE(size_t length);

size_t CMSG_LEN(size_t length);

unsigned char *CMSG_DATA(struct cmsghdr *cmsg);

下面通过封装两个函数,send_fd 和 recv_fd 来进一步认识这些函数宏的作用:

void send_fd(int sock_fd, int send_fd)

{

int ret;

struct msghdr msg;

struct cmsghdr *p_cmsg;

struct iovec vec;

char cmsgbuf[CMSG_SPACE(sizeof(send_fd))];

int *p_fds;

char sendchar = 0;

msg.msg_control = cmsgbuf;

msg.msg_controllen = sizeof(cmsgbuf);

p_cmsg = CMSG_FIRSTHDR(&msg);

p_cmsg->cmsg_level = SOL_SOCKET;

p_cmsg->cmsg_type = SCM_RIGHTS;

p_cmsg->cmsg_len = CMSG_LEN(sizeof(send_fd));

p_fds = (int *)CMSG_DATA(p_cmsg);

*p_fds = send_fd; // 通过传递辅助数据的方式传递文件描述符

msg.msg_name = NULL;

msg.msg_namelen = 0;

msg.msg_iov = &vec;

msg.msg_iovlen = 1; //主要目的不是传递数据,故只传1个字符

msg.msg_flags = 0;

vec.iov_base = &sendchar;

vec.iov_len = sizeof(sendchar);

ret = sendmsg(sock_fd, &msg, 0);

if (ret != 1)

ERR_EXIT("sendmsg");

}

int recv_fd(const int sock_fd)

{

int ret;

struct msghdr msg;

char recvchar;

struct iovec vec;

int recv_fd;

char cmsgbuf[CMSG_SPACE(sizeof(recv_fd))];

struct cmsghdr *p_cmsg;

int *p_fd;

vec.iov_base = &recvchar;

vec.iov_len = sizeof(recvchar);

msg.msg_name = NULL;

msg.msg_namelen = 0;

msg.msg_iov = &vec;

msg.msg_iovlen = 1;

msg.msg_control = cmsgbuf;

msg.msg_controllen = sizeof(cmsgbuf);

msg.msg_flags = 0;

p_fd = (int *)CMSG_DATA(CMSG_FIRSTHDR(&msg));

*p_fd = -1;

ret = recvmsg(sock_fd, &msg, 0);

if (ret != 1)

ERR_EXIT("recvmsg");

p_cmsg = CMSG_FIRSTHDR(&msg);

if (p_cmsg == NULL)

ERR_EXIT("no passed fd");

p_fd = (int *)CMSG_DATA(p_cmsg);

recv_fd = *p_fd;

if (recv_fd == -1)

ERR_EXIT("no passed fd");

return recv_fd;

}

转载地址:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值