struct msghdr 和 struct cmsghdr的详细介绍及个别IO操作函数

struct msghdr 和 struct cmsghdr的详细介绍及个别IO操作函数

首先,我们从一个实际的数据包发送的例子入手,来看看其发送的具体流程,以及过程中涉及到的相关数据结构;在我们的虚拟机上发送icmp回显请求包,ping另一台主机192.168.1.111。我们使用系统调用sendto发送这个icmp包。

ssize_t sendto(int s, const void *buf, size_t len, int

flags,

const struct sockaddr *to, socklen_t tolen);

系统调用sendto最终调用内核函数asmlinkage

long sys_sendto(int fd, void __user * buff, size_t

len,unsigned flags, struct

sockaddr __user *addr, int addr_len)

sys_sendto构建一个结构体struct

msghdr,用于接收来自应用层的数据包,下面是结构体struct msghdr的定义:

struct msghdr {

void

*msg_name;//存数据包的目的地址,网络包指向struct

sockaddr_in

//向内核发数据时,指向struct sockaddr_nl

int

msg_namelen;//地址长度,一般为16

struct iovec

*msg_iov;

__kernel_size_t msg_iovlen;

void

*msg_control;

__kernel_size_t

msg_controllen;

unsigned

msg_flags;

};

这个结构体的内容可以分为四组:

第一组是msg_name和msg_namelen,记录这个消息的名字,其实就是数据包的目的地址。msg_name是指向一个结构体struct

sockaddr的指针。长度为16:

struct sockaddr{

sa_family_t sa_family;

char

sa_addr[14];

}

所以,msg_namelen的长度为16。需要注意的是,结构体struct

sockaddr只在进行参数传递时使用,无论是在用户态还是在内核态,我们都把其强制转化为结构体struct

sockaddr_in:

strcut sockaddr_in{

sa_family_t

sin_family;

unsigned short int sin_port;

struct

in_addr

sin_addr;

unsigned

char

__pad[__SOCK_SIZE__ - sizeof(short int) -

sizeof(unsigned short int) - sizeof(struct in_addr)];

};

struct in_addr{

__u32 s_addr;

}

__SOCK_SIZE__的值为16,所以,struct

sockaddr中真正有用的数据只有8bytes。在我们的ping例子中,传入到内核的msghdr结构中:

msg.msg_name = { sa_family_t = MY_AF_INET,

sin_port = 0, sin_addr.s_addr = 172.16.48.1

}

msg_msg_namelen = 16。

请求回显icmp包没有目的端地址的端口号。

第二组是msg_iov和msg_iovlen,记录这个消息的内容。msg_iov是一个指向结构体struct

iovec的指针,实际上,确切地说,应该是一个结构体strcut

iovec的数组。#include<sys/uio.h>头文件定义了struct

iovc,其定义如下:

struct iovec{

void

__user

*iov_base;

__kernel_size_t iov_len;

};

iov_base指向数据包缓冲区,即参数buff,iov_len是buff的长度。msghdr中允许一次传递多个buff,以数组的形式组织在

msg_iov中,msg_iovlen就记录数组的长度(即有多少个buff)。在我们的ping程序的实例中:

msg.msg_iov = { struct iovec = { iov_base = { icmp头+填充字符'E' },

iov_len = 40 } }

msg.msg_len = 1

第三组是msg_control和msg_controllen,它们可被用于发送任何的控制信息,在我们的例子中,没有控制信息要发送。暂时略过。

第四组是msg_flags。其值即为传入的参数flags。raw协议不支持MSG_OOB向标志,即带外数据。向向内核发送msg时使用msghdr,netlink

socket使用自己的消息头nlmsghdr和自己的消息地址sockaddr_nl:

struct sockaddr_nl

{

sa_family_t

nl_family;

unsigned short nl_pad;

__u32

nl_pid;

__u32

nl_groups;

};

struct nlmsghdr

{

__u32 nlmsg_len;

__u16 nlmsg_type;

__u16 nlmsg_flags;

__u32 nlmsg_seq;

__u32 nlmsg_pid;

};

过程如下:

struct msghdr msg; memset(&msg, 0,

sizeof(msg)); msg.msg_name = (void

*)&(nladdr); msg.msg_namelen =

sizeof(nladdr);

{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)

相关推荐

zte中兴手机a1
亚洲365bet备用

zte中兴手机a1

📅 07-30 👀 2347
如何对计算机上没有声音的问题进行故障处理或解决计算机音频问题
精選法國十大必去絕美城市-除了巴黎之外你還去過哪些?
八马茶业完成港股上市备案 为中国最大的高端茶企
【深度解读】为什么众多中国企业都选择赴美国上市?
beat365亚洲体育在线

【深度解读】为什么众多中国企业都选择赴美国上市?

📅 07-18 👀 1634
错别字第2期:今天推出:常见错别字1000例,可以直接复制
yy怎么设置密码房间 yy设置密码频道方法介绍
亚洲365bet备用

yy怎么设置密码房间 yy设置密码频道方法介绍

📅 07-12 👀 807
「梦幻西游」瞬法怎么洗到百分百
365bet官方网址

「梦幻西游」瞬法怎么洗到百分百

📅 07-22 👀 8503
企业银行账号是几位数
365bet官方网址

企业银行账号是几位数

📅 06-27 👀 4948