linux sendto 源码,Linux内核源代码解析——用户发送数据包的起源之sendto

Jack:我想知道用户如何把数据发送到内核空间的?

我:你觉得哪里比较难理解呢?

Jack:一般程序员会在程序里通过socket变量获得一个文件描述符,然后通过write把定义好的字符串写入到该描述符。

我:是的。你有什么不明白的吗?

Jack:可是,我不知道这个write底层到底会做什么。

我:这个write底层会调用sock_send函数。我给你看一下这个函数的定义。

static int

sock_send(int fd, void * buff, int len, unsigned flags)

{

struct socket *sock;

struct file *file;

DPRINTF((net_debug,

"NET: sock_send(fd = %d, buff = %X, len = %d, flags = %X)

",

fd, buff, len, flags));

if (fd < 0 || fd >= NR_OPEN || ((file = current->filp[fd]) == NULL))

return(-EBADF);

if (!(sock = sockfd_lookup(fd, NULL))) return(-ENOTSOCK);

return(sock->ops->send(sock, buff, len, (file->f_flags & O_NONBLOCK), flags));

}

sock_send函数通过用户传入的socket描述符fd找到对应的struct socket结构,然后把找到的socket结构。然后把socket结构(sock),buff(这是一个逻辑地址),以及文件flag传入传输层的对应函数。

最后一个语句return调用了一个函数指针(

这就是函数指针的妙处!),这个函数指针如果对应下面的传输层协议是UDP协议,就会调用udp_sendto.

static int

udp_write(struct sock *sk, unsigned char *buff, int len, int noblock,

unsigned flags)

{

return(udp_sendto(sk, buff, len, noblock, flags, NULL, 0));

}

其实是一个包裹函数。干活儿的是udp_sendto。

static int

udp_sendto(struct sock *sk, unsigned char *from, int len, int noblock,

unsigned flags, struct sockaddr_in *usin, int addr_len)

