当前位置: 技术问答>linux和unix
为什么linux中sendto函数中的msg.msg_iovlen=1;
来源: 互联网 发布时间:2017-02-27
本文导语: 为什么linux中sendto函数中的msg.msg_iovlen=1; | 内核中定义的sys_sendto的源码吗? 这个属于sendmsg中struct msghdr的用法问题, sys_sendto函数最终调用的是sock_sendmsg int sock_sendmsg(struct socket *sock, struct ms...
为什么linux中sendto函数中的msg.msg_iovlen=1;
|
内核中定义的sys_sendto的源码吗?
这个属于sendmsg中struct msghdr的用法问题, sys_sendto函数最终调用的是sock_sendmsg
int sock_sendmsg(struct socket *sock, struct msghdr *msg, size_t size);
而用户空间的函数sendmsg是直接调用的内核中的sock_sendmsg,
ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
这两个函数同时支持tcp和udp , 当然还有别的像unix域等。
其中struct iovec的定义
struct iovec
{
void *iov_base; /* Pointer to data. */ //用户sendto中的ptr就是赋值到此
size_t iov_len; /* Length of data. */ //用户sendto中的长度就是赋值到此
};
不知道LZ知不知道writev函数,一次能从多个指针的地方写入数据。
msg.msg_iovlen = 1就是指msg.msg_iov的指针指向的地方只有一个struct iovec结构体。
sendto一次只能从一个ptr发送长度为len的东西,故只用定义一个struct iovec iov[1];
msg_iovlen就是指struct iovec的个数。
例子:
如果你想用sendmsg发送ptr1 , len1 ; ptr2, len2的数据。 传统做法是将ptr1 和 ptr2的数据都拷贝到一起。
如 char *ptr = (char*)malloc(len1 + len2);
memcpy(ptr , ptr1 , len1) ; memcpy(ptr , ptr2 , len2)
然后用sendto(sockfd , ptr , len1 + len2, 0 , addr , addrlen);
现在用sendmsg就不用拷贝。如下:
struct msghdr msg;
struct iovec iov[2];
iov[0].iov_base = ptr1;
iov[0].iov_len = len1;
iov[1].iov_base = ptr2;
iov[1].iov_len = len2;
memset(&msg , 0 , sizeof(msg));
msg.msg_name = &addr; //tcp 时为NULL
msg.msg_namelen = sizeof(addr); //tcp时为0
msg.msg_iov = iov;
msg.msg_iovlen = 2 ; //!!!!!此处为2!
sendmsg(sockfd , &msg , 0);
//这样就不省了拷贝数据的开锁!
理解struct msghdr中msg_iovlen的意义了吗?
这个属于sendmsg中struct msghdr的用法问题, sys_sendto函数最终调用的是sock_sendmsg
int sock_sendmsg(struct socket *sock, struct msghdr *msg, size_t size);
而用户空间的函数sendmsg是直接调用的内核中的sock_sendmsg,
ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
这两个函数同时支持tcp和udp , 当然还有别的像unix域等。
struct msghdr
{
void *msg_name; /* Address to send to/receive from. */
socklen_t msg_namelen; /* Length of address data. */
struct iovec *msg_iov; /* Vector of data to send/receive into. */
size_t msg_iovlen; /* Number of elements in the vector. */
void *msg_control; /* Ancillary data (eg BSD filedesc passing). */
size_t msg_controllen; /* Ancillary data buffer length.
!! The type should be socklen_t but the
definition of the kernel is incompatible
with this. */
int msg_flags; /* Flags on received message. */
};
其中struct iovec的定义
struct iovec
{
void *iov_base; /* Pointer to data. */ //用户sendto中的ptr就是赋值到此
size_t iov_len; /* Length of data. */ //用户sendto中的长度就是赋值到此
};
不知道LZ知不知道writev函数,一次能从多个指针的地方写入数据。
msg.msg_iovlen = 1就是指msg.msg_iov的指针指向的地方只有一个struct iovec结构体。
sendto一次只能从一个ptr发送长度为len的东西,故只用定义一个struct iovec iov[1];
msg_iovlen就是指struct iovec的个数。
例子:
如果你想用sendmsg发送ptr1 , len1 ; ptr2, len2的数据。 传统做法是将ptr1 和 ptr2的数据都拷贝到一起。
如 char *ptr = (char*)malloc(len1 + len2);
memcpy(ptr , ptr1 , len1) ; memcpy(ptr , ptr2 , len2)
然后用sendto(sockfd , ptr , len1 + len2, 0 , addr , addrlen);
现在用sendmsg就不用拷贝。如下:
struct msghdr msg;
struct iovec iov[2];
iov[0].iov_base = ptr1;
iov[0].iov_len = len1;
iov[1].iov_base = ptr2;
iov[1].iov_len = len2;
memset(&msg , 0 , sizeof(msg));
msg.msg_name = &addr; //tcp 时为NULL
msg.msg_namelen = sizeof(addr); //tcp时为0
msg.msg_iov = iov;
msg.msg_iovlen = 2 ; //!!!!!此处为2!
sendmsg(sockfd , &msg , 0);
//这样就不省了拷贝数据的开锁!
理解struct msghdr中msg_iovlen的意义了吗?