struct msghdr 和 struct cmsghdr的详细介绍及个别IO操作函数
(2013-03-01 15:16:48)
标签:
structmsghdr和structio操作函数 |
分类: 网络编程 |
所以,msg_namelen的长度为16。需要注意的是,结构体struct sockaddr只在进行参数传递时使用,无论是在用户态还是在内核态,我们都把其强制转化为结构体struct sockaddr_in:
__SOCK_SIZE__的值为16,所以,struct sockaddr中真正有用的数据只有8bytes。在我们的ping例子中,传入到内核的msghdr结构中:
请求回显icmp包没有目的端地址的端口号。
struct sockaddr_nl
{
sa_family_t
unsigned short nl_pad;
__u32
__u32
};
struct nlmsghdr
{
__u32 nlmsg_len;
__u16 nlmsg_type;
__u16 nlmsg_flags;
__u32 nlmsg_seq;
__u32 nlmsg_pid;
};
过程如下:
struct msghdr msg;
{
char buffer[] = "An
example message";
struct nlmsghdr nlhdr;
nlhdr = (struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_MSGSIZE));
strcpy(NLMSG_DATA(nlhdr),buffer);//将数据存放在消息头指向的数据地址
nlhdr->nlmsg_len
= NLMSG_LENGTH(strlen(buffer));
nlhdr->nlmsg_pid = getpid();
nlhdr->nlmsg_flags = 0;
iov.iov_base = (void *)nlhdr;
iov.iov_len = nlh->nlmsg_len;
}
msg.msg_iov =
&iov;
msg.msg_iovlen = 1;
fd=socket(AF_NETLINK, SOCK_RAW, netlink_type);
sendmsg(fd,&msg,0)
简介I/O向量
I/O向量(struct iovec)
readv(2)与writev(2)函数
#include
这些函数需要三个参数:
使用writev的例子
下面的程序代码展示了如何使用writev函数将三个独立的C字符串作为一次写操作写入标准输出。
#include
int main(int argc,char **argv)
{
}
编译运行程序:
$ gcc
$ ./writev
[THIS IS FROM WRITEV]
$
也许我们希望多花一些时间来修改这个程序并做各种测试,但是要注意一定要将iov[ ]数组分配得足够大。
sendmsg(2)与recvmsg(2)函数
sendmsg(2)函数
函数
write
send
sendto
writev
sendmsg
sendmsg(2)函数原型如下:
函数参数描述如下:
recvmsg(2)函数
函数参数如下:
要在其上接收信息的套接口s
信息头结构指针msg,这会控制函数调用的操作。
可选标记位参数flags。这与recv或是recvfrom函数调用的标记参数相同。
这个函数的返回值为实际接收的字节数。否则,返回-1表明发生了错误,而errno表明错误原因。
理解struct msghdr
当我第一次看到他时,他看上去似乎是一个需要创建的巨大的结构。但是不要怕。其结构定义如下:
struct msghdr {
};
成员msg_name与msg_namelen
当调用recvmsg时,msg_name会指向一个将要接收的地址的接收区域。当调用sendmsg时,这会指向一个数据报将要发送到的目的地址。
注意,msg_name定义为一个(void *)数据类型。我们并不需要将我们的套接口地址转换为(struct sockaddr *)。
成员msg_iov与msg_iovlen
成员msg_control与msg_controllen
成员msg_flags
标记位
MSG_EOR
MSG_TRUNC
MSG_CTRUNC
MSG_OOB
MSG_ERRQUEUE
我们可以在recvmsg(2)与sendmsg(2)的man手册页中查看更多的信息。
附属数据结构与宏
简介struct
下图显示了一个包含附属数据的缓冲区是如何组织的。
控制信息头部本身由下面的C结构定义:
其成员描述如下:
这一章所用的例子程序只使用SOL_SOCKET的cmsg_level值。这一章我们感兴趣的控制信息类型如下(cmsg_level=SOL_SOCKET):
简介cmsg(3)宏
#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);
void *CMSG_DATA(struct cmsghdr *cmsg);
CMSG_LEN()宏
下面的例子演示了如果附属数据是一个文件描述符,我们应如何来计算cmsg_len成员的值:
int fd;
printf("cmsg_len = %d\n",CMSG_LEN(sizeof fd));
CMSG_SPACE()宏
int fd;
char abuf[CMSG_SPACE(sizeof fd)];
这个例子在abuf[]中声明了足够的缓冲区空间来存放头部,填充字节以及附属数据本身,和最后的填充字节。如果在缓冲区中有多个附属数据对象,一定要同时添加多个CMSG_SPACE()宏调用来得到所需的总空间。
CMSG_DATA()宏
struct cmsgptr *mptr;
int fd;
. . .
fd = *(int *)CMSG_DATA(mptr);
CMSG_ALIGN()宏
CMSG_FIRSTHDR()宏
msghdr结构的指针(不要与struct
CMSG_NXTHDR()宏
遍历附属数据