{

struct sockaddr_in sin;

int tmp;

int err;

DPRINTF((DBG_UDP, "UDP: sendto(len=%d, flags=%X)

", len, flags));

/* Check the flags. */

if (flags)

return(-EINVAL);

if (len < 0)

return(-EINVAL);

if (len == 0)

return(0);

/* Get and verify the address. */

if (usin) {

if (addr_len < sizeof(sin)) return(-EINVAL);

err=verify_area(VERIFY_READ, usin, sizeof(sin));

if(err)

return err;

memcpy_fromfs(&sin, usin, sizeof(sin));

if (sin.sin_family && sin.sin_family != AF_INET)

return(-EINVAL);

if (sin.sin_port == 0)

return(-EINVAL);

} else {

if (sk->state != TCP_ESTABLISHED) return(-EINVAL);

sin.sin_family = AF_INET;

sin.sin_port = sk->dummy_th.dest;

sin.sin_addr.s_addr = sk->daddr;

}

if(!sk->broadcast && chk_addr(sin.sin_addr.s_addr)==IS_BROADCAST)

return -EACCES;/* Must turn broadcast on first */

sk->inuse = 1;

/* Send the packet. */

tmp = udp_send(sk, &sin, from, len);

/* The datagram has been sent off.  Release the socket. */

release_sock(sk);

return(tmp);

}

这其实也是一个包裹函数,真正干活的是udp_send函数。

static int

udp_send(struct sock *sk, struct sockaddr_in *sin,

unsigned char *from, int len)

{

struct sk_buff *skb;

struct device *dev;

struct udphdr *uh;

unsigned char *buff;

unsigned long saddr;

int size, tmp;

int err;

DPRINTF((DBG_UDP, "UDP: send(dst=%s:%d buff=%X len=%d)

",

in_ntoa(sin->sin_addr.s_addr), ntohs(sin->sin_port),

from, len));

err=verify_area(VERIFY_READ, from, len);

if(err)

return(err);

/* Allocate a copy of the packet. */

size = sizeof(struct sk_buff) + sk->prot->max_header + len;

skb = sk->prot->wmalloc(sk, size, 0, GFP_KERNEL);

if (skb == NULL) return(-ENOMEM);

skb->mem_addr = skb;

skb->mem_len = size;

skb->sk = NULL;/* to avoid changing sk->saddr */

skb->free = 1;

skb->arp = 0;

/* Now build the IP and MAC header. */

buff = skb->data;

saddr = 0;

dev = NULL;

DPRINTF((DBG_UDP, "UDP: >> IP_Header: %X -> %X dev=%X prot=%X len=%d

",

saddr, sin->sin_addr.s_addr, dev, IPPROTO_UDP, skb->mem_len));

tmp = sk->prot->build_header(skb, saddr, sin->sin_addr.s_addr,

&dev, IPPROTO_UDP, sk->opt, skb->mem_len,sk->ip_tos,sk->ip_ttl);

skb->sk=sk;/* So memory is freed correctly */

if (tmp < 0 ) {

sk->prot->wfree(sk, skb->mem_addr, skb->mem_len);

return(tmp);

}

buff += tmp;

saddr = dev->pa_addr;

DPRINTF((DBG_UDP, "UDP: >> MAC+IP len=%d

", tmp));

skb->len = tmp + sizeof(struct udphdr) + len;/* len + UDP + IP + MAC */

skb->dev = dev;

#ifdef OLD

/*

* This code used to hack in some form of fragmentation.

* I removed that, since it didn't work anyway, and it made the

* code a bad thing to read and understand. -FvK

*/

if (len > dev->mtu) {

#else

if (skb->len > 4095)

{

#endif

printk("UDP: send: length %d > mtu %d (ignored)

", len, dev->mtu);

sk->prot->wfree(sk, skb->mem_addr, skb->mem_len);

return(-EMSGSIZE);

}

/* Fill in the UDP header. */

uh = (struct udphdr *) buff;

uh->len = htons(len + sizeof(struct udphdr));

uh->source = sk->dummy_th.source;

uh->dest = sin->sin_port;

buff = (unsigned char *) (uh + 1);

/* Copy the user data. */

memcpy_fromfs(buff, from, len);

/* Set up the UDP checksum. */

udp_send_check(uh, saddr, sin->sin_addr.s_addr, skb->len - tmp, sk);

/* Send the datagram to the interface. */

sk->prot->queue_xmit(sk, dev, skb, 1);

return(len);

}

这个函数里真正干活的是memcpy_fromfs函数,执行完了这个函数,数据就已经从用户空间拷贝到内核空间了。

之后的sk->prot->queue_xmit(sk, dev, skb, 1);通过函数指针把sk上的skb这个数据包排入发送队列。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/552326.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

仓库处理中 无法修改_临沂用友U8erp系统软件如何新增仓库?

存货一般是用仓库来保管的&#xff0c;对存货进行核算管理&#xff0c;首先应对仓库进行管理&#xff0c;因此进行仓库设置是供销链管理系统的重要基础准备工作之一。第一次使用本系统时&#xff0c;应先将本单位使用的仓库&#xff0c;预先输入到系统之中&#xff0c;即进行&q…

linux变量最大长度,51CTO博客-专业IT技术博客创作平台-技术成就梦想

变量操作总结&#xff1a;${Var:-Value} 变量Var 为unset 或 null 则输出Value。 有值则输出变量Var的值。${Var:Value} 变量Var 为unset 或 null 则输出Value&#xff0c;并且赋值于变量Var。 同上。${Var:Value} 变量Var 为unset 或 null 则输出变量…

Dreamwear如何创建javascript_JavaScript 太糟糕,JVM 有妙招!

虽然 JavaScript 凭借其简洁性、交互性等优势横扫了各大编程语言榜单&#xff0c;但是一直以来&#xff0c;JavaScript 应用程序的工具链极其复杂&#xff0c;引发不少开发者吐槽&#xff0c;在此&#xff0c;我们是否有更好的解决方案将其替代&#xff1f;接下来&#xff0c;本…

linux mint 18.3浏览器,在Linux Mint 19/Ubuntu 18.04中安装Tor Browser浏览器的方法

本文介绍在Linux Mint 19/Ubuntu 18.04系统中安装Tor Browser浏览器的方法&#xff0c;本文不使用Tor的默认Ubuntu存储库&#xff0c;因为它们包含旧版本的Tor。一、添加Tor存储库要在Linux Mint 19/Ubuntu 18.04系统中安装最新版本的Tor&#xff0c;我们将使用官方Tor Apt存储…

code block怎样实现图形界面_微服务入门:Openresty实现API网关

概念介绍如果大家清楚“网关”这个概念&#xff0c;那就很容易理解“API网关“&#xff0c;即所有API的入口。 从面向对象设计的角度看&#xff0c;它与外观模式类似&#xff0c;封装了系统内部架构。在单体应用架构中&#xff0c;没有「 API网关 」的概念&#xff0c;每个项目…

linux mei swap,Linux swapoff命令

Linux swapoff命令Linux swapoff命令用于关闭系统交换区(swap area)。swapoff实际上为swapon的符号连接&#xff0c;可用来关闭系统的交换区。语法swapoff [设备]参数&#xff1a;-a 将/etc/fstab文件中所有设置为swap的设备关闭-h 帮助信息-V 版本信息实例显示分区信息:# sfdi…

vue lang_推荐一个基于Vue 的 H5 快速开发模板

关注 Vue社区&#xff0c;回复“加群”加入我们一起学习&#xff0c;天天进步praisejuejin.im/post/5e612534e51d4527017971a2模板基于 vue-cli4 和 Vant-ui 搭建&#xff0c;进行大型 H5 项目开发最佳实践方案&#xff0c;让我们来一探究竟模板地址 (github.com/push-over/vue…

c语言判断字符是汉字,c语言里面判断字符是否为汉字

这是跟汉字的存储方式有关&#xff0c;西文字符用ASCII码的话&#xff0c;一个字节可以表示一个字符&#xff0c;而汉字用的是双字节表示一个汉字。那么&#xff0c;为了在机器内部区分ASCII码和汉字机内码&#xff0c;就规定汉字的两个字节的最高为都为1.例如&#xff1a;汉字…

springboot urlresource_Spring Boot上传文件+部署到Tomcat

1 概述Spring Boot上传文件,根据官方uploadfile示例修改的,可以打成war放到服务器上(笔者使用的是Tomcat).主要步骤是创建异常类,属性类,接口类与控制器类,最后进行少量修改打包部署到服务器上.2 环境win10Tomcat 9.0.30IDEA 2019.03Spring boot 2.2.2 RELEASE3 新建工程选择sp…

alc236黑苹果驱动_台式机黑苹果独显驱动

黑苹果安装离不开黑苹果驱动程序&#xff0c;常见的有网卡驱动、显卡驱动、声卡驱动、还有其他的一些常用的驱动程序&#xff0c;这里我们单独讲一下黑苹果上驱动英伟达GTX的独显驱动&#xff0c;即我们平常说的N卡&#xff0c;如果文章中介绍的有错误&#xff0c;或者您还有其…

c语言课设报告时钟vc环境,C语言课程设计报告模拟时钟转动程序.doc

C语言课程设计报告模拟时钟转动程序PAGE课程设计报告题 目课 程 名 称 结构化程序设计课程设计院 部 名 称专 业班 级学 生 姓 名 王蕾学 号课程设计地点课程设计学时指 导 教 师金陵科技学院教务处制目 录TOC \o "1-3" \h \z \u HYPERLINK \l "_Toc282443576&q…

c语言break在if中用法,break可用于什么语句 break语句可用于for语句和if语句中 对吗...

c语言中break语句的作用C语言中&#xff0c;break都可以用在什么地方&#xff1f;用到每一个语...break 一般是针对一个循环或者switch中的case,表示跳出当前的循环或选择&#xff0c;即在一个单层循环中&#xff0c;可以通过break 来跳出循环&#xff0c;在switch 中的case通过…

python简单实用案例_Python 21 Django 实用小案例1

8 9 10 {% csrf_token %}11 用户名&#xff1a;12 密码&#xff1a;13 验证码&#xff1a;14 15 16 17

c语言的一段程序,C语言第一个程序(入门)

1.文件类型(基本)c语言源文件 为.c 文件扩展名&#xff0c;例如 main.c 编译后将得到 a.out 文件 运行会得到 我们程序执行的结果2.hello world (第一个程序)#include --------------------> 引入标准库的信息main () { …

matlab table中的文字转string_MATLAB_GUI_教程(2)pushbutton

目录前言上期教程按钮介绍按钮(pushbutton)如何在窗口中创建一个按钮常用属性常用属性练习回调函数的编写规则设置回调函数&#xff1a;定义(编写)回调函数&#xff1a;NoteGUI中各个回调函数之间数据的传递setappdatagetappdata方法按钮的回调函数前言上期教程按钮介绍这个按钮…

c语言数码管的动态显示时间,8位数码管动态显示时间,可调节,调节的数闪烁显示...

原标题&#xff1a;8位数码管动态显示时间&#xff0c;可调节&#xff0c;调节的数闪烁显示// 时间&#xff0c;可调节&#xff0c;//调节时间时&#xff0c;调节的数闪烁显示&#xff1b;//比较两种闪烁的方法&#xff1b;#include#define uint unsigned int#define uchar uns…

python中类和对象_Python里的类和对象简介

---恢复内容开始--- Python里的类 对象属性方法&#xff1b; 对象的属性主要是指主要的特征和参量&#xff0c;而方法主要是指函数&#xff1b; 类是一个具有一定特征和方法的集合&#xff0c;而对象是类的一个&#xff1b;类和对象的关系就如同模具和用这个模具制作出的物品之…

r语言 fread函数参数_R语言 第4章 初级绘图(6)

分析数据间的关系散点矩阵图如果数据框是多维数据&#xff0c;那么plot函数将绘制出两两之间散点图组合成为散点矩阵图(matrix of scatterplots)。散点矩阵图将多个散点图组合起来&#xff0c;以便可以同时浏览多个二元变量关系&#xff0c;一定程度上克服了在平面上展示高维数…

android 渠道打包工具,Android渠道打包技术小结

导读本文对比了渠道4种渠道打包方式:与iOS的单一渠道(AppStore)不同&#xff0c;Android平台在国内的渠道多入牛毛。以我们的App为例&#xff0c;就有27个普通渠道(应用宝&#xff0c;百度&#xff0c;360这种)和更多的推广专用渠道。我们打包技术也经过了若干次的改进。1.利用…

机械臂中的四元素转为旋转矩阵_雅克比矩阵(上)雅克比推导

1、前言 回顾前面几期的内容&#xff0c;在第一期中介绍了机器人的正/逆运动学建模&#xff0c;正运动学解决的问题是如何从关节空间的关节变量描述操作空间的位姿&#xff0c;反之则是逆运动学的内容。将操作空间和关节的空间的关系用以下关系式进行表达。机器人正/逆运动…