内核中用于数据接收的结构体struct msghdr(转)

内核中用于数据接收的结构体struct msghdr(转)

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

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

const struct sockaddr *to, socklen_t tolen);

s就是socket的fd。buf是待发送的icmp数据包,len是buf的长度。flags可以是下列标志位的位或:

MSG_DONTROUTE

在发送分组时,不使用网关,只有直接连接在本网络中的主机才能接收到数据。这个标志通常仅用于诊断和路由程序。可路由的协议族才能使用这个标志;packet sockets不可以使用。

MSG_DONTWAIT

使用非阻塞操作。

MSG_NOSIGNAL

当流式套接字的另一端中断连接时不发送SIGPIPE信号,但仍然返回EPIPE错误。

MSG_CONFIRM (仅用于Linux 2.3以上版本)

通知链路层发生了转发过程:得到了另一端的成功应答。如果链路层没有收到通知,它将按照常规探测网络上的相邻主机(比如通过免费arp)。只能用于 SOCK_DGRAM和SOCK_RAW类型的套接字,且仅对IPv4和IPv6有效。

除此之外,还有MSG_MORE,MSG_OOB,MSG_EOR。

to是这个数据包发送的目地端地址,tolen是to的长度。

系统调用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;

int             msg_namelen;

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的数组。下面是该结构体的定义:

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标志,即带外数据。

时间: 2024-10-12 11:32:38

内核中用于数据接收的结构体struct msghdr(转)的相关文章

读取文件中的数据(以结构体存放)

/* *读取文件中的数据(数据以结构体存放) */ #include<iostream> #include <fstream> //#define Field 31 //field_anal number #define Field 15 //field_post number using namespace std; //the level restore certain level data //level_z show the level struct Level { int

ios开发中的C语言学习—— 结构体简介

在开发过程中,经常会需要处理一组不同类型的数据,比如学生的个人信息,由姓名.年龄.性别.身高等组成,因为这些数据是由不同数据类型组成的,因此不能用数组表示,对于不同数据类型的一组数据,可以采用结构体来进行存储.当然,对于面向对象的语言来说,最好是用类来表示,但是C语言是面向过程的,因此选择用结构体来表示. 一.结构体的定义 struct 结构体名{ 类型名 成员名1; 类型名 成员名2; ... ... 类型名 成员名n; }; 二.结构体的变量声明 1.先定义结构体类型,再定义变量 代码 //

linux 中 C 语言的使用 -- 结构体多态

在 Linux 内核代码,特别是驱动代码中经常见到的用法是使用一个标准结构,后面的代码基于这个结构来实现,类似面向对象的多态特性. 在 C 语言里面借助结构体和函数指针实现的这个功能,这里我们写了个例子,提取了关键代码: #include <stdio.h> struct s_new{ char name[10]; char* (* my_method)(char *name); }; char* powerful(char *name){ printf("%s is powerfu

Swift中元组(Tuples),结构体(Struct),枚举(Enums)之间的区别

Swift有许多种存储数据方式,你可以用枚举(enums),元组(tuples),结构体(structs),类(classes),在这篇文章中我们将比较枚举.元组.结构体之间区别,首先从最简单的开始-元组(tuples). 元组(tuple) 元组是多个值组成的复合值类型,例如,你可以定义一个含有整形和字符串的tuple let amout=(100,"EUR") 当你函数需要返回多个值时,元组这个时候非常有用,你可以使用下标方式来访问元组中的值,如.0,.1以此类推,如下: let

【C/C++学院】0814-引用高级、引用高级增加/auto自动变量自动根据类型创建数据/Bool/Enum/newdelete全局/大数据乘法与结构体/函数模板与auto/宽字符本地化/inline

引用高级.引用高级增加 #include<iostream> #include<stdlib.h> // int a[10] // int (&ra)[10] // int a[2][5] // int (&ra)[2][5] void main1() { int a[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; int(&ra)[10](a);//引用就是给原来的变量有一个别名同一个地址 int i = 0; for (

查看hive中某个表中的数据、表结构及所在路径

查看hive中action_data_myisam表中的数据.表结构及所在路径 1.客户端进入hive环境:hive 2.查看表数据,鉴于数据量大,这里只显示前五条:select * from action_data_myisam limit 5; 3.查看表结构:desc action_data_myisam; 4.查看此表所在路径:describe extended action_data_myisam; 图1针对1.2.3步 图2 针对第4步 end!

修改Dictionary或List中结构体struct值的问题

问题:修改Dictionary中结构体struct值的值,如果直接用Dictionary[key].a += XX;(a为结构体中某数值型属性) ,则会报错: 无法修改.Dictionary<int,struct>.this[int]”的返回值,因为它不是变量 如果用一个变量承接Dictionary[key]中的结构体,即struct newStr =Dictionary[key],然后再做出修改:newStr.a += XX,则Dictionary中对应的结构体的值不发生变化.(由此可判断结

C# 结构体 struct

C# 结构体 struct C#中结构类型和类类型在语法上非常相似,他们都是一种数据结构,都可以包括数据成员和方法成员. 结构和类的区别: 1.结构是值类型,它在栈中分配空间:而类是引用类型,它在堆中分配空间,栈中保存的只是引用. 2.结构类型直接存储成员数据,让其他类的数据位于对中,位于栈中的变量保存的是指向堆中数据对象的引用. C#中的简单类型,如int.double.bool等都是结构类型.如果需要的话,甚至可以使用结构类型结合运算符运算重载,再为C#语言创建出一种新的值类型来. 由于结构

Go语言结构体(struct)

Go 语言结构体 Go 语言中数组可以存储同一类型的数据,但在结构体中我们可以为不同项定义不同的数据类型. 结构体是由一系列具有相同类型或不同类型的数据构成的数据集合. 结构体表示一项记录,比如保存图书馆的书籍记录,每本书有以下属性: title       :书名 author   :作者 address       :地址 mobile         :手机号 publisher     :出版社 定义结构体 结构体定义需要使用 type 和 struct 语句.struct 语句定义一个