godeby

godeby 查看完整档案

填写现居城市  |  填写毕业院校  |  填写所在公司/组织填写个人主网站
编辑
_ | |__ _ _ __ _ | '_ \| | | |/ _` | | |_) | |_| | (_| | |_.__/ \__,_|\__, | |___/ 该用户太懒什么也没留下

个人动态

godeby 关注了标签 · 7月24日

c

C 语言,是一种通用的、过程式的编程语言,广泛用于系统与应用软件的开发。具有高效、灵活、功能丰富、表达力强和较高的移植性等特点,在程序员中备受青睐。

C 语言是由 UNIX 的研制者丹尼斯·里奇(Dennis Ritchie)和肯·汤普逊(Ken Thompson)于 1970 年研制出的B语言的基础上发展和完善起来的。目前,C 语言编译器普遍存在于各种不同的操作系统中,例如 UNIX、MS-DOS、Microsoft Windows 及 Linux 等。C 语言的设计影响了许多后来的编程语言,例如 C++、Objective-C、Java、C# 等。

设计

C 语言是一个程序语言,设计目标是提供一种能以简易的方式编译、处理低级存储器、产生少量的机器码以及不需要任何运行环境支持便能运行的编程语言。C 语言也很适合搭配汇编语言来使用。尽管 C 语言提供了许多低级处理的功能,但仍然保持着良好跨平台的特性,以一个标准规格写出的 C 语言程序可在许多电脑平台上进行编译,甚至包含一些嵌入式处理器(单片机或称 MCU)以及超级电脑等作业平台。

  • C 语言是一个有结构化程序设计、具有变量作用域(variable scope)以及递归功能的过程式语言。
  • C 语言传递参数均是以值传递(pass by value),另外也可以传递指针(a pointer passed by value)。
  • 不同的变量类型可以用结构体(struct)组合在一起。
  • 只有 32 个保留字(reserved keywords),使变量、函数命名有更多弹性。
  • 部份的变量类型可以转换,例如整型和字符型变量。
  • 通过指针(pointer),C 语言可以容易的对存储器进行低级控制。
  • 编译预处理(preprocessor)让 C 语言的编译更具有弹性。

关注 10053

godeby 收藏了文章 · 2019-03-19

还不会正则表达式?看这篇!

banner

正则表达式是很多程序员,甚至是一些有了多年经验的开发者薄弱的一项技能。大家都很多时候都会觉得正则表达式难记、难学、难用,但不可否认的是正则表达式是一项很重要的技能,所有我将学习和使用正则表达式时的关键点整理如下,供大家参考。

不同语言中的正则表达式写法有少许差异,本文将使用Javascript中的语法。

什么是正则表达式?

正则表达式(Regular Expression或Regex),是用于定义某种特定搜索模式的字符组合。正则表达式可用于匹配、查找和替换文本中的字符,进行输入数据的验证,查找英文单词的拼写错误等。

调试工具

下面列出了几款优秀的在线调试工具,如果你想创建或者调试正则表达式可能会需要。个人比较偏好Regex101,regex101支持在正则表达式的不同flavor之间切换、解释你的正则表达式、显示匹配信息、提供常用语法参考等功能,非常强大。

regex101

Regexr

Regexpal

开始

在Javascript中,一个正则表达式以 / 开头和结尾,所以简单至 /hello regexp/ 就是一个正则表达式。

Flags(标志符或修饰符)

Flags写在结束的/之后,可以影响整个正则表达式的匹配行为。常见的flags有:

  1. g:全局匹配(global);正则表达式默认只会返回第一个匹配结果,使用标志符g则可以返回所有匹配
  2. i:忽略大小写(case-insensitive);在匹配时忽略英文字母的大小写
  3. m:多行匹配(multiline);将开始和结束字符(^和$)视为在多行上工作,即分别匹配每一行(由 \n\r 分割)的开始和结束,而不只是只匹配整个输入字符串的最开始和最末尾处

Flags可以组合使用,如:

flags combination

Character Sets(字符集合)

用于匹配字符集合中的任意一个字符,常见的字符集有:

  1. [xyz]:匹配 "x""y"`"z"`
  2. [^xyz]:补集,匹配除 "x" "y" "z"的其他字符
  3. [a-z]:匹配从 "a""z" 的任意字符
  4. [^a-n]:补集,匹配除 "a""n" 的其他字符
  5. [A-Z]:匹配从 "A""Z" 的任意字符
  6. [0-9]:匹配从 "0""9" 的任意数字

比如匹配所有的字母和数字可以写成:/[a-zA-Z0-9]/ 或者 /[a-z0-9]/i

Quantifiers (量词)

在实际使用中,我们常常需要匹配同一类型的字符多次,比如匹配11位的手机号,我们不可能将 [0-9] 写11遍,此时我们可以使用Quantifiers来实现重复匹配。

  1. {n}:匹配 n
  2. {n,m}:匹配 n-m
  3. {n,}:匹配 >=n
  4. ?:匹配 0 || 1
  5. *:匹配 >=0 次,等价于 {0,}
  6. +:匹配 >=1 次,等价于 {1,}

Metacharacters(元字符)

