scp源码浅析
背景:
- 经常使用scp传文件,发现它真的很给力,好奇心由来已久!
- 恰好接到一个移植SSH服务到专有网络(非IP网络)的小任务,完成工作又能满足好奇心,何乐而不为!
- 我只从源码浅浅的分析一下,后续有更多想法再补充
源码赏析:
1、所有的故事都从main开始,也从main结束。(main也很无辜,它只是打开了计算机的一扇窗):
作为一个命令行工具,命令行是必须要处理的,这里scp也是采用常见的getopt来处理命令行。
while ((ch = getopt(argc, argv, "dfl:prtvBCc:i:P:q12346S:o:F:")) != -)
上面的字符串就是可以使用的命令行选项,带冒号的表示有参数,比如 d 表示可以在shell输入 scp -d ...,l: 表示可以在shell输入 scp -l 1000 ... ,当然这样重点要提到 -r, 加上它就可以递归传输子目录,非常实用,其他参数我就不再详解了。
接下来会看到如下代码:
/* Command to be executed on remote system using "ssh". */
(void) snprintf(cmd, sizeof cmd, "scp%s%s%s%s",
verbose_mode ? " -v" : "",
iamrecursive ? " -r" : "", pflag ? " -p" : "",
targetshouldbedirectory ? " -d" : "");
可以看到,注释里提到了,这是要通过ssh到远程linux系统(你的目的电脑)去执行的一条命令,同样也是scp喔,所以这是scp神奇又方便的原因之一!
它通过ssh连接到目的机器,同样执行了一个scp程序来实现数据通路,完成数据接收或者发送。
注意:上面隐含了2个条件:
(1)你本机或者远程机,两者之间必须有一个ssh服务端
(2)两者都必须有scp这个工具
2、文件的发送和接收
之所以来看scp的源码,也就是对它的文件读写传输很感兴趣,首先看的是如何选择合适大小的块来读写,如下函数:
BUF * allocbuf(BUF *bp, int fd, int blksize)
这个函数就会根据文件大小来分配一个合适的文件块,来分块读写,并网络传输。
函数的返回值是一个结构,用来存放即将分配的内存地址和内存大小。
typedef struct {
size_t cnt;
char *buf;
} BUF;
而这个函数最核心的逻辑就是获取文件的块大小(基于文件系统I/O),并按照预定的块大小来补齐,就像常见的64字节对齐一样,如果你不是64字节的倍数,那就给你补齐。这里scp的预定块大小的补齐是按16384字节来补齐的。
if (fstat(fd, &stb) < ) {
run_err("fstat: %s", strerror(errno));
return ();
}
size = roundup(stb.st_blksize, blksize);
#ifndef roundup
# define roundup(x, y) ((((x)+((y)-))/(y))*(y))
#endif
这里,roundup就是按16384的倍数向上取整了,比如XFS的块大小是512bytes到64KB,EXT3,EXT4的块大小是4KB。
然后就是分配size大小的内存了。
if (bp->cnt >= size)
return (bp);
if (bp->buf == NULL)
bp->buf = xmalloc(size);
else
bp->buf = xreallocarray(bp->buf, , size);
memset(bp->buf, , size);
bp->cnt = size;
然后就是逐块的发送文件了。
set_nonblock(remout);
for (haderr = i = ; i < stb.st_size; i += bp->cnt) {
amt = bp->cnt;
if (i + (off_t)amt > stb.st_size)
amt = stb.st_size - i;
if (!haderr) {
if ((nr = atomicio(read, fd,
bp->buf, amt)) != amt) {
haderr = errno;
memset(bp->buf + nr, , amt - nr);
}
}
/* Keep writing after error to retain sync */
if (haderr) {
(void)atomicio(vwrite, remout, bp->buf, amt);
memset(bp->buf, , amt);
continue;
}
if (atomicio6(vwrite, remout, bp->buf, amt, scpio,
&statbytes) != amt)
haderr = errno;
}
unset_nonblock(remout);
当然,如果设置了-r选项,就会递归处理子目录以及子目录的文件
文件接收方会收到发送方发过来的整个文件大小,然后整个过程就跟发送有点类似了:
set_nonblock(remin);
for (count = i = ; i < size; i += bp->cnt) {
amt = bp->cnt;
if (i + amt > size)
amt = size - i;
count += amt;
do {
j = atomicio6(read, remin, cp, amt,
scpio, &statbytes);
if (j == ) {
run_err("%s", j != EPIPE ?
strerror(errno) :
"dropped connection");
exit();
}
amt -= j;
cp += j;
} while (amt > ); if (count == bp->cnt) {
/* Keep reading so we stay sync'd up. */
if (wrerr == NO) {
if (atomicio(vwrite, ofd, bp->buf,
count) != count) {
wrerr = YES;
wrerrno = errno;
}
}
count = ;
cp = bp->buf;
}
}
unset_nonblock(remin);
参考:
https://en.wikipedia.org/wiki/XFS
https://en.wikipedia.org/wiki/Ext4
scp源码浅析的更多相关文章
- 【深入浅出jQuery】源码浅析--整体架构
最近一直在研读 jQuery 源码,初看源码一头雾水毫无头绪,真正静下心来细看写的真是精妙,让你感叹代码之美. 其结构明晰,高内聚.低耦合,兼具优秀的性能与便利的扩展性,在浏览器的兼容性(功能缺陷.渐 ...
- 【深入浅出jQuery】源码浅析2--奇技淫巧
最近一直在研读 jQuery 源码,初看源码一头雾水毫无头绪,真正静下心来细看写的真是精妙,让你感叹代码之美. 其结构明晰,高内聚.低耦合,兼具优秀的性能与便利的扩展性,在浏览器的兼容性(功能缺陷.渐 ...
- Struts2源码浅析-ConfigurationProvider
ConfigurationProvider接口 主要完成struts配置文件 加载 注册过程 ConfigurationProvider接口定义 public interface Configurat ...
- (转)【深入浅出jQuery】源码浅析2--奇技淫巧
[深入浅出jQuery]源码浅析2--奇技淫巧 http://www.cnblogs.com/coco1s/p/5303041.html
- HashSet其实就那么一回事儿之源码浅析
上篇文章<HashMap其实就那么一回事儿之源码浅析>介绍了hashMap, 本次将带大家看看HashSet, HashSet其实就是基于HashMap实现, 因此,熟悉了HashMap ...
- Android 手势识别类 ( 三 ) GestureDetector 源码浅析
前言:上 篇介绍了提供手势绘制的视图平台GestureOverlayView,但是在视图平台上绘制出的手势,是需要存储以及在必要的利用时加载取出手势.所 以,用户绘制出的一个完整的手势是需要一定的代码 ...
- Android开发之Theme、Style探索及源码浅析
1 背景 前段时间群里有伙伴问到了关于Android开发中Theme与Style的问题,当然,这类东西在网上随便一搜一大把模板,所以关于怎么用的问题我想这里也就不做太多的说明了,我们这里把重点放在理解 ...
- 【深入浅出jQuery】源码浅析2--使用技巧
最近一直在研读 jQuery 源码,初看源码一头雾水毫无头绪,真正静下心来细看写的真是精妙,让你感叹代码之美. 其结构明晰,高内聚.低耦合,兼具优秀的性能与便利的扩展性,在浏览器的兼容性(功能缺陷.渐 ...
- Android手势源码浅析-----手势绘制(GestureOverlayView)
Android手势源码浅析-----手势绘制(GestureOverlayView)
随机推荐
- maven pom 增加本地jar 依赖
https://www.cnblogs.com/huhongy/p/7337280.html <dependency> <groupId>org.hamcrest</gr ...
- http返回值含义
1xx:信息响应类,表示接收到请求并且继续处理2xx:处理成功响应类,表示动作被成功接收.理解和接受 3xx:重定向响应类,为了完成指定的动作,必须接受进一步处理4xx:客户端错误,客户请求包含语法错 ...
- Webpack学习笔记九 webpack优化总结
webpack 优化笔记 webpack4 自带的优化包括 swingTree(摇摆树)和作用域提升 swingTree 比如入口文件 index.js引入通用方法 util, 里面有 10个方法, ...
- ABAP术语-IDOC
IDOC 原文:http://www.cnblogs.com/qiangsheng/archive/2008/02/21/1075988.html Intermediate Document Inte ...
- mysql更新返回值问题(更新内容跟之前内容一样,返回0)
mysql更新返回值问题 问: 有一界面要更新个人信息,有几十个text标签需要填写假设有一用户从用户列表点修改进入了修改页面,但又没有修改什么,马上点击保存这时,因为text标签非常多,不能够一一判 ...
- python网络编程,通过服务名称和会话类型(tcp,udp)获取端口号,简单的异常处理
作为一个php程序员,同时有对网络方面感兴趣,php就比较蛋疼了,所以就抽了些时间看python 之前学python基础因为工作原因,断断续续的看了个基础,差不多是可以写代码了 最近在看<pyt ...
- C# 设置程序最小化到任务栏右下角,鼠标左键单击还原,右键提示关闭程序
首先设置程序最小化到任务栏右下角 先给窗口添加一个notifyIcon控件 为notifyIcon控件设置ICO图标(不设置图标将无法在任务栏显示) 给notifyIcon控件添加点击事件 然后是最小 ...
- Python自动化运维——系统进程管理模块
Infi-chu: http://www.cnblogs.com/Infi-chu/ 模块:psutil psutil是一个跨平台库,可以很轻松的为我们实现获取系统运行的进程和资源利用率等信息. 功能 ...
- (数据科学学习手札23)决策树分类原理详解&Python与R实现
作为机器学习中可解释性非常好的一种算法,决策树(Decision Tree)是在已知各种情况发生概率的基础上,通过构成决策树来求取净现值的期望值大于等于零的概率,评价项目风险,判断其可行性的决策分析方 ...
- 【功能笔记】Ubuntu查看系统资源占用(内存,cpu和进程) {转载}
转载自http://bluexp29.blog.163.com/blog/static/33858148201071534450856/ linux真是太强大了. 查看ubuntu的资源占用的命令为$ ...