内核中用于数据接收的结构体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标志,即带外数据。

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

  1. C#中的元组(Tuple)和结构体(struct)

    在正常的函数调用中,一个函数只能返回一个类型的值,但在某些特殊情况下,我们可能需要一个方法返回多个类型的值,除了通过ref,out或者泛型集合可以实现这种需求外,今天,讲一下元组和结构体在这一方面的应 ...

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

    在开发过程中,经常会需要处理一组不同类型的数据,比如学生的个人信息,由姓名.年龄.性别.身高等组成,因为这些数据是由不同数据类型组成的,因此不能用数组表示,对于不同数据类型的一组数据,可以采用结构体来 ...

  3. 字符设备驱动1:新的方式添加cdev + 在open函数中将文件私有数据指向设备结构体

    本例中,驱动入口处,使用cdev_add添加驱动,这点也可与字符设备驱动0:一个简单但完整的字符设备驱动程序对比一下. 另外主要讲xx_open实现文件私有数据指向设备结构体. 引子: 偶然看到,在j ...

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

    Swift有许多种存储数据方式,你可以用枚举(enums),元组(tuples),结构体(structs),类(classes),在这篇文章中我们将比较枚举.元组.结构体之间区别,首先从最简单的开始- ...

  5. 《挑战30天C++入门极限》C/C++中结构体(struct)知识点强化

        C/C++中结构体(struct)知识点强化 在上一个教程中我们已经简单的阐述了什么是结构体了,为了进一部的学习结构体这一重要的知识点,我们今天来学习一下链表结构. 结构体可以看做是一种自定义 ...

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

    查看hive中action_data_myisam表中的数据.表结构及所在路径 1.客户端进入hive环境:hive 2.查看表数据,鉴于数据量大,这里只显示前五条:select * from act ...

  7. Go语言结构体(struct)

    Go 语言结构体 Go 语言中数组可以存储同一类型的数据,但在结构体中我们可以为不同项定义不同的数据类型. 结构体是由一系列具有相同类型或不同类型的数据构成的数据集合. 结构体表示一项记录,比如保存图 ...

  8. go语言之行--结构体(struct)详解、链表

    一.struct简介 go语言中没有像类的概念,但是可以通过结构体struct实现oop(面向对象编程).struct的成员(也叫属性或字段)可以是任何类型,如普通类型.复合类型.函数.map.int ...

  9. C# 结构体 struct

    C# 结构体 struct C#中结构类型和类类型在语法上非常相似,他们都是一种数据结构,都可以包括数据成员和方法成员. 结构和类的区别: 1.结构是值类型,它在栈中分配空间:而类是引用类型,它在堆中 ...

随机推荐

  1. sql 2005,2008开启bcp的方法嗯哈步骤

    sqlserver 2008开启bcp服务的方法和步骤 sqlserver 2005开启bcp服务的方法和步骤 在开始菜单中找到sql server 2005 -->> 配置工具 --&g ...

  2. [原创]svn 常见错误总结

    错误: Unable to make name in 'X:\nfs\drivers\can_uart\.svn\tmp' 解决: 改变当前文件夹的权限 linux 下显示修改的文件名 参考链接:ht ...

  3. Android Fragment完全解析,关于碎片你所需知道的一切

    转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/8881711 我们都知道,Android上的界面展示都是通过Activity实现的, ...

  4. nginx命令

    window  cmd 到nginx的文件夹 start nginx    启动命令 nginx -s reload 重新启动 nginx -s stop   关闭   linux   到 sbin ...

  5. scoll滚动

    [前端性能]高性能滚动 scroll 及页面渲染优化   最近在研究页面渲染及web动画的性能问题,以及拜读<CSS SECRET>(CSS揭秘)这本大作. 本文主要想谈谈页面优化之滚动优 ...

  6. Android开发学习笔记--计时器的应用实例

    为了了解安卓计时器的用法,写了一个秒表的应用,正是这个秒表,让我对Android应用的速度大跌眼镜,我设置了一个计时器,10ms更新一次显示的时间,然后更标准的时间一比较发现,跑10s就有一秒的时间误 ...

  7. iOS开发——网络篇——文件下载(NSMutableData、NSFileHandle、NSOutputStream)和上传、压缩和解压(三方框架ZipArchive),请求头和请求体格式,断点续传Range

    一.小文件下载 NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/images/minion ...

  8. Java常见的几种排序算法-插入、选择、冒泡、快排、堆排等

    本文就是介绍一些常见的排序算法.排序是一个非常常见的应用场景,很多时候,我们需要根据自己需要排序的数据类型,来自定义排序算法,但是,在这里,我们只介绍这些基础排序算法,包括:插入排序.选择排序.冒泡排 ...

  9. Ebase Xi The world's best RAD platform.

    Ebase Xi : http://www.ebasetech.com/ The world's best RAD platform. Xi combines browser and mobile a ...

  10. struts2 action 3中书写方式

    1.pojo类   简单的javabean 类 需要有 public String execute(){return null;} 2.实现 Action 借口  重写 execute 3.继承 Ac ...