在正则表达式中有一些具有特殊含义的字母,被称为元字符,简言之,元字符就是描述字符的字符,它用于对字符表达式的内容、转换及各种操作信息进行描述。

常见的元字符有:

  1. \d:匹配任意数字,等价于 [0-9]
  2. \D:匹配任意非数字字符;\d 的补集
  3. \w:匹配任意基本拉丁字母表中的字母和数字,以及下划线;等价于 [A-Za-z0-9_]
  4. \W:匹配任意非基本拉丁字母表中的字母和数字,以及下划线;\w 的补集
  5. \s:匹配一个空白符,包括空格、制表符、换页符、换行符和其他Unicode空格
  6. \S:匹配一个非空白符;\s的补集
  7. \b:匹配一个零宽单词边界,如一个字母与一个空格之间;例如,/\bno/ 匹配 "at noon" 中的 "no"/ly\b/ 匹配 "possibly yesterday." 中的 "ly"
  8. \B:匹配一个零宽非单词边界,如两个字母之间或两个空格之间;例如,/\Bon/ 匹配 "at noon" 中的 "on"/ye\B/ 匹配 "possibly yesterday." 中的 "ye"
  9. \t:匹配一个水平制表符(tab)
  10. \n:匹配一个换行符(newline)
  11. \r:匹配一个回车符(carriage return)

Special Characters (特殊字符)

正则中存在一些特殊字符,它们不会按照字面意思进行匹配,而有特殊的意义,比如前文讲过用于量词的?*+。其他常见的特殊字符有:

  1. \:转义字符,可以将普通字符转成特殊字符。比如 \w;也可以将特殊字符转成字面意思,比如 \+ 匹配 "+"
  2. .:匹配任意单个字符,但是换行符除外:\n, \r, \u2028\u2029;在字符集中([.]),无特殊含义,即表示 '.' 的字面意思
  3. |:替换字符(alternate character),匹配 | 前或后的表达式。比如需要同时匹配 "bear""pear",可以使用 /(b|p)ear/ 或者 /bear|pear/;但是不能用 /b|pear/,该表达式只能匹配 "b""pear"
  4. ^:匹配输入的开始。比如,/^A/ 不匹配 "an Apple" 中的 "A",但匹配 "An apple" 中的 "A"
  5. $:匹配输入的结尾。比如,/t$/ 不匹配 "eater" 中的 "t",但匹配 "eat" 中的 "t"^$ 在表单验证时常需要使用,因为需要验证从开始到结尾的一个完整输入,而不是匹配输入中的某一段

Groups(分组)

  1. (xyz):捕获分组(Capturing Group),匹配并捕获匹配项;例如,/(foo)/ 匹配且捕获 "foo bar." 中的 "foo"。被匹配的子字符串可以在结果数组的元素 [1], ..., [n] 中找到,或在被定义的 RegExp 对象的属性 $1, ..., $9 中找到
  2. (?:xyz):非捕获分组(Non-capturing Group),匹配但不会捕获匹配项;匹配项不能再次被访问到
  3. \nn 是一个正整数,表示反向引用(back reference),指向正则表达式中第n个括号(从左开始数)中匹配的子字符串;例如,/apple(,)\sorange\1/ 匹配 "apple, orange, cherry, peach." 中的 "apple,orange,"

Assertion(断言)

  1. x(?=y):仅匹配被y跟随的x;例如,/bruce(?=wayne)/,如果"bruce"后面跟着wayne,则匹配之。/bruce(?=wayne|banner)/ ,如果"bruce"后面跟着"wayne"或者banner,则匹配之。但是,"wayne""banner" 都不会在匹配结果中出现
  2. x(?!y):仅匹配不被y跟随的x;例如,/\d+(?!\.)/ 只会匹配不被 "." 跟随的数字。

/\d+(?!\.)/.exec('3.141') 匹配 "141",而不是 "3.141"

应用

上面罗列出了这么多正则表达式的语法和规则,可以在一定程度上帮助我们分析和理解一段正则表达式的作用,但是如何将这些规则组合并创造出有特定作用的表达式还需要我们自己多加练习,下面举几个例子来说明运用这些规则。

1. 匹配手机号码

我们先从比较简单的匹配手机号码开始。目前国内的手机号码是1(3/4/5/7/8)开头的11位数字,因此手机号码的正则可以分解为以下几部分:

  1. 1 开头:/^1/
  2. 第2位为3、4、5、7、8中的一个:/[34578]//(3|4|5|7|8)/
  3. 剩余3-11位均为数字,并以数字结尾:/\d{9}$/

组合起来即为 /^1[34578]\d{9}$//^1(3|4|5|7|8)\d{9}$/,因为使用捕获括号存在性能损失,所以推荐使用第一种写法。

2. 匹配电子邮件

标准的电子邮件组成为 <yourname>@<domain>.<extension><optional-extension>

每部分的格式标准为(进行了相应的简化,主要为展示如何书写正则):

  1. yourname:任意英文字母(a-z/A-Z)、数字(0-9)、下划线(_)、英文句点(.)、连字符(-),长度大于0
  2. domain:任意英文字母(a-z/A-Z)、数字(0-9)、连字符(-),长度大于0
  3. extension:任意英文字母(a-z/A-Z),长度2-8
  4. optional-extension:"."开头,后面跟任意英文字母(a-z/A-Z),长度2-8,可选

每部分的正则表达式为:

  1. yourname:/[a-z\d._-]+/
  2. domain:/[a-z\d-]+/
  3. extension: /[a-z]{2,8}/
  4. optional-extension:/(\.[a-z]{2,8})?/

组合起来形成最后的正则表达式:/^([a-z\d._-]+)@([a-z\d-]+)\.([a-z]{2,8})(\.[a-z]{2,8})?$/;为了增加可读性可以将每部分用"()"包起来,并不要忘记起始和结束符 ^$

结语

今天关于正则表达式的普及就先到这儿,希望对大家以后写正则能有一点帮助。关于本文中没有涉及到的知识可以参考以下链接:

  1. Wikipedia - Regular Expression
  2. MDN - Regular Expression
  3. Microsoft - Regular Expression Reference
  4. W3schools - Regexp
最后,推荐大家使用Fundebug,一款很好用的BUG监控工具~

我的博客即将同步至腾讯云+社区,邀请大家一同入驻:https://cloud.tencent.com/dev...

查看原文

godeby 收藏了文章 · 2019-03-19

web前端技术体系大全

以下为个人目前接触到的前端技术,欢迎大家补充。

一、前端技术框架

1、Vue.js

官网:https://cn.vuejs.org/
Vue CLI:https://cli.vuejs.org/
菜鸟教程:http://www.runoob.com/w3cnote...
Nuxt.js:https://zh.nuxtjs.org/
桌面应用Electron:https://electronjs.org/

2、React.js

官网:https://react.docschina.org/
中文网:http://react-china.org/
阮一峰:http://www.ruanyifeng.com/blo...
菜鸟教程:http://www.runoob.com/react/r...

3、Jquery.js

中文API:https://www.jquery123.com/
菜鸟教程:http://www.runoob.com/jquery/...
w3school:http://www.w3school.com.cn/jq...

二、web基础知识

1、菜鸟教程
http://www.runoob.com/
2、w3school
http://www.w3school.com.cn/
3、廖雪峰
https://www.liaoxuefeng.com/
4、ECMAScript 6 入门 - 阮一峰
http://es6.ruanyifeng.com/
5、less
http://lesscss.cn/
6、sass
http://sass.bootcss.com/
7、HTML5+
http://www.dcloud.io/docs/api...

三、前端UI框架

1、bootstrap
http://www.bootcss.com/
2、layerUI
https://www.layui.com/

3、iview系列

iview(vue web端)
https://www.iviewui.com/
iview-admin(vue后台管理)
https://lison16.github.io/ivi...
iview-weapp(vue微信小程序)
https://weapp.iviewui.com/doc...
iview-admin(vue后台管理)
https://lison16.github.io/ivi...

4、element系列(饿了么出品)

element(vue web端)
http://element-cn.eleme.io/#/...
mint-ui(vue移动端)
https://mint-ui.github.io/#!/...
vue-element-admin(vue后台管理)
https://panjiachen.github.io/...

5、ant-design系列(蚂蚁金服出品)

ant-design(react web端)
https://ant.design/docs/react...
ant-design-mobile(react移动端)
https://mobile.ant.design/ind...
ant-design(vue web端)
https://vue.ant.design/docs/v...

6、vant系列(有赞出品)

vant(vue移动端)
https://youzan.github.io/vant...
vant-weapp(vue微信小程序)
https://youzan.github.io/vant...

7、vux(vue移动端)
https://vux.li/
8、Flutter(vue移动端)
https://flutterchina.club/

四、数据交互

1、Ajax
http://www.runoob.com/ajax/aj...
2、Axios
http://www.axios-js.com/zh-cn...
3、Mock(模拟随机数据)
http://mockjs.com/

五、代码构建工具

1、webpack
https://www.webpackjs.com/
2、gulp
https://www.gulpjs.com.cn/
3、grunt
https://www.gruntjs.net/

六、包管理工具

1、npm
https://www.npmjs.cn/
2、cnpm
http://npm.taobao.org/
3、yarn
https://yarn.bootcss.com/

七、代码托管

1、gitlab
https://about.gitlab.com/
2、github
https://github.com/
3、gitee码云
https://gitee.com

九、团队办公

1、界面设计:蓝湖
https://lanhuapp.com
2、图标管理:iconfont
https://www.iconfont.cn/
3、接口文档:RAP
http://rapapi.org/org/index.do
4、测试管理:禅道
https://www.zentao.net/
5、Swagger(API 的设计、编写 API 文档、测试和部署)
https://swagger.io/

八、技术社区

1、思否
https://segmentfault.com/
2、博客园
https://www.cnblogs.com/
3、CSDN
https://www.csdn.net/
4、前端网
https://www.qdfuns.com/
5、掘金
https://juejin.im/

九、可视化(图表、地图)

1、百度系列

百度地图API
https://lbsyun.baidu.com/
echarts
https://echarts.baidu.com/
mapv
https://mapv.baidu.com/

2、腾讯系列

腾讯地图API
https://lbs.qq.com/

3、阿里系列

高德地图API
https://lbs.amap.com/
antv
http://antv.alipay.com/zh-cn/...
G2 可视化图形语法
G6 图可视化引擎
F2 移动端可视化方案
L7 地理空间数据可视化

4、highcharts(图表)
https://www.highcharts.com.cn/
5、d3(图形绘制)
https://d3js.org/
6、inMap(iview的地图可视化)
http://inmap.talkingdata.com/...
7、ArcGIS(地图可视化)
https://developers.arcgis.com...
8、leaflet(地图可视化)
https://leafletjs.com/referen...
9、Cesium(三维地图可视化)
https://cesiumjs.org/index.html
10、Mapbox(地图可视化)
https://www.mapbox.com/
11、Openlayers(地图服务)
http://www.openlayers.cn/port...
12、GeoServer(地图服务)
http://blog.geoserver.org/
13、Google Map(地图可视化)
https://developers.google.cn/...
14、天地图(地图可视化)
http://lbs.tianditu.gov.cn/

查看原文

godeby 收藏了文章 · 2019-01-08

网络协议 15 - P2P 协议:小种子大学问

【前五篇】系列文章传送门:

  1. 网络协议 10 - Socket 编程(上):实践是检验真理的唯一标准
  2. 网络协议 11 - Socket 编程(下):眼见为实耳听为虚
  3. 网络协议 12 - HTTP 协议:常用而不简单
  4. 网络协议 13 - HTTPS 协议:加密路上无尽头
  5. 网络协议 14 - 流媒体协议:要说爱你不容易

    “兄弟,有种子吗?”
    “什么种子?小麦种吗?”
    “......,来,哥今天带你认识下什么是种子”。

    大家说起种子,应该都知道是用来下载资源的。那么资源下载都有哪些方式?种子下载又有什么优势呢?

下载电影的两种方式

    第一种是通过 HTTP 进行下载。这种方式,有过经历的人应该体会到,当下载文件稍大点,下载速度简直能把人急死。

    第二种方式就是是通过 FTP(文件传输协议)。FTP 采用两个 TCP 连接来传输一个文件。

  1. 控制连接。服务器以被动的方式,打开众所周知用于 FTP 的端口 21,客户端则主动发起连接。该连接将命令从客户端传给服务器,并传回服务器的应答。常用的命令有:lsit - 获取文件目录,reter - 取一个文件,store - 存一个文件;
  2. 数据连接。每当一个文件在客户端与服务器之间传输时,就创建一个数据连接。

FTP 的工作模式

    在 FTP 的两个 TCP 连接中,每传输一个文件,都要新建立一个数据连接。基于这个数据连接,FTP 又有两种工作模式:主动模式(PORT)被动模式(PASV),要注意的是,这里的主动和被动都是站在服务器角度来说的。工作模式过程如下:

主动模式工作流程

  1. 客户端随机打开一个大于 1024 的端口 N,向服务器的命令端口 21 发起连接,同时开放 N+1 端口监听,并向服务器发出“port N+1” 命令;
  2. 由服务器从自己的数据端口 20,主动连接到客户端指定的数据端口 N+1

被动模式工作流程

  1. 客户端在开启一个 FTP 连接时,打开两个任意的本地端口 N(大于1024)和 N+1。然后用 N 端口连接服务器的 21 端口,提交 PASV 命令;
  2. 服务器收到命令,开启一个任意的端口 P(大于 1024),返回“227 entering passive mode”消息,消息里有服务器开放的用来进行数据传输的端口号 P。
  3. 客户端收到消息,取得端口号 P,通过 N+1 端口连接服务器的 P 端口,进行数据传输。

    上面说了 HTTP 下载和 FTP 下载,这两种方式都有一个大缺点-难以解决单一服务器的带宽压力。因为它们使用的都是传统 C/S 结构,这种结构会随着客户端的增多,下载速度越来越慢。这在当今互联网世界显然是不合理的,我们期望能实现“下载人数越多,下载速度不变甚至更快”的愿望。

    后来,一种创新的,称为 P2P 的方式实现了我们的愿望。

P2P

    P2P 就是 peer-to-peer。这种方式的特点是,资源一开始并不集中存储在某些设备上,而是分散地存储在多台设备上,这些设备我们称为 peer。

    在下载一个文件时,只要得到那些已经存在了文件的 peer 地址,并和这些 peer 建立点对点的连接,就可以就近下载文件,而不需要到中心服务器上。一旦下载了文件,你的设备也就称为这个网络的一个 peer,你旁边的那些机器也可能会选择从你这里下载文件。

    通过这种方式解决上面 C/S 结构单一服务器带宽压力问题。如果使用过 P2P2 软件,例如 BitTorrent,你就会看到自己网络不仅有下载流量,还有上传流量,也就是说你加入了这个 P2P 网络,自己可以从这个网络里下载,同时别人也可以从你这里下载。这样就实现了,下载人数越多,下载速度越快的愿望

种子文件(.torent)

    上面整个过程是不是很完美?是的,结果很美好,但为了实现这个美好,我们还是有很多准备工作要做的。比如,我们怎么知道哪些 peer 有某个文件呢?

    这就用到我们常说的种子(.torrent)。 .torrent 文件由Announce(Tracker URL)文件信息两部分组成。

    其中,文件信息里有以下内容:

  • Info 区:指定该种子包含的文件数量、文件大小及目录结构,包括目录名和文件名;
  • Name 字段:指定顶层目录名字;
  • 每个段的大小:BitTorrent(BT)协议把一个文件分成很多个小段,然后分段下载;
  • 段哈希值:将整个种子种,每个段的 SHA-1 哈希值拼在一起。

    下载时,BT 客户端首先解析 .torrent 文件,得到 Tracker 地址,然后连接 Tracker 服务器。Tracker 服务器回应下载者的请求,将其他下载者(包括发布者)的 IP 提供给下载者。

    下载者再连接其他下载者,根据 .torrent 文件,两者分别对方自己已经有的块,然后交换对方没有的数据。

    可以看到,下载的过程不需要其他服务器参与,并分散了单个线路上的数据流量,减轻了服务器的压力。

    下载者每得到一个块,需要算出下载块的 Hash 验证码,并与 .torrent 文件中的进行对比。如果一样,说明块正确,不一样就需要重新下载这个块。这种规定是为了解决下载内容的准确性问题。

    从这个过程也可以看出,这种方式特别依赖 Tracker。Tracker 需要收集所有 peer 的信息,并将从信息提供给下载者,使下载者相互连接,传输数据。虽然下载的过程是非中心化的,但是加入这个 P2P 网络时,需要借助 Tracker 中心服务器,这个服务器用来登记有哪些用户在请求哪些资源。

    所以,这种工作方式有一个弊端,一旦 Tracker 服务器出现故障或者线路被屏蔽,BT 工具就无法正常工作了。那能不能彻底去中心化呢?答案是可以的。

去中心化网络(DHT)

    DHT(Distributed Hash Table),这个网络中,每个加入 DHT 网络的人,都要负责存储这个网络里的资源信息和其他成员的联系信息,相当于所有人一起构成了一个庞大的分布式存储数据库。

    而 Kedemlia 协议 就是一种著名的 DHT 协议。我们来基于这个协议来认识下这个神奇的 DHT 网络。

    当一个客户端启动 BitTorrent 准备下载资源时,这个客户端就充当了两个角色:

  1. peer 角色:监听一个 TCP 端口,用来上传和下载文件。对外表明我这里有某个文件;
  2. DHT Node 角色:监听一个 UDP 端口,通过这个角色,表明这个节点加入了一个 DHT 网络。

    在 DHT 网络里面,每一个 DHT Node 都有一个 ID。这个 ID 是一个长字符串。每个 DHT Node 都有责任掌握一些“知识”,也就是文件索引。也就是说,每个节点要知道哪些文件是保存哪些节点上的。注意,这里它只需要有这些“知识”就可以了,而它本身不一定就是保存这个文件的节点。

    当然,每个 DHT Node 不会有全局的“知识”,也就是说它不知道所有的文件保存位置,只需要知道一部分。这里的一部分,就是通过哈希算法计算出来的。

Node ID 和文件哈希值

    每个文件可以计算出一个哈希值,而 DHT Node 的 ID 是和哈希值相同长度的串

    对于文件下载,DHT 算法是这样规定的:

如果一个文件计算出一个哈希值,则和这个哈希值一样的那个 DHT Node,就有责任知道从哪里下载这个文件,即便它自己没保存这个文件。

    当然不一定总这么巧,都能找到和哈希值一模一样的,有可能文件对应的 DHT Node 下线了,所以 DHT 算法还规定:

除了一模一样的那个 DHT Node 应该知道文件的保存位置,ID 和这个哈希值非常接近的 N 个 DHT Node 也应该知道。

    以上图为例。文件 1 通过哈希运算,得到匹配 ID 的 DHT Node 为 Node C(当然还会有其他的,为了便于理解,咱们就先关注 Node C),所以,Node C 就有责任知道文件 1 的存放地址,虽然 Node C 本身没有存放文件 1。

    同理,文件 2 通过哈希计算,得到匹配 ID 的 DHT Node 为 Node E,但是 Node D 和 E 的值很近,所以 Node D 也知道。当然,文件 2 本身不一定在 Node D 和 E 这里,但是我们假设 E 就有一份。

    接下来,一个新节点 Node new 上线了,如果要下载文件 1,它首先要加入 DHT 网络。如何加入呢?

    在这种模式下,种子 .torrent 文件里面就不再是 Tracker 的地址了,而是一个 list 的 Node 地址,所有这些 Node 都是已经在 DHT 网络里面的。当然,随着时间的推移,很有可能有退出的,有下线的,这里我们假设,不会所有的都联系不上,总有一个能联系上。

    那么,Node new 只要在种子里面找到一个 DHT Node,就加入了网络。

    Node new 不知道怎么联系上 Node C,因为种子里面的 Node 列表里面很可能没有 Node C,但是没关系,它可以问。DHT 网络特别像一个社交网络,Node new 会去它能联系上的 Node 问,你们知道 Node C 的联系方式吗?

    在 DHT 网络中,每个 Node 都保存了一定的联系方式,但是肯定没有所有 Node 的联系方式。节点之间通过相互通信,会交流联系方式,也会删除联系方式。这和人们的沟通方式一样,你有你的朋友圈,他有他的朋友圈,你们互相加微信,就互相认识了,但是过一段时间不联系,就可能会删除朋友关系一样。

    在社交网络中,还有个著名的六度理论,就是说社交网络中的任何两个人的直接距离不超过六度,也就是即使你想联系比尔盖茨,最多通过六个人就能够联系上。

    所以,Node New 想联系 Node C,就去万能的朋友圈去问,并且求转发,朋友再问朋友,直到找到 C。如果最后找不到 C,但是能找到离 C 很近的节点,也可以通过 C 的相邻节点下载文件 1。

    在 Node C上,告诉 Node new,要下载文件 1,可以去 B、D、F,这里我们假设 Node new 选择了 Node B,那么新节点就和 B 进行 peer 连接,开始下载。它一旦开始下载,自己本地也有文件 1 了,于是,Node new 就告诉 C 以及 C 的相邻节点,我也有文件 1 了,可以将我加入文件 1 的拥有者列表了。

    你可能会发现,上面的过程中漏掉了 Node new 的文件索引,但是根据哈希算法,一定会有某些文件的哈希值是和 Node new 的 ID 匹配的。在 DHT 网络中,会有节点告诉它,你既然加入了咱们这个网络,也就有责任知道某些文件的下载地址了。

    好了,完成分布式下载了。但是我们上面的过程中遗留了两个细节性的问题。

1)DHT Node ID 以及文件哈希值是什么?
    其实,我们可以将节点 ID 理解为一个 160bits(20字节)的字符串,文件的哈希也使用这样的字符串。

2)所谓 ID 相似,具体到什么程度算相似?
    这里就要说到两个节点距离的定义和计算了。

    在 Kademlia 网络中,两个节点的距离采用的是逻辑上的距离,假设节点 A 和 节点 B 的距离为 d,则:

d = A XOR B

    上面说过,每个节点都有一个哈希 ID,这个 ID 由 20 个字符,160 bits 位组成。这里,我们就用一个 5 bits ID 来举例。
    我们假设,节点 A 的 ID 是 01010,节点 B 的 ID 是 01001,则:

距离 d = A XOR B = 01010 XOR 00011 = 01001 = 9

    所以,我们说节点 A 和节点 B 的逻辑距离为 9。

    回到我们上面的问题,哈希值接近,可以理解为距离接近,也即,和这个节点距离近的 N 个节点要知道文件的保存位置

    要注意的是,这个距离不是地理位置,因为在 Kademlia 网络中,位置近不算近,ID 近才算近。我们可以将这个距离理解为社交距离,也就是在朋友圈中的距离,或者社交网络中的距离。这个和你的空间位置没有多少关系,和人的经历关系比较大。

DHT 网络节点关系的维护

    就像人一样,虽然我们常联系的只有少数,但是朋友圈肯定是远近都有。DHT 网络的朋友圈也一样,远近都有,并且按距离分层

    假设某个节点的 ID 为 01010,如果一个节点的 ID,前面所有位数都与它相同,只有最后 1 位不停,这样的节点只有 1 个,为 01011。与基础节点的异或值为 00001,也就是距离为 1。那么对于 01010 而言,这样的节点归为第一层节点,也就是k-buket 1

    类似的,如果一个节点的 ID,前面所有位数和基础节点都相同,从倒数第 2 位开始不同,这样的节点只有 2 个,即 01000 和 01001,与基础节点的亦或值为 00010 和 00011,也就是距离为 2 和 3。这样的节点归为第二层节点,也就是k-bucket 2

    所以,我们可以总结出以下规律:

如果一个节点的 ID,前面所有位数相同,从倒数第 i 位开始不同,这样的节点只有 2^(i-1) 个,与基础节点的距离范围为 [2^(i-1), 2^i],对于原始节点而言,这样的节点归为k-bucket i

    你会发现,差距越大,陌生人就越多。但是朋友圈不能把所有的都放下,所以每一层都只放 K 个,这个 K 是可以通过参数配置的。

DHT 网络中查找好友

    假设,Node A 的 ID 为 00110,要找 B(10000),异或距离为 10110,距离范围在 [2^4, 2^5),这就说明 B 的 ID 和 A 的从第 5 位开始不同,所以 B 可能在 k-bucket 5 中。

    然后,A 看看自己的 k-bucket 5 有没有 B,如果有,结束查找。如果没有,就在 k-bucket 5 里随便找一个 C。因为是二进制,C、B 都和 A 的第 5 位不停,那么 C 的 ID 第5 位肯定与 B 相同,即它与 B 的距离小于 2^4,相当于 A、B 之间的距离缩短了一半以上。

    接着,再请求 C,在 C 的通讯里里,按同样的查找方式找 B,如果 C 找到了 B,就告诉 A。如果 C 也没有找到 B,就按同样的搜索方法,在自己的通讯里里找到一个离 B 更近一步的 D(D、B 之间距离小于 2^3),把 D 推荐给 A,A 请求 D 进行下一步查找。

    你可能已经发现了,Kademlia 这种查询机制,是通过折半查找的方式来收缩范围,对于总的节点数目为 N 的网络,最多只需要 log2(N) 次查询,就能够找到目标。

    如下图,A 节点找 B 节点,最坏查找情况:

    图中过程如下:

  1. A 和 B 的每一位都不一样,所以相差 31,A 找到的朋友 C,不巧正好在中间,和 A 的距离是 16,和 B 的距离是 15;
  2. C 去自己朋友圈找,碰巧找到了 D,距离 C 为 8,距离 B 为 7;
  3. D 去自己朋友圈找,碰巧找到了 E,距离 D 为 4,距离 B 为 3;
  4. E 在自己朋友圈找,找到了 F,距离 E 为 2,距离 B 为 1;
  5. F 在距离为 1 的地方找到了 B。
节点的沟通

    在 Kademlia 算法中,每个节点下面 4 个指令:

  • PING:测试一个节点是否在线。相当于打个电话,看还能打通不;
  • STORE:要钱一个节点存储一份数据;
  • FIND_NODE:根据节点 ID 查找一个节点;
  • FIND_VALUE:根据 KEY 查找一个数据,实则上和 FIND_NODE 非常类似。KEY 就是文件对应的哈希值,找到保存文件的节点。
节点的更新

    整个 DHT 网络,会通过相互通信,维护自己朋友圈好友的状态。

  • 每个 bucket 里的节点,都按最后一次接触时间倒序排列。相当于,朋友圈里最近联系的人往往是最熟的;
  • 每次执行四个指令中的任意一个都会触发更新;
  • 当一个节点与自己接触时,检查它是否已经在 k-bucket 中。就是说是否已经在朋友圈。如果在,那么就将它移到 k-bucket 列表的最底,也就是最新的位置(刚联系过,就置顶下,方便以后多联系)。如果不在,就要考虑新的联系人要不要加到通讯录里面。假设通讯录已满,就 PING 一下列表最上面的节点(最旧的),如果 PING 通了,将旧节点移动到列表最底,并丢弃新节点(老朋友还是要留点情面的)。如 PING 不同,就删除旧节点,并将新节点加入列表(联系不上的老朋友还是删掉吧)。

    通过上面这个机制,保证了任意节点的加入和离开都不影响整体网络。

小结

  • 下载一个文件可以通过 HTTP 或 FTP。这两种都是集中下载的方式,而 P2P 则换了一种思路,采用非中心化下载的方式;
  • P2P 有两种。一种是依赖于 Tracker 的,也就是元数据集中,文件数据分散。另一种是基于分布式的哈希算法,元数据和文件数据全部分散。

参考:

  1. 维基百科-DHT 网络词条;
  2. 维基百科-Kademlia 词条;
  3. 刘超 - 趣谈网络协议系列课;
查看原文

godeby 关注了标签 · 2018-12-19

javascript

JavaScript 是一门弱类型的动态脚本语言,支持多种编程范式,包括面向对象和函数式编程,被广泛用于 Web 开发。

一般来说,完整的JavaScript包括以下几个部分:

  • ECMAScript,描述了该语言的语法和基本对象
  • 文档对象模型(DOM),描述处理网页内容的方法和接口
  • 浏览器对象模型(BOM),描述与浏览器进行交互的方法和接口

它的基本特点如下:

  • 是一种解释性脚本语言(代码不进行预编译)。
  • 主要用来向HTML页面添加交互行为。
  • 可以直接嵌入HTML页面,但写成单独的js文件有利于结构和行为的分离。

JavaScript常用来完成以下任务:

  • 嵌入动态文本于HTML页面
  • 对浏览器事件作出响应
  • 读写HTML元素
  • 在数据被提交到服务器之前验证数据
  • 检测访客的浏览器信息

《 Javascript 优点在整个语言中占多大比例?

关注 137354

godeby 关注了标签 · 2018-12-19

java

Java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的 Java 程序设计语言和 Java 平台(即 JavaSE, JavaEE, JavaME)的总称。Java 技术具有卓越的通用性、高效性、平台移植性和安全性。

Java编程语言的风格十分接近 C++ 语言。继承了 C++ 语言面向对象技术的核心,Java舍弃了 C++ 语言中容易引起错误的指針,改以引用取代,同时卸载原 C++ 与原来运算符重载,也卸载多重继承特性,改用接口取代,增加垃圾回收器功能。在 Java SE 1.5 版本中引入了泛型编程、类型安全的枚举、不定长参数和自动装/拆箱特性。太阳微系统对 Java 语言的解释是:“Java编程语言是个简单、面向对象、分布式、解释性、健壮、安全与系统无关、可移植、高性能、多线程和动态的语言”。

版本历史

重要版本号版本代号发布日期
JDK 1.01996 年 1 月 23 日
JDK 1.11997 年 2 月 19 日
J2SE 1.2Playground1998 年 12 月 8 日
J2SE 1.3Kestrel2000 年 5 月 8 日
J2SE 1.4Merlin2002 年 2 月 6 日
J2SE 5.0 (1.5.0)Tiger2004 年 9 月 30 日
Java SE 6Mustang2006 年 11 月 11 日
Java SE 7Dolphin2011 年 7 月 28 日
Java SE 8JSR 3372014 年 3 月 18 日
最新发布的稳定版本:
Java Standard Edition 8 Update 11 (1.8.0_11) - (July 15, 2014)
Java Standard Edition 7 Update 65 (1.7.0_65) - (July 15, 2014)

更详细的版本更新查看 J2SE Code NamesJava version history 维基页面

新手帮助

不知道如何开始写你的第一个 Java 程序?查看 Oracle 的 Java 上手文档

在你遇到问题提问之前,可以先在站内搜索一下关键词,看是否已经存在你想提问的内容。

命名规范

Java 程序应遵循以下的 命名规则,以增加可读性,同时降低偶然误差的概率。遵循这些命名规范,可以让别人更容易理解你的代码。

  • 类型名(类,接口,枚举等)应以大写字母开始,同时大写化后续每个单词的首字母。例如:StringThreadLocaland NullPointerException。这就是著名的帕斯卡命名法。
  • 方法名 应该是驼峰式,即以小写字母开头,同时大写化后续每个单词的首字母。例如:indexOfprintStackTraceinterrupt
  • 字段名 同样是驼峰式,和方法名一样。
  • 常量表达式的名称static final 不可变对象)应该全大写,同时用下划线分隔每个单词。例如:YELLOWDO_NOTHING_ON_CLOSE。这个规范也适用于一个枚举类的值。然而,static final 引用的非不可变对象应该是驼峰式。

Hello World

public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello, World!");
    }
}

编译并调用:

javac -d . HelloWorld.java
java -cp . HelloWorld

Java 的源代码会被编译成可被 Java 命令执行的中间形式(用于 Java 虚拟机的字节代码指令)。

可用的 IDE

学习资源

常见的问题

下面是一些 SegmentFault 上在 Java 方面经常被人问到的问题:

(待补充)

关注 107473

godeby 关注了标签 · 2018-12-19

前端

Web前端开发是从网页制作演变而来的,名称上有很明显的时代特征。在互联网的演化进程中,网页制作是Web 1.0时代的产物,那时网站的主要内容都是静态的,用户使用网站的行为也以浏览为主。2005年以后,互联网进入Web 2.0时代,各种类似桌面软件的Web应用大量涌现,网站的前端由此发生了翻天覆地的变化。网页不再只是承载单一的文字和图片,各种富媒体让网页的内容更加生动,网页上软件化的交互形式为用户提供了更好的使用体验,这些都是基于前端技术实现的。

Web前端优化
  1. 尽量减少HTTP请求 (Make Fewer HTTP Requests)
  2. 减少 DNS 查找 (Reduce DNS Lookups)
  3. 避免重定向 (Avoid Redirects)
  4. 使得 Ajax 可缓存 (Make Ajax Cacheable)
  5. 延迟载入组件 (Post-load Components)
  6. 预载入组件 (Preload Components)
  7. 减少 DOM 元素数量 (Reduce the Number of DOM Elements)
  8. 切分组件到多个域 (Split Components Across Domains)
  9. 最小化 iframe 的数量 (Minimize the Number of iframes)
  10. 杜绝 http 404 错误 (No 404s)

关注 155287

godeby 关注了标签 · 2018-12-19

html

超文本标记语言(英文:HyperText Markup Language,HTML)是为“网页创建和其它可在网页浏览器中看到的信息”设计的一种标记语言。

关注 62378

godeby 关注了标签 · 2018-12-19

python

Python(发音:英[ˈpaɪθən],美[ˈpaɪθɑ:n]),是一种面向对象、直译式电脑编程语言,也是一种功能强大的通用型语言,已经具有近二十年的发展历史,成熟且稳定。它包含了一组完善而且容易理解的标准库,能够轻松完成很多常见的任务。它的语法非常简捷和清晰,与其它大多数程序设计语言不一样,它使用缩进来定义语句。

Python支持命令式程序设计、面向对象程序设计、函数式编程、面向切面编程、泛型编程多种编程范式。与Scheme、Ruby、Perl、Tcl等动态语言一样,Python具备垃圾回收功能,能够自动管理存储器使用。它经常被当作脚本语言用于处理系统管理任务和网络程序编写,然而它也非常适合完成各种高级任务。Python虚拟机本身几乎可以在所有的作业系统中运行。使用一些诸如py2exe、PyPy、PyInstaller之类的工具可以将Python源代码转换成可以脱离Python解释器运行的程序。

Python的主要参考实现是CPython,它是一个由社区驱动的自由软件。目前由Python软件基金会管理。基于这种语言的相关技术正在飞快的发展,用户数量快速扩大,相关的资源非常多。

关注 102742

godeby 关注了标签 · 2018-12-19

html5

HTML5 是 HTML 下一个的主要修订版本,现在仍处于发展阶段。广义论及 HTML5 时,实际指的是包括 HTML、CSS 和 JavaScript 在内的一套技术组合。

关注 88053

认证与成就

  • 获得 0 次点赞
  • 获得 6 枚徽章 获得 0 枚金徽章, 获得 1 枚银徽章, 获得 5 枚铜徽章

擅长技能
编辑

(゚∀゚ )
暂时没有

开源项目 & 著作
编辑

(゚∀゚ )
暂时没有

注册于 2018-10-06
个人主页被 52 人浏览