diff --git a/README.md b/README.md index fe4987d28c..8d1c8b69c3 100644 --- a/README.md +++ b/README.md @@ -1,9 +1 @@ -lemonchann的个人博客仓库。 - -### 文章版权 - -**[_posts](https://github.com/lemonchann/lemonchann.github.io/tree/master/_posts)** 文件夹内所有文章若无特别声明均使用[CC BY-SA 4.0 International License(知识共享署名-相同方式共享 4.0 国际许可协议)](http://creativecommons.org/licenses/by-sa/4.0/)授权。 - -### 致谢 - -本站原始主题来自Jekyll主题[LOFFER](https://fromendworld.github.io/LOFFER/) + diff --git a/_config.yml b/_config.yml index 67c75ad960..f2a14339f4 100644 --- a/_config.yml +++ b/_config.yml @@ -3,7 +3,7 @@ # # Name of your site (displayed in the header) -name: "lemonchann's blog" +name: "mila's blog" # Short bio or description (displayed in the header) description: "learning and practicing make skillfull" @@ -12,10 +12,10 @@ description: "learning and practicing make skillfull" # # URL of your avatar or profile pic (you could use your GitHub profile pic) -avatar: https://github.com/lemonchann/lemonchann.github.io/raw/master/images/blog.jpg +avatar: https://raw.githubusercontent.com/Milaaaaaa/Milaaaaaa.github.io/master/images/blog.jpg # 你的favicon(出现在浏览器tab上)图片URL,建议使用较小(64px × 64px)的图片 -favicon: https://github.com/lemonchann/lemonchann.github.io/raw/master/images/favicon.ico +favicon: https://raw.githubusercontent.com/Milaaaaaa/Milaaaaaa.github.io/master/images/favicon.ico # Tabs in header. There are 'Blog', 'About', 'Archive', 'Tags' # and URL Link(e.g. 'Theme' tab below) tabs. If you don't need one, just delete @@ -40,11 +40,10 @@ footer-links: #weibo: frommidworld #请输入你的微博个性域名 https://www.weibo.com/ behance: # https://www.behance.net/ dribbble: - zhihu: ll-chen-2 - email: lemonchann@foxmail.com + email: 1010736772@qq.com facebook: flickr: - github: lemonchann + github: Milaaaaaa googleplus: # anything in your profile username that comes after plus.google.com/ instagram: linkedin: @@ -56,7 +55,7 @@ footer-links: youtube: # Text under the icons in footer -footer-text: Copyright (c) 2019 lemonchann +#footer-text: Copyright (c) 2019 lemonchann # Enter your Disqus shortname (not your username) to enable commenting on posts # You can find your shortname on the Settings page of your Disqus account @@ -64,17 +63,17 @@ disqus: # fromendworld # Gitalk gitalk: - clientID: bd65d5c0df878155b7fa - clientSecret: d0220762c05c2d6b6f6152a0f0e4b6b090de9729 - repo: lemonchann.github.io - owner: lemonchann + clientID: 5d1d13e330f61b2a5559 + clientSecret: 2fcc89e2167767ecf8b3f28bf9277d51042edc1d + repo: Milaaaaaa.github.io + owner: Milaaaaaa # Enter your Google Analytics web tracking code (e.g. UA-2110908-2) to activate tracking -google_analytics: UA-152888548-1 +google_analytics: UA-158947978-1 # Your website URL (e.g. http://barryclark.github.io or http://www.barryclark.co) # Used for Sitemap.xml and your RSS feed -url: https://lemonchann.github.io +url: https://Milaaaaaa.github.io # If you're hosting your site at a Project repository on GitHub pages # (http://yourusername.github.io/repository-name) diff --git a/_posts/2018-10-12-Play_with_vscode_PlantUML_preview.md b/_posts/2018-10-12-Play_with_vscode_PlantUML_preview.md deleted file mode 100644 index 84b5b04c77..0000000000 --- a/_posts/2018-10-12-Play_with_vscode_PlantUML_preview.md +++ /dev/null @@ -1,92 +0,0 @@ ---- -layout: post -title: "玩转vscode支持PlantUML绘制预览流程图" -date: 2018-10-12 -tags: [vscode] -comments: true -author: lemonchann ---- - -软件设计过程中,有好几种图需要画,比如流程图、类图、组件图等,我知道大部分人画流程图一般都会用微软的viso绘制,我之前也是这个习惯,viso画图有个不好的地方是需要时刻去调整线条和边框已达到简洁美观,今天我给大家介绍一款程序员画图神器PlantUML,一款你用了就爱上的画图软件! - -VsCode以插件的形式支持了这款画图神器,还不知道VsCode? - -> VsCode 强大地自定义功能,已经成为程序员最爱编辑器。 -> Microsoft在2015年4月30日Build 开发者大会上正式宣布了 Visual Studio Code 项目:一个运行于 Mac OS X、Windows和Linux之上的,针对于编写现代 Web 和云应用的跨平台源代码编辑器。 - -> 该编辑器也集成了所有一款现代编辑器所应该具备的特性,包括语法高亮(syntax high lighting),可定制的热键绑定(customizable keyboard bindings),括号匹配(bracket matching)以及代码片段收集(snippets)。Somasegar 也告诉笔者这款编辑器也拥有对 Git 的开箱即用的支持。引用[360百科](https://baike.so.com/doc/24428308-25261478.html) - - - -## 主角出场 - -### PlantUML - -**PlantUML是一个开源项目,支持快速绘制:** - ->时序图 -用例图 -类图 -活动图 (旧版语法在此处) -组件图 -状态图 -对象图 -部署图 -定时图 - -**同时还支持以下非UML图:** ->线框图形界面 -架构图 -规范和描述语言 (SDL) -Ditaa diagram -甘特图 -MindMap diagram -以 AsciiMath 或 JLaTeXMath 符号的数学公式 - -通过简单直观的语言来定义这些示意图,与MarkDown有相似的作用,这两种语言一个主要面向文本渲染一个主要用于图形绘制。 -#### 语法 -语法简单明了,查看以下[官方教程](http://plantuml.com/zh/sequence-diagram) -**我截取几个官网的事例图片在这里:** - -- 活动图 -![活动图](https://i.loli.net/2019/11/21/GIBKdwfv2zCLH5y.png) -- 类图 -![类图](https://i.loli.net/2019/11/21/KZz4F82AugpNckW.png) -- 时序图 -![时序图](https://i.loli.net/2019/11/21/XIKTPifd6GmMB5Y.png) -- 用例图 -![用例图](https://i.loli.net/2019/11/21/8nMHGwyV1lobCLz.png) -- 状态图 -![状态图](https://i.loli.net/2019/11/21/6b9q2BXLyeZSIpD.png) - -#### 图中的图片都是用源代码' '写'' 出来的哦!是不是很cool - - -### PlantUML遇上VsCode -#### 安装 -- 安装graphviz-2.38.msi -- 安装2个vscode插件: -> PlantUML、Graphviz Preview - -#### 例子 -```plantUML -@startuml -Alice -> Bob: Authentication Request -Bob --> Alice: Authentication Response - -Alice -> Bob: Another authentication Request -Alice <-- Bob: another authentication Response -@enduml -``` -#### 预览 -> Alt+D - -#### 文件格式 -> .wsd, .pu, .puml, .plantuml, .iuml - -#### 如何导出 -> F1/ctrl+shift+p; PlantUML:导出当前图表;选择导出格式png;导出即可。 - - - -#### 好了,这么好用工具赶紧用起来吧! \ No newline at end of file diff --git a/_posts/2018-11-1-Performance_ulimit_TCP_link.md b/_posts/2018-11-1-Performance_ulimit_TCP_link.md deleted file mode 100644 index 64094424e4..0000000000 --- a/_posts/2018-11-1-Performance_ulimit_TCP_link.md +++ /dev/null @@ -1,54 +0,0 @@ ---- -layout: post -title: "性能调优ulimit增加TCP连接最大限制" -date: 2018-11-1 -tags: [linux] -comments: true -author: lemonchann ---- - -Linux系统中tcp连接数是有最大限制的,即是进程可打开的最大文件描述个数,通过命令`ulimit -n`查看 - - - -## TCP连接数限制 - -高负载的服务器通过修改ulimit参数达到合理规划用户使用资源和系统资源的目的。 - -## 用户级别 - -#### 修改最大连接数 -- 修改系统参数实现 - -> ulimit -SHn 65535 - -> -H硬限制是实际的限制,-S软限制是warnning限制,只会做出warning. -如果运行ulimit命令修改的时候没有加上SH,就是两个参数一起改变. - -- 修改pam模块配置实现 - -1. session required /lib/security/pam_limits.so - -2. 修改/etc/security/limits.conf如下举例 - - `* soft nofile 65536` - `* hard nofile 65536` - `*代表所有用户,当然也可以指定用户如root` - -#### 确认修改是否生效 -项目中遇到修改后虽然命令查看已经是修改后的值,但是进程连接的tcp个数还是系统默认的1024导致接入拒绝 - -##### 查看进程实际的最大连接数 -`cat /proc/进程pid/limits` -`Max open files 就是当前进程的实际值` - -## 系统级别 -查看总的系统打开文件限制 -> cat /proc/sys/fs/file-max - -若要修改可以在rc.local加 -> echo 你要的 > /proc/sys/fs/file-max - - - - diff --git a/_posts/2018-6-21-Markdown_brief_syntactic.md b/_posts/2018-6-21-Markdown_brief_syntactic.md deleted file mode 100644 index af588d410b..0000000000 --- a/_posts/2018-6-21-Markdown_brief_syntactic.md +++ /dev/null @@ -1,117 +0,0 @@ ---- -layout: post -title: "Markdown 语法简明笔记" -date: 2018-6-21 -tags: [markdown] -comments: true -author: lemonchann -toc: true ---- -**Markdown是一种可以使用普通文本编辑器编写的标记语言,通过简单的标记语法,它可以使普通文本内容具有一定的格式。markdown是为那些需要经常码字或者进行文字排版的、对码字手速和排版顺畅度有要求的人群设计的,他们希望用键盘把文字内容打出来后就已经排版好了,最好从头到尾都不要使用鼠标。这些人包括经常需要写文档的码农、博客写手、网站小编、出版业人士等等** 参考[**百度百科**](https://baike.baidu.com/item/markdown/3245829?fr=aladdin) - - - -### markdown语法 -开始学习markdown就有必要了解一下基本的语法,这里罗列一些基本的语法,这些语法是非常简单且常用的,能够帮助你快速掌握这门轻量的标记语言并且能够动手写自己的小博客,动手写起博客之后一些高级的用法可以边用边学。 - -- **标题样式** -在Markdown中,若一段文字被定义为标题,只要在这段文字前加 # 号即可。注意这里#号后面是有空格的。 ->'# '一级标题, '## '二级标题, '### '三级标题 -- **列表** -1. 无序列表使用`*`、+和-来做为列表的项目标记,这些符号是都可以使用的,注意符号与字符间**必须有一个空格**。 ->* Candy. ->* Gum. ->* Booze. ->- Candy. ->- Gum. ->- Booze. ->+ Candy. ->+ Gum. ->+ Booze. - -2. 有序的列表则是使用一般的数字接着一个英文句点作为项目标记: ->1. Red ->2. Green ->3. Blue -- **目录** ->用`[TOC]`生成目录 -- **加粗** 用双*号 ->`**xxx**` **xxx** -- **引用** 由'>'开头 ->`>` -- **斜体**单*号 ->`*x*` *x* -- **删除线** 双波浪线 ->`~~xx~~` ~~xx~~ -- **分割线** 另起一行输入三个连续* ->`***` - -- **下划线** ++ 开头 ++结尾 ->`++下划线++` ++下划线++ - -- **高亮标记** ==开头 ==结尾 ->`==高亮标记==` ==高亮标记== - -- **换行** 在末尾敲击两个以上空白,然后回车 - -- **插入链接** ->语法:`[链接说明](uri)` - -- **插入图片** ->语法: `![image](uri)` 语法上和插入链接只是多了个! 插入图片的方法有很多种,csdn markdown提供插入图片功能,也可以注册各种图床(网上搜索说是七牛云最好用,没用过不发表)我这里说一种脑回路清奇的用GitHub当图床插入图片的方法。原链接参考[知乎](https://www.zhihu.com/question/21065229/answer/61070700?utm_medium=social&utm_source=wechat_session) - -### 以我的实践举个图片插入的栗子: - -1. 将markdown需要用的图片放到git仓库中,发布到github上 -2. 访问我的github仓库https://github.com/lemonchann/cloud_image -3. 访问图片cloud_image/Markdown语法简明笔记1.png -4. 点 download 按钮,在地址栏可以复制图片地址,或者在Download按钮上直接右键 "复制链接地址" -5. 拷贝链接地址https://raw.githubusercontent.com/lemonchann/cloud_image/master/Markdown%E8%AF%AD%E6%B3%95%E7%AE%80%E6%98%8E%E7%AC%94%E8%AE%B01.png -6. 在Markdown中引用图片 -7. 这是这篇博客我在markdown编辑器里的编辑的内容![Markdown语法简明笔记1](https://github.com/lemonchann/lemonchann.github.io/raw/master/images/2018-6-21-Markdown_brief_syntactic/Markdown%E8%AF%AD%E6%B3%95%E7%AE%80%E6%98%8E%E7%AC%94%E8%AE%B01.png) - - ![Markdown语法简明笔记2](https://github.com/lemonchann/lemonchann.github.io/raw/master/images/2018-6-21-Markdown_brief_syntactic/Markdown%E8%AF%AD%E6%B3%95%E7%AE%80%E6%98%8E%E7%AC%94%E8%AE%B02.png) -- **插入图片2** -> 图片还可以用相对路径的方法插入,必须和markdown文件相同目录下的文件或文件夹,但这种方法不适合写单篇的csdn或知乎文章,可以用于写书写个人博客。 -> 语法示例: -> `![pic](image/test.png) 或 ![pic](test.png)` - -- **程序员必备代码段** 以三个 ` 开头带程序类型和 ``` 结尾,中间包含代码段 -```c++ -#include -using namespace std; -class test -{ - int a; - string str; -}; -``` -- **代码框** 用两个 ` 把代码框在中间就是代码段,也可以用于防止markdown语法生效(类似转义符) - ->`it is code` - -- **表格** - -header 1 | header 2 ----|--- -row 1 col 1 | row 1 col 2 -row 2 col 1 | row 2 col 2 - - - -### 编辑器推荐 - -推荐编辑器 - -- typora,谁用谁知道。 - -- vscode+markdown - - - -### 参考文章 -- [Markdown: Basics (快速入门)](http://wowubuntu.com/markdown/basic.html) -- [Markdown中插入图片有什么技巧?](https://www.zhihu.com/question/21065229/answer/61070700?utm_medium=social&utm_source=wechat_session) - -- [【进阶版】有道云笔记Markdown指南](http://note.youdao.com/iyoudao/?p=2445) -- [【简明版】有道云笔记Markdown指南](http://note.youdao.com/iyoudao/?p=2411)it \ No newline at end of file diff --git a/_posts/2019-11-18-new_gitbook_tutors.md b/_posts/2019-11-18-new_gitbook_tutors.md deleted file mode 100644 index 1024e275f2..0000000000 --- a/_posts/2019-11-18-new_gitbook_tutors.md +++ /dev/null @@ -1,104 +0,0 @@ ---- -layout: post -title: "新版本gitbook配置图书预览和生成" -date: 2019-11-18 -tags: [tool] -comments: true -author: lemonchann - ---- - -什么是Gitbook? 简单说就是可以把用md写的多个文档组织成**书**发布,md你可以放在github管理,配置gitbook关联github可以实现实时commit的预览生成。也可本地预览,甚至生成各种格式文档输出的强大工具。 - - - -## 安装Gitbook -* 安装nodejs可以去[官网](http://nodejs.cn/download/)下载对应版本 -* 安装gitbook,打开win cmd输入npm install gitbook-cli -g -> 常用命令: -> **gitbook -V 查看版本** -> **gitbook serve 生成网页localhost:4000预览** - 命令输入要进到SUMMARY.md所在目录![gitbook_serve](https://github.com/lemonchann/lemonchann.github.io/raw/master/images/2019-11-18-new_gitbook_tutors/gitbook_serve.png) -> gitbook init //初始化目录文件 -> gitbook help //列出gitbook所有的命令 -> gitbook --help //输出gitbook-cli的帮助信息 -> gitbook build //生成静态网页 -> gitbook serve //生成静态网页并运行服务器 -> gitbook build --gitbook=2.0.1 //生成时指定gitbook的版本, 本地没有会先下载 -> gitbook ls //列出本地所有的gitbook版本 -> gitbook ls-remote //列出远程可用的gitbook版本 -> gitbook fetch 标签/版本号 //安装对应的gitbook版本 -> gitbook update //更新到gitbook的最新版本 -> gitbook uninstall 2.0.1 //卸载对应的gitbook版本 -> gitbook build --log=debug //指定log的级别 -> gitbook builid --debug //输出错误信息 - -## 用Gitbook转换markdown文件生成PDF - -### 安装calibre -* 电子书生成下载依赖calibre否则会报错,建议先安装,[下载地址](https://calibre-ebook.com/download) -* 配置calibre环境变量,我的目录是C:\Program Files\Calibre2 - - ![环境变量设置1](https://github.com/lemonchann/lemonchann.github.io/raw/master/images/2019-11-18-new_gitbook_tutors/%E7%8E%AF%E5%A2%83%E5%8F%98%E9%87%8F%E8%AE%BE%E7%BD%AE1.PNG) - - ![环境变量设置2](https://github.com/lemonchann/lemonchann.github.io/raw/master/images/2019-11-18-new_gitbook_tutors/%E7%8E%AF%E5%A2%83%E5%8F%98%E9%87%8F%E8%AE%BE%E7%BD%AE2.PNG) - -### 生成PDF - -打开win cmd命令行,到SUMMARY.md所在目录执行 **gitbook pdf 生成pdf** -> 转换PDF失败原因: -1. 没有安装calibre -2. 安装calibre之后需要设置环境变量C:\Program Files\Calibre2 -3. [报错1](http://xcoding.tech/2018/08/08/hexo/%E5%A6%82%E4%BD%95%E4%BB%8E%E6%A0%B9%E6%9C%AC%E8%A7%A3%E5%86%B3hexo%E4%B8%8D%E5%85%BC%E5%AE%B9%7B%7B%7D%7D%E6%A0%87%E7%AD%BE%E9%97%AE%E9%A2%98/) - -## Gitbook关联github - -**Gitbook上同步github的配置界面已经发生了变化,新界面操作如下:** - -![gitbook空间](https://github.com/lemonchann/lemonchann.github.io/raw/master/images/2019-11-18-new_gitbook_tutors/gitbook%E7%A9%BA%E9%97%B4.png) - -![关联github](https://github.com/lemonchann/lemonchann.github.io/raw/master/images/2019-11-18-new_gitbook_tutors/%E5%85%B3%E8%81%94github.png) - -### 发布到github pages -#### 关于 GitHub Pages ->GitHub Pages 是一项静态站点托管服务,它直接从 GitHub 上的仓库获取 HTML、CSS 和 JavaScript 文件,(可选)通过构建过程运行文件,然后发布网站。 您可以在 GitHub Pages 示例集合中查看 GitHub Pages 站点的示例。 - -您可以在 GitHub 的 github.io 域或自己的自定义域上托管站点。 更多信息请参阅“对 GitHub Pages 使用自定义域”。 - -要开始使用,请参阅“创建 GitHub Pages 站点”。 - -#### GitHub Pages 站点的类型 -有三种类型的 GitHub Pages 站点:项目、用户和组织。 项目站点连接到 GitHub 上托管的特定项目,例如 JavaScript 库或配方集合。 用户和组织站点连接到特定的 GitHub 帐户。 - -用户和组织站点始终从名为 .github.io 或 .github.io 的仓库发布。 除非您使用自定义域,否则用户和组织站点位于 http(s)://.github.io 或 http(s)://.github.io。 - -项目站点的源文件与其项目存储在同一个仓库中。 除非您使用自定义域,否则项目站点位于 http(s)://.github.io/ 或 http(s)://.github.io/。 -[更多](https://help.github.com/cn/github/working-with-github-pages/about-github-pages) - -#### [这里](http://www.chengweiyang.cn/gitbook/github-pages/README.html)也包含推送到**github.page**的方法 -- master, 保存书籍的源码 -- gh-pages, 保存书籍编译后的 HTML 文件 - -**步骤:** - -- `gitbook build` 将书籍内容输出到默认目录,也就是当前目录下的 _book 目录 - - ![gitbook_pdf](https://github.com/lemonchann/lemonchann.github.io/raw/master/images/2019-11-18-new_gitbook_tutors/gitbook_pdf.png) - -- 创建gh-pages分支,并且删除不需要的文件,仅保留git目录和 _book目录 -> $ git checkout --orphan gh-pages -$ git rm --cached -r . -$ git clean -df -$ rm -rf *~` -- 然后,加入 _book 下的内容到分支中: -> $ cp -r _book/* . -$ git add . -$ git commit -m "Publish book" -- 将编译好的书籍内容上传到 GitHub 项目的 远程gh-pages 分支了 -> $git push -u origin gh-pages - - -### 参考 -[详细教程](https://jackchan1999.github.io/2017/05/01/gitbook/GitBook%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B/) -[官方指引-integrations-Github](https://docs.gitbook.com/integrations/github) -[Github的GitBook项目](https://github.com/GitbookIO/gitbook/blob/master/docs/setup.md) -[github pages中文帮助](https://help.github.com/cn/github/working-with-github-pages/about-github-pages) \ No newline at end of file diff --git a/_posts/2019-11-22-create_blog_with_github_pages.md b/_posts/2019-11-22-create_blog_with_github_pages.md deleted file mode 100644 index 5341caff62..0000000000 --- a/_posts/2019-11-22-create_blog_with_github_pages.md +++ /dev/null @@ -1,375 +0,0 @@ ---- -layout: post -title: "可能是最全面的github pages搭建个人博客教程" -date: 2019-11-22 -tags: [geek] -comments: true -author: lemonchann ---- - -作为一个程序员怎么能没有自己的个人博客呢,这里详细记录和分享我的博客搭建经验,让你轻轻松松拥有自己的博客网站。 傻瓜式一站式教你用github pages 来搭建博客,详细记录全过程。 - - - -## 开始 - -先看下博客整体效果。[**点击在线预览我的博客**]( https://lemonchann.github.io/ ) - -![blogPage](https://raw.githubusercontent.com/lemonchann/lemonchann.github.io/master/images/2019-11-22-create_blog_with_github_pages/blogPage.png) - -### 支持特性 - -- 简约风格博客 - -- Powered By Jekyll - -- 博客文章搜索 - -- 自定义社交链接 - -- 网站访客统计 - -- Google Analytics 网站分析 - -- Gitalk评论功能 - -- 自定义关于about页面 - -- 支持中文布局 - -- 支持归档与标签 - - - -## 建立博客Git仓库 - -首先你要在[github](https://github.com/)上有自己博客仓库,用来生成和存放博客文章。你可以直接fork我的博客仓库。这样你马上有了自己的博客仓库。 - -[点这里我的博客地址](https://github.com/lemonchann/lemonchann.github.io)进去fork,之后在你自己的仓库下会看到刚复制的仓库。以后的操作都在你自己的仓库进行。 - -![fork博客](https://raw.githubusercontent.com/lemonchann/lemonchann.github.io/master/images/2019-11-22-create_blog_with_github_pages/fork%E5%8D%9A%E5%AE%A2.png) - -**版权声明: fork之后_posts文件夹内容是我的博客文章,版权归我所有。你可以选择删除里面的文章替换上自己的或者转载附上链接注明出处。 ** - -## 修改博客仓库名称 - -进到你自己的博客仓库,修改博客仓库名称成你自己的用户名。github page解析的时候找的是这个 username.github.io的仓库名。 - -![修改仓库名称](https://raw.githubusercontent.com/lemonchann/lemonchann.github.io/master/images/2019-11-22-create_blog_with_github_pages/%E4%BF%AE%E6%94%B9%E4%BB%93%E5%BA%93%E5%90%8D%E7%A7%B0.png) - -此时,不出意外的话,打开域名https://username.github.io 就能看到你刚搭建的博客了。*注意替换username成你自己的github用户名*。 - -## 博客配置 - -上面点开域名看到的还是我的博客配置,显示的博客名字也是我的。还需要更改配置才是你的博客。 - -博客的配置文件是仓库根目录下的_config.yml文件,直接点开它编辑。 - -![config文件](https://raw.githubusercontent.com/lemonchann/lemonchann.github.io/master/images/2019-11-22-create_blog_with_github_pages/config%E6%96%87%E4%BB%B6.png) - -你还需要更改以下配置: - -### 博客名称和描述 - -![更改名称](https://raw.githubusercontent.com/lemonchann/lemonchann.github.io/master/images/2019-11-22-create_blog_with_github_pages/%E6%9B%B4%E6%94%B9%E5%90%8D%E7%A7%B0.png) - -分别是博客名称和描述,自己任意写点啥。 - -### 博客社交链接 - -![更改社交链接](https://raw.githubusercontent.com/lemonchann/lemonchann.github.io/master/images/2019-11-22-create_blog_with_github_pages/%E6%9B%B4%E6%94%B9%E7%A4%BE%E4%BA%A4%E9%93%BE%E6%8E%A5.png) - -这里配置社交链接按钮,没配的不显示,我现在配了知乎、邮箱、github账号三个。其他你想加自己加上就可以。 - -### 配置gitalk - -这个是评论功能的配置。评论功能基于gitalk,在配置文件中找到gitalk配置项目: - -修改规则如下: - -```yml -gitalk: - clientID: <你的clientID> - clientSecret: <你的clientSecret> - repo: <你的repository名称> - owner: <你的GitHub用户名> -``` - -原理是利用github的issues评论文章。其中clientID和clientSecret需要[点击这里创建](https://github.com/settings/applications/new) - -![创建gitalk鉴权app](https://raw.githubusercontent.com/lemonchann/lemonchann.github.io/master/images/2019-11-22-create_blog_with_github_pages/%E5%88%9B%E5%BB%BAgitalk%E9%89%B4%E6%9D%83app.png) - -点绿色按钮创建,成功之后会得到以上两个id,修改配置即可。 - -### Google站长统计 - -首先你要去注册一个[Google Analytics]( https://analytics.google.com/analytics/ )账号,它可以统计你博客网站的访问人数,访问来源等非常丰富的网站数据。如果你不在乎可以不用跳过这节。不过要把配置中我的`google_analytics: UA-XXXXXXX-X`删除,**否则统计到我的去了**。 - -``` -# Enter your Google Analytics web tracking code (e.g. UA-2110908-2) to activate tracking -google_analytics: UA-XXXXXXX-X -``` - -下面是我的网站实时分析页面展示: - -![google分析页面](https://raw.githubusercontent.com/lemonchann/lemonchann.github.io/master/images/2019-11-22-create_blog_with_github_pages/google%E5%88%86%E6%9E%90%E9%A1%B5%E9%9D%A2.png) - -由于不可描述的原因,国内注册账号可能会遇到问题,所有不配置也没关系。 - -### 博客网址配置 - -``` -# Your website URL (e.g. http://barryclark.github.io or http://www.barryclark.co) -# Used for Sitemap.xml and your RSS feed -url: https://yourname.github.io -``` - -这里配置你自己的博客地址。 - -### 配置提交 - -对_config.ymld的修改需要提交才能生效,点下图中绿色按钮提交。 - -![配置提交](https://raw.githubusercontent.com/lemonchann/lemonchann.github.io/master/images/2019-11-22-create_blog_with_github_pages/%E9%85%8D%E7%BD%AE%E6%8F%90%E4%BA%A4.png) - -**done! 现在输入上面提到的博客地址,回车,你拥有了自己的博客。** - -## 如何写博客 - -好了,博客有了。如何更新文章呢? - -文章用markdown语法,写好统一放在_post文件夹下上传,git page会自动从你的git仓库拉去解析成网页,立刻就能在你的博客网页浏览。 - -关于文章的**命名格式**:博客文章必须按照统一的命名格式 `yyyy-mm-dd-blogName.md` 比如我这篇博客的名字是`2019-11-22-create_blog_with_github_pages.md` - -**看到这里,如果只是简单的想写博客,后面的不看也可以了,后面章节是记录一些DIY的过程。** - -## 本地博客预览 - -到目前为止,我们提交的文章都是必须上传到github仓库才能预览。如果你想写完在本地浏览器看一下效果在上传也是可以的,因为不是所有人都有这样的需求。 - -### 安装 Ruby 和 DevKit - -在官网下载,[点这里]( https://rubyinstaller.org/downloads/ )下载适合系统版本的 [Ruby+Devkit](https://github.com/oneclick/rubyinstaller2/releases/download/RubyInstaller-2.6.5-1/rubyinstaller-devkit-2.6.5-1-x64.exe) 包。安装,弹出的窗口选3 - -![安装ruby](https://github.com/lemonchann/lemonchann.github.io/raw/master/images/2019-11-22-create_blog_with_github_pages/%E5%AE%89%E8%A3%85ruby.PNG) - -`gem -v` `ruby -v` 查看得到版本号就说明成功了。 - -如果是在墙内,需要切换安装源到https://gems.ruby-china.com/。墙外请忽略。 - -`gem sources --add https://gems.ruby-china.com/ --remove https://rubygems.org/` 切换安装源 - -`gem sources -l` 查看版本 - -### bundler安装 - -`gem install bundler` 安装bundler - -`bundle -v 查看版本 - bundle config mirror.https://rubygems.org https://gems.ruby-china.com` 切换安装源 - -### 安装jekyll - -` gem install jekyll` - -![jekyll安装](https://github.com/lemonchann/lemonchann.github.io/raw/master/images/2019-11-22-create_blog_with_github_pages/jekyll%E5%AE%89%E8%A3%85.PNG) - -### 预览博客 - -` jekyll server` 输入之后打开浏览器,不出意外输入localhost:4000即可看到博客内容。 - -![jekyll_server安装](https://github.com/lemonchann/lemonchann.github.io/raw/master/images/2019-11-22-create_blog_with_github_pages/jekyll_server%E6%88%90%E5%8A%9F.PNG) - -如果你没这么顺利,那以下的错误解决供参考 - -#### 常见错误 - -- 缺少某个包 - -![jekyll_error](https://github.com/lemonchann/lemonchann.github.io/raw/master/images/2019-11-22-create_blog_with_github_pages/jekyll_error.PNG) - -如图,缺少jekyll-paginate,安装即可`gem install jekyll-paginate`若还提示缺少就装啥。 - -![jekyll_server_erro错误2](https://github.com/lemonchann/lemonchann.github.io/raw/master/images/2019-11-22-create_blog_with_github_pages/jekyll_server_erro%E9%94%99%E8%AF%AF2.PNG) - -- 权限拒绝 - - socket.rb:201:in `bind` :Permission denied - bind(2) for 127.0.0.1:4000 (Error:EACCES) - -![jekyll_error_EASSE](https://github.com/lemonchann/lemonchann.github.io/raw/master/images/2019-11-22-create_blog_with_github_pages/jekyll_error_EASSE.png) - -出现这个错误一般是4000端口被占用了,解决方法: - -1. netstat -ano|findstr "4000" 找到占用4000端口的进程ID - -2. 查看最后一列数字就是PID=312964 - - ![netstat查看](https://raw.githubusercontent.com/lemonchann/lemonchann.github.io/master/images/2019-11-22-create_blog_with_github_pages/%E6%9F%A5%E7%9C%8Bnetstat.png) - -3. 打开windows资源管理器,结束该进程. - - ![任务管理器](https://raw.githubusercontent.com/lemonchann/lemonchann.github.io/master/images/2019-11-22-create_blog_with_github_pages/%E4%BB%BB%E5%8A%A1%E7%AE%A1%E7%90%86%E5%99%A8.png) - -4. `$ tasklist|findstr 312964`也能查看进程名,查到结束掉他同步骤3. - - - -## 搜索功能集成 - -博客模板本来是没有搜索功能的,搜索功能依赖[Simple-Jekyll-Search](https://github.com/christian-fei/Simple-Jekyll-Search)提供支持。 - -### 配置search.json - -[复制这份代码到你博客的根目录](https://github.com/christian-fei/Simple-Jekyll-Search/blob/master/example/search.json) - -这个配置文件代表可以按博客的标题、标签、时间、分类搜索。 - -### 下载simple-jekyll-searchj文件 - -[下载这整个文件夹](https://github.com/christian-fei/Simple-Jekyll-Search/tree/master/example/js),里面包含simple-jekyll-search.min.js和simple-jekyll-search.js两个文件,连同js文件夹放在你的根目录下面。 - -### 配置搜索框标签 - -在你想展示搜索框的页面我的是index.html,这个页面和每个人的博客模板有关,可能需要一点前端知识,添加如下的html标签。 - -```html -
- -
    -
    - - - - - -``` - -其中,以下两个是二选一的,一个是用云端的js一个是用本地的js如果本地有的话。 - -`` - -配置完成,打开博客,你得到这样一个搜索框。 - -![search_block](https://raw.githubusercontent.com/lemonchann/lemonchann.github.io/master/images/2019-11-22-create_blog_with_github_pages/search_block.png) - -## 搜索框样式 - -搜索框的样式是可以改变的,这里有修改HTML中CSS样式的方法,我搞后端的,前端现学现卖。 - -[html插入标签样式方法](https://blog.csdn.net/u014103733/article/details/72961366) - - - -## 社交链接 - -模板提供的链接没有知乎链接,或者你想增加自定义的链接,都可以通过以下方法添加。以增加zhihu链接为例 - -链接的图片是svg格式的(我也刚知道),大概了解一下什么是svg和viewBox - -[viewBox](https://developer.mozilla.org/zh-CN/docs/Web/SVG/Attribute/viewBox) - -> viewBox属性的值是一个包含4个参数的列表 `min-x`, `min-y`, `width` and `height`, 以空格或者逗号分隔开, 在用户空间中指定一个矩形区域映射到给定的元素,查看属性 - -[深入简出 SVG 教程](https://zhuanlan.zhihu.com/p/36138381) - -### 配置_config.yml - -```yml -footer-links: - weibo: yourname #请输入你的微博个性域名 https://www.weibo.com/ - zhihu: yourname #输入你知乎主页链接上的名字 https://https://www.zhihu.com/people/ -``` - -### 修改svg-icons.html - -因为footer.html中调用了svg-icons.html来生成社交链接。 - -可见是先调用了svg-icon.html显示社交链接,所以修改_include/svg-icons.html增加zhihu链接 - -```html -{% if site.footer-links.zhihu %} -
  • - {% endif %} -``` - -上面配置内容应该都能理解,`viewBox` 指定图片大小。 - -主要是`path d=` 内容的获取,这里其实是指定svg图片的内容,我们可以从 [这里](https://raw.githubusercontent.com/FortAwesome/Font-Awesome/master/svgs/brands/)获取到大部分svg素材,比如知乎的svg[在这](https://github.com/FortAwesome/Font-Awesome/blob/master/svgs/brands/zhihu.svg),点`raw` 按钮查看源文件,复制`path d=`后面的内容到上面的配置即可。 - -![zhihuSvg](https://raw.githubusercontent.com/lemonchann/lemonchann.github.io/master/images/2019-11-22-create_blog_with_github_pages/zhihuSvg.png) - - - -## 添加网站计数 - -网站统计[由不蒜子](http://busuanzi.ibruce.info/)提供支持,就是可以统计网站当前访问次数和人数。配置也非常简单,[官方指引](http://ibruce.info/2015/04/04/busuanzi/#more)在这里。 - -### 修改页面html - -想让统计显示在哪个页面,需要修改那个页面的html,增加如下内容: - -```html - - - -
    - - View: - - - - User: - -
    -``` - -### style标签说明 - -可以通过style标签改变字体颜色与大小。具体参考:[html颜色表](http://xh.5156edu.com/page/z1015m9220j18754.html)和[html style属性](https://www.geeksforgeeks.org/html-style-attribute/) - -eg. `style="font-family:arial;color:Gainsboro;font-size:10px; text-align:right;width:200px;background-color:gray;` - - - -## 如何传图片 - -写markdown最头疼的就是图片的插入了,推荐用[PicGo](https://picgo.github.io/PicGo-Doc/zh/guide/)一键上传得到链接,直接可以插入markdown。 - -PicGo支持图片上传github、SM.MS图床、阿里云、腾讯云等主流图床或云端。直接拖图片,上传云端、得到链接一步搞定,方便快捷。 - -![PicGo](https://raw.githubusercontent.com/lemonchann/lemonchann.github.io/master/images/2019-11-22-create_blog_with_github_pages/PicGo.png) - -## 其他功能 - -[小功能](https://blog.csdn.net/ds19991999/article/details/81293467) - -[好用的github插件](https://blog.csdn.net/u012702547/article/details/100533763) - -## 网站结构 - -根目录的index.html生成blog首页 - -_include/footer.html生成侧边栏 - -_include/svg-icons.html生成社交头像的链接 - -## 致谢 - -感谢Jekyll提供的技术支持才能有这个博客。 - -感谢[LOFFER](https://fromendworld.github.io/LOFFER/document/)提供的原始模板,我在其上进行的二次开发。 \ No newline at end of file diff --git a/_posts/2019-12-27-cpp_reference.md b/_posts/2019-12-27-cpp_reference.md deleted file mode 100644 index 5d827d0e6f..0000000000 --- a/_posts/2019-12-27-cpp_reference.md +++ /dev/null @@ -1,984 +0,0 @@ ---- -layout: post -title: "腾讯后台开发面试笔试C++知识点参考笔记" -date: 2019-12-29 -tags: [c++] -comments: true -author: lemonchann ---- - -**文章是由我笔试面试腾讯笔记整理而来,主要是针对面试的C++后台开发岗位,涵盖了大部分C++后台开发相关的,可能会考察和被问到的技术点。** - -**自认为这篇笔记比较全面的涵盖了,后台开发C++笔试面试大部分知识点,不管你是已经工作准备参加社招,还是在校学生准备参加校招,笔记都可以作为技术面试准备阶段参考查阅,查缺补漏。** - -笔记是基础C++知识点总结,没有过多的阐述后台开发的系统架构,和分布式后台服务设计相关内容,以及C++11新特性,这些在笔试面试也会被问到但不在这篇讨论范围,可以关注我后面有机会补上。 - -### 阅读提示 - -文章约12839字,阅读时长预计33分钟。建议关注收藏方便回头查阅。 - -### gdb调试命令 - -#### step和next的区别? - -当前line有函数调用的时候,next会直接执行到下一句 ,step会进入函数. - -#### 查看内存 - -> (gdb)p &a //打印变量地址 - -> (gdb)x 0xbffff543 //查看内存单元内变量 - -> 0xbffff543: 0x12345678 - -> (gdb) x /4xb 0xbffff543 //单字节查看4个内存单元变量的值 - -> 0xbffff543: 0x78 0x56 0x34 0x12 - -#### 多线程调试 - -> (gdb) info threads:查看GDB当前调试的程序的各个线程的相关信息 - -> (gdb) thread threadno:切换当前线程到由threadno指定的线程 - -> break filename:linenum thread all 在所有线程相应行设置断点,注意如果主线程不会执行到该行,并且启动all-stop模式,主线程执行n或s会切换过去 - -> set scheduler-locking off|on\step 默认off,执行s或c其它线程也同步执行。on,只有当前相称执行。step,只有当前线程执行 - -> show scheduler-locking 显示当前模式 - -> thread apply all command 每个线程执行同意命令,如bt。或者thread apply 1 3 bt,即线程1,3执行bt。 - -#### 查看调用堆栈 - -> (gdb)bt - -> (gdb)f 1 //帧简略信息 - -> (gdb)info f 1 //帧详细信息 - -#### 断点 - -> b test.cpp:11 - -> b test.cpp:main - -gdb attach 调试方法: - -> gdb->file xxxx->attach pid->**这时候进程是停止的**->c 继续运行 - -#### 带参数调试 - -输入参数命令set args 后面加上程序所要用的参数,注意,不再带有程序名,直接加参数,如: - -> (gdb)set args -l a -C abc - -#### list命令 - -> list linenum  //显示程序第linenum行的周围的程序 - -> list function  //显示程序名为function的函数的源程序 - - - -### static关键字的作用 - - - -### 软硬链接 - -ln -s 源文件 目标文件, ln -s / /home/good/linkname链接根目录/到/home/good/linkname - -1. 软链接就是:“ln –s 源文件 目标文件”,只会在选定的位置上生成一个文件的镜像,不会占用磁盘空间,类似与windows的快捷方式。 - -2. 硬链接ln源文件目标文件,没有参数-s, 会在选定的位置上生成一个和源文件大小相同的文件,无论是软链接还是硬链接,文件都保持同步变化。 - - - -### 函数指针 - - int (*func)(int, int) //函数指针 - - int (*funcArry[10])(int, int) //函数指针数组 - -const int* p; //指向const int的指针 - -int const* p; //同上 - -int* const p; //const指针 - - - -### 设计模式 - -[单例模式](http://blog.csdn.net/wuzhekai1985/article/details/6665869) - -[观察者模式(也叫发布订阅模式](http://blog.csdn.net/wuzhekai1985/article/details/6674984)) - -[工厂模式](http://blog.csdn.net/wuzhekai1985/article/details/6660462) 三种:简单工厂模式、工厂方法模式、抽象工厂模式 - -为什么要用工厂模式?原因就是对上层的使用者隔离对象创建的过程;或者是对象创建的过程复杂, - -使用者不容易掌握;或者是对象创建要满足某种条件,这些条件是业务的需求也好,是系统约束也好 - -,没有必要让上层使用者掌握,增加别人开发的难度。所以,到这时我们应该清楚了,无论是工厂模式, - -还是上面的战友说的开闭原则,都是为了隔离一些复杂的过程,使得这些复杂的过程不向外暴露, - -如果暴露了这些过程,会对使用者增加麻烦,这也就是所谓的团队合作。 - -### 数据结构 - -#### [各种排序算法](http://blog.csdn.net/daguairen/article/details/52611874) - -#### [堆排序](https://www.cnblogs.com/0zcl/p/6737944.html) - -关键:1.初始建堆从最后一个非叶节点开始调整 2.筛选从顶点开始往下调整 - -#### [通俗易懂的快排]( http://blog.csdn.net/vayne_xiao/article/details/53508973) - -#### 二叉树定理 - -度为2节点数 = 叶子节点数 - 1 - -证明:树枝数=节点数-1, n0*0 +n1*1 +n2*2 = n0+n1+n2-1 (n0代表度为0的节点数,以此类推) - - - -### 互斥锁 - -```c -pthread_mutex_t m_mutex; -pthread_mutex_init(&m_mutex, NULL)等效于pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER -pthread_mutex_lock(&m_mutex); -pthread_mutex_unlock(&m_mutex) -pthread_mutex_destroy(&m_mutex) -int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg); -bool g_flag = false; -void* t1(void* arg) -{ - cout << "create t1 thread success" << endl; - pthread_mutex_lock(&m_mutex); - g_flag = true; - pthread_mutex_unlock(&m_mutex); -} - -void* t2(void* arg) -{ - cout << "create t2 thread success" << endl; - pthread_mutex_lock(&m_mutex); - g_flag = false; - pthread_mutex_unlock(&m_mutex); -} - -int main(int argc, char* argv[]) -{ - pthread_t tid1, tid2; - pthread_create(&tid1, NULL, t1, NULL); - sleep(2); - pthread_create(&tid2, NULL, t2, NULL); - pthread_join(tid1, NULL); - pthread_join(tid2, NULL); -} -``` - - - -### 大小端转换 - -```c -#define BigLittleSwap32(A) ((((uint32)(A) & 0xff000000) >> 24) | \ - (((uint32)(A) & 0x00ff0000) >> 8) | \ - (((uint32)(A) & 0x0000ff00) << 8) | \ - (((uint32)(A) & 0x000000ff) << 24)) -``` - - - -### io多路复用 - -[为什么 IO 多路复用要搭配非阻塞IO]( https://www.zhihu.com/question/37271342) - -设置非阻塞 `io fcntl(sockfd, F_SETFL, O_NONBLOCK); ` - -#### select - -```c -int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout); - -void FD_CLR(int fd, fd_set *set); - -int FD_ISSET(int fd, fd_set *set); - -void FD_SET(int fd, fd_set *set); - -void FD_ZERO(fd_set *set); - -fd_set rdfds; -struct timeval tv; -int ret; -FD_ZERO(&rdfds); -FD_SET(socket, &rdfds); -tv.tv_sec = 1; -tv.tv_uses = 500; -ret = select (socket + 1, %rdfds, NULL, NULL, &tv); -if(ret < 0) perror (“select”); -else if (ret = = 0) printf(“time out”); -else -{ - printf(“ret = %d/n”,ret); - if(FD_ISSET(socket, &rdfds)){ - /* 读取socket句柄里的数据 */ -}注意select函数的第一个参数,是所有加入集合的句柄值的最大那个那个值还要加1.比如我们创建了3个句柄; -``` - - - -#### poll实现 - -poll的实现和select非常相似,只是描述fd集合的方式不同,poll使用pollfd结构而不是select的fd_set结构,其他的都差不多,管理多个描述符也是进行轮询,根据描述符的状态进行处理,但是poll没有最大文件描述符数量的限制。poll和select同样存在一个缺点就是,包含大量文件描述符的数组被整体复制于用户态和内核的地址空间之间,而不论这些文件描述符是否就绪,它的开销随着文件描述符数量的增加而线性增大。 - -#### epoll原理 - -https://www.cnblogs.com/Anker/archive/2013/08/17/3263780.html - -```c -#include -int epoll_create(int size); - -int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event); - -int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout); -``` - -**epoll对文件描述符的操作有两种模式:LT(level trigger)和ET(edge trigger)。LT模式是默认模式,LT模式与ET模式的区别如下:** - -LT模式:当epoll_wait检测到描述符事件发生并将此事件通知应用程序,应用程序可以不立即处理该事件。下次调用epoll_wait时,会再次响应应用程序并通知此事件。 - -ET模式:当epoll_wait检测到描述符事件发生并将此事件通知应用程序,应用程序必须立即处理该事件。如果不处理,下次调用epoll_wait时,不会再次响应应用程序并通知此事件。 - -ET模式在很大程度上减少了epoll事件被重复触发的次数,因此效率要比LT模式高。epoll工作在ET模式的时候, - -必须使用非阻塞套接口,以避免由于一个文件句柄的阻塞读/阻塞写操作把处理多个文件描述符的任务饿死。 - -Epoll ET模型下,为什么每次EPOLLIN事件都会带一次EPOLLOUT事件: https://bbs.csdn.net/topics/390630226 - - - -#### udp套接字 - - [ref1](http://blog.csdn.net/chenhanzhun/article/details/41914029) - - [ref1](https://www.cnblogs.com/bleopard/p/4004916.html) - -```c -#include - -ssize_t sendto(int sockfd, void *buff, size_t nbytes, int flags, const struct sockaddr *destaddr, socklen_t addrlen); - -ssize_t recvfrom(int sockfd, void *buff, size_t nbytes, int flags, struct sockaddr *addr, socklen_t *addrlen); -``` - - - -### 网络套接字 - -#### udp原理与套接字 - -udp服务端: - -```c -sockListener=socket(AF_INET,SOCK_DGRAM,0) - -bind(sockListener,(struct sockaddr*)&addrListener,sizeof(addrListener)) - -nMsgLen=recvfrom(sockListener,szBuf,1024,0,(struct sockaddr*)&addrClient,&addrLen) -``` - -udp客户端 - -```c -sockClient=socket(AF_INET,SOCK_DGRAM,0); -bind(sockClient,(struct sockaddr*)&addrLocal,sizeof(addrLocal)) -FD_ZERO(&setHold); -FD_SET(STDIN_FILENO,&setHold); -FD_SET(sockClient,&setHold); -cout<<"you can type in sentences any time"< 4字节单位- 首部长度单位 1字节单位-总长度单位 8字节单位-片偏移单位 - -### STL容器 - -#### vector与list - -1.vector数据结构 - -vector和数组类似,拥有一段连续的内存空间,并且起始地址不变。 - -因此能高效的进行随机存取,时间复杂度为o(1); - -但因为内存空间是连续的,所以在进行插入和删除操作时,会造成内存块的拷贝,时间复杂度为o(n)。 - -另外,当数组中内存空间不够时,会重新申请一块内存空间并进行内存拷贝。 - - 2.list数据结构 - -list是由双向链表实现的,因此内存空间是不连续的。 - -只能通过指针访问数据,所以list的随机存取非常没有效率,时间复杂度为o(n); - -但由于链表的特点,能高效地进行插入和删除。 - -#### [Vector动态内存分配]( https://blog.csdn.net/xnmc2014/article/details/86748138) - -这个问题其实很简单,在调用push_back时,若当前容量已经不能够放入心得元素(capacity=size),那么vector会重新申请一块内存,把之前的内存里的元素拷贝到新的内存当中,然后把push_back的元素拷贝到新的内存中,最后要析构原有的vector并释放原有的内存。所以说这个过程的效率是极低的,为了避免频繁的分配内存,C++每次申请内存都会成倍的增长,例如之前是4,那么重新申请后就是8,以此类推。当然不一定是成倍增长,比如在我的编译器环境下实测是0.5倍增长,之前是4,重新申请后就是6 - -[TinySTL]( https://github.com/zouxiaohang/TinySTL/tree/master/TinySTL) - - - -### 预处理指令 - -\#pragma once 防止头文件重复引用 - -一字节对齐 - -\#pragma pack(push, 1) - -\#pragma pack(pop) - - - -### class面向对象 - -#### 类继承 - -class LayerManager : public ILayerManager{}; - - - -#### 为什么析构函数要是虚函数? - -基类指针可以指向派生类的对象(多态性),如果删除该指针delete []p;就会调用该指针指向的派生类析构函数,而派生类的析构函数又自动调用基类的析构函数,这样整个派生类的对象完全被释放。如果析构函数不被声明成虚函数,则编译器实施静态绑定,在删除基类指针时,只会调用基类的析构函数而不调用派生类析构函数,这样就会造成派生类对象析构不完全。所以,将析构函数声明为虚函数是十分必要的。 - - - -#### 覆盖虚函数机制 - -在某些情况下,希望覆盖虚函数机制并强制函数调用使用虚函数的特定版 - -本,这里可以使用作用域操作符: - -```c++ -Item_base *baseP = &derived; - -// calls version from the base class regardless of the dynamic type of baseP -double d = baseP->Item_base::net_price(42); -``` - -这段代码强制将 net_price 调用确定为 Item_base 中定义的版本,该调用 - -将在编译时确定。**只有成员函数中的代码才应该使用作用域操作符覆盖虚函数机制。** - -**为什么会希望覆盖虚函数机制?最常见的理由是为了派生类虚函数调用基类中的版本。**在这种情况下,基类版本可以完成继承层次中所有类型的公共任务,而每个派生类型只添加自己的特殊工作。 - -例如,可以定义一个具有虚操作的 Camera 类层次。Camera 类中的 display函数可以显示所有的公共信息,派生类(如 PerspectiveCamera)可能既需要显示公共信息又需要显示自己的独特信息。可以显式调用 Camera 版本以显示公共信息,而不是在 PerspectiveCamera 的 display 实现中复制 Camera 的操作。 - -在这种情况下,已经确切知道调用哪个实例,因此,不需要通过虚函数机制。派生类虚函数调用基类版本时,必须显式使用作用域操作符。如果派生类函数忽略了这样做,则函数调用会在运行时确定并且将是一个自身调用,从而导致无穷递归。 - - - -#### 名字冲突与继承 - -虽然可以直接访问基类成员,就像它是派生类成员一样,但是成员保留了它 - -的基类成员资格。一般我们并不关心是哪个实际类包含成员,通常只在基类和派 - -生类共享同一名字时才需要注意。 - -与基类成员同名的派生类成员将屏蔽对基类成员的直接访问。 - -```c -struct Base -{ - Base(): mem(0) { } - protected: - int mem; -}; - -struct Derived : Base -{ - Derived(int i): mem(i) { } // initializes Derived::mem - int get_mem() { return mem; } // returns Derived::mem - protected: - int mem; // hides mem in the base -}; - -get_mem 中对 mem 的引用被确定为使用 Derived 中的名字。如果编写如下代码: -Derived d(42); -cout << d.get_mem() << endl; // prints 42 -``` - -则输出将是 42。 - -使用作用域操作符访问被屏蔽成员 - -可以使用作用域操作符访问被屏蔽的基类成员: - -```c -struct Derived : Base -{ - int get_base_mem() { return Base::mem; } -}; -``` - -作用域操作符指示编译器在 Base 中查找 mem。 - -设计派生类时,只要可能,最好避免与基类数据成员的名字相同 - - - -#### 类成员函数的重载、覆盖和隐藏区别? - -a.成员函数被重载的特征: - -(1)相同的范围(在同一个类中); - -(2)函数名字相同; - -(3)参数不同; - -(4)virtual 关键字可有可无。 - -b.覆盖是指派生类函数覆盖基类函数,特征是: - -(1)不同的范围(分别位于派生类与基类); - -(2)函数名字相同; - -(3)参数相同; - -(4)基类函数必须有virtual 关键字。 - -c.“隐藏”是指派生类的函数屏蔽了与其同名的基类函数,规则如下: - -(1)如果派生类的函数与基类的函数同名,但是参数不同。此时,不论有无virtual关键字,基类的函数将被隐藏(注意别与重载混淆,仅同名就可以)。 - -(2)如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有virtual 关键字。此时,基类的函数被隐藏(注意别与覆盖混淆) - - - -#### 纯虚函数 - -```c -class Disc_item : public Item_base - -{ - public: - double net_price(std::size_t) const = 0; -}; -``` - -含有(或继承)一个或多个纯虚函数的类是抽象基类。除了作 - -为抽象基类的派生类的对象的组成部分,甚至不能创建抽象类型Disc_item的对象。 - - - -### 模板编程 - -#### 函数模板 - -```c -template -int compare(const T &v1, const T &v2) -{ - if (v1 < v2) return -1; - if (v2 < v1) return 1; - return 0; -} - -``` - -使用compare(1, 2) - -#### 类模板 - -```c -template class Queue - -{ - -public: - - Queue (); // default constructor - Type &front (); // return element from head of Queue - const Type &front () const; - void push (const Type &); // add element to back of Queue - void pop(); // remove element from head of Queue - bool empty() const; // true if no elements in the Queue - private: - // ... -}; -``` - -使用Queue qi; - - - -### 操作符重载 - -#### 输出操作符 - -输出操作符通常是非成员函数,定义成类的友元 - -```c -friend ostream& operator<<(ostream& out, const Sales_item& s) -{ - out << s.isbn << "\t" << s.units_sold << "\t" - << s.revenue << "\t" << s.avg_price(); - return out; -} -``` - -#### 算术和关系操作 - -算术和关系操作符定义为非成员函数 - - 为了与内置操作符保持一致,加法返回一个右值,而不是一个引用。 - -```c -Sales_item operator+(const Sales_item& lhs, const Sales_item& rhs) - -{ - - Sales_item ret(lhs); // copy lhs into a local object that we'll - ret += rhs; // add in the contents of rhs - return ret; // return ret by value -} - -int operator<(const TableIndex2D& right) const; - -friend bool operator== (const UEContext& info1,const UEContext& info2) const -{ - if(info1.ContextID != info2.ContextID) return false; - return true; -} - -friend bool operator!= (const UEContext& info1,const UEContext& info2) const -{ - return !(info1 == info2); -} -``` - -### 复制控制 - -**包括,一个拷贝构造函数,一个赋值运算符,一个析构函数,一对取址运算符** - -如果你这么写:`class Empty{};` - -和你这么写是一样的: - -```c -class Empty -{ - public: - Empty(); // 缺省构造函数 - Empty(const Empty& rhs); // 拷贝构造函数 - ~Empty(); // 析构函数 ---- 是否 - // 为虚函数看下文说明 - Empty& operator=(const Empty& rhs); // 赋值运算符 - Empty* operator&(); // 取址运算符 - const Empty* operator&() const; -}; - -Empty(const Empty& rhs) -{ - a = rhs.a -} -``` - - - -类赋值操作符必须是类的成员,以便编译器可以知道是否需要合成一个, 赋值必须返回对 *this 的引用。 - -一般而言,赋值操作符与复合赋值操作符应返回操作符的引用 - -```c -Guti& Guti::operator=( const Guti& rhs ) -{ - mtmsi_m = rhs.mtmsi_m; - mmeCode_m = rhs.mmeCode_m; - mmeGid_m = rhs.mmeGid_m; - plmnId_m = rhs.plmnId_m; - return *this; -}; - -注意,检查对自己赋值的情况 -c& c::operator=(const c& rhs) -{ - // 检查对自己赋值的情况 - if (this == &rhs) return *this; - ... -} -``` - - - -### 构造函数初始化式 - -初始化const对象和引用对象的唯一机会。P389 C++ Primer 5th - - - -### 协议 - -#### RTP/RTSP/RTCP - -RTP协议RFC1889和RFC3550 G711 PCMU - -#### HTTP - - - -### Linux基础 - -Linux shell之数组:https://www.cnblogs.com/Joke-Shi/p/5705856.html - -Linux expr命令:http://www.runoob.com/linux/linux-comm-expr.html - -shell中变量类型:local,global,export关键字: https://www.cnblogs.com/kaishirenshi/p/10274179.html - -Linux let 命令:http://www.runoob.com/linux/linux-comm-let.html - -vim修改tab成4个空格写python: http://www.cnblogs.com/wi100sh/p/4938996.html - -python判断文件是否存在的几种方法: https://www.cnblogs.com/jhao/p/7243043.html - -python--文件操作删除某行: https://www.cnblogs.com/nopnog/p/7026390.html - -pytho3字典遍历的几种操作: https://www.jb51.net/article/138414.htm - - - -chmod - -命令名称: chmod - -执行权限: 所有用户 - -功能描述: 改变文件或目录权限 - -语法: 第一种方法 chmod [{ugoa}{+-=}{rwx}] [文件或目录] - -​ 备注: u:所有者 g:所属组 o:其他人 a:所有人 - -​ +:为用户增加权限 -:为用户减少权限 =:为用户赋予权限 - -​ r:读权限 w:写权限 x:执行权限 - - - -​ 第二种方法 chmod -R [mode=421] [文件或目录] ←(这种方法用的比较多) - -​ 备注: r:4 w:2 x:1 - -​ r为读权限,可以用4来表示, - -​ w为写权限,可以用2来表示, - -​ x为执行权限,可以用1来表示。 - - - -### new操作 - -动态分配数组int *pia = new int[10]; // array of 10 uninitialized ints - -释放分配的数组 delete [] pia; - -#### new数组 - -```c -int *arr = new int[1024] -delte [] a -# 堆上new 对象 -class MyClass -{ - MyClass(int a) {}; - int empty() {return 0;}; -}; - -MyClass *p = new MyClass(1); -delete p; - -# 栈上分配 对象 -MyClass test(1); -``` - - - -#### 放置式new - -区分以下几种操作符号: - -new operator-普通的new关键字 - -operator new-仅仅申请内存返回void* - -placement new-在指定内存调用构造函数初始化类 - -new [] operator-如果是类对象,会在首部多申请4字节内存用于保存对象个数 - - - -深入探究 new 和 delete https://blog.csdn.net/codedoctor/article/details/76187567 - -当我们使用关键字new在堆上动态创建一个对象A时,比如 A* p = new A(),它实际上做了三件事: - -向堆上申请一块内存空间(做够容纳对象A大小的数据)(operator new) - -调用构造函数 (调用A的构造函数(如果A有的话))(placement new) - -返回正确的指针 - -当然,如果我们创建的是简单类型的变量,那么第二步会被省略。 - - - -当我们delete的时候也是如此,比如我们delete p 的时候,其行为如下: - -定位到指针p所指向的内存空间,然后根据其类型,调用其自带的析构函数(内置类型不用) - -然后释放其内存空间(将这块内存空间标志为可用,然后还给操作系统) - -将指针标记为无效(指向NULL) - - - -https://blog.csdn.net/rain_qingtian/article/details/14225211 - -```c - - -void* p=::operator new (sizeof(Buffer)); //创建一块内存;冒号表示全局的new -Buffer* bp= start_cast(p); //指针进行装换 -Buffer* buf3=new(bp) Buffer(128); //把bp指针指向的内存租借buf3, -buf3->put('c'); -buf3->~Buffer(); //这里析够函数要显示调用 -::operator delete(p); -``` - - - -[放置new构造对象数组](https://bbs.csdn.net/topics/392271390) - -![放置new对象数组](https://github.com/lemonchann/lemonchann.github.io/raw/master/images/2019-12-27-cpp_reference/%E6%94%BE%E7%BD%AEnew%E5%AF%B9%E8%B1%A1.png) - - - - - -在栈上分配类内存: https://www.cnblogs.com/weekbo/p/8533368.html - -new与malloc区别 - -b. new和malloc最大区别: new会调用类的构造函数,malloc不会; - -c. delete和free同理;new/delete是运算符,malloc/free函数。所以new/delete效率应该会高点。 - - - -### [Linux IPC机制汇总](https://www.cnblogs.com/Jimmy1988/p/7744659.html) - -#### 管道 - -```c - #include - -无名管道: int pipe(int pipedes[2]) - -有名管道:int mkfifo(const char *pathname, mode_t mode) -``` - - - -#### 消息队列 - -```c -#include - -int msgget(key_t key, int msgflg) //创建 - -int msgctl(int msqid, int cmd, struct msqid_ds *buf) //设置/获取消息队列的属性值 - -int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg) //发送消息到消息队列(添加到尾端) - -ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg) //接收消息 -``` - - - -#### 共享内存 - -```c -#include - -int shmget(key_t key, size_t size, int shmflg) //创建一个共享内存空间 - -int shmctl(int shmid, int cmd, struct shmid_ds *buf) //对共享内存进程操作,包括:读取/设置状态,删除操作 - -void *shmat(int shmid, const void *shmaddr, int shmflg) //将共享内存空间挂载到进程中 - -int shmdt(const void *shmaddr) //将进程与共享内存空间分离 **(****只是与共享内存不再有联系,并没有删除共享内存****)** -``` - - - -#### 信号 - -` #include` - - - -### 手动实现strcpy - -```c -char *strcpy(char *strDest, const char *strSrc) -{ - if ( strDest == NULL || strSrc == NULL) - return NULL ; - if ( strDest == strSrc) - return strDest ; - char *tempptr = strDest ; - while( (*strDest++ = *strSrc++) != ‘/0’) - return tempptr ; -} -``` - - - -### C++对象内存布局 - -这部分详细内容可以参考[深度探索C++对象模型](https://book.douban.com/subject/10427315/) - -#### 虚函数多态机制 - -通过虚表指针访问虚成员函数,对普通成员函数的访问区别于虚成员函数。具体如下: - -virtual member function虚成员函数normalize()的调用实际上转换成: - -(*ptr->vpter[1])(ptr) - -![](https://github.com/lemonchann/lemonchann.github.io/raw/master/images/2019-12-27-cpp_reference/%E6%88%90%E5%91%98%E8%99%9A%E5%87%BD%E6%95%B0%E6%8C%87%E9%92%88.png) - -函数指针也有差别,下面第一个是普通函数指针或者static member function。第二个是non-static member function成员函数指针。 - -![](https://github.com/lemonchann/lemonchann.github.io/raw/master/images/2019-12-27-cpp_reference/%E6%88%90%E5%91%98%E5%87%BD%E6%95%B0%E6%8C%87%E9%92%88.png) - - - -#### 不同继承层次的对象内存布局 - -##### 单一继承 - -![单一继承](https://github.com/lemonchann/lemonchann.github.io/raw/master/images/2019-12-27-cpp_reference/%E5%8D%95%E4%B8%80%E7%BB%A7%E6%89%BF.png) - -![单一继承1](https://github.com/lemonchann/lemonchann.github.io/raw/master/images/2019-12-27-cpp_reference/%E5%8D%95%E4%B8%80%E7%BB%A7%E6%89%BF1.png) - - - -##### 多重继承 - -![多重继承](https://github.com/lemonchann/lemonchann.github.io/raw/master/images/2019-12-27-cpp_reference/%E5%A4%9A%E9%87%8D%E7%BB%A7%E6%89%BF.png) - -![多重继承1](https://github.com/lemonchann/lemonchann.github.io/raw/master/images/2019-12-27-cpp_reference/%E5%A4%9A%E9%87%8D%E7%BB%A7%E6%89%BF1.png) - -![多重继承2](https://github.com/lemonchann/lemonchann.github.io/raw/master/images/2019-12-27-cpp_reference/%E5%A4%9A%E9%87%8D%E7%BB%A7%E6%89%BF2.png) - - - -### 参考 - -[常见C++笔试题](http://blog.csdn.net/dongfengsun/article/details/1541926) \ No newline at end of file diff --git a/_posts/2019-6-12-Play_with_VsCode_MarkDown_preview.md b/_posts/2019-6-12-Play_with_VsCode_MarkDown_preview.md deleted file mode 100644 index 7b8b26a54b..0000000000 --- a/_posts/2019-6-12-Play_with_VsCode_MarkDown_preview.md +++ /dev/null @@ -1,30 +0,0 @@ ---- -layout: post -title: "玩转vscode支持Markdown预览" -date: 2019-6-12 -tags: [markdown,vscode] -comments: true -author: lemonchann ---- - -Markdown是一种可以使用普通文本编辑器编写的标记语言,通过简单的标记语法,它可以使普通文本内容具有一定的格式。 - - - -### Markdown - -Markdown具有一系列衍生版本,用于扩展Markdown的功能(如表格、脚注、内嵌HTML等等),这些功能原初的Markdown尚不具备,它们能让Markdown转换成更多的格式,例如LaTeX,Docbook。Markdown增强版中比较有名的有Markdown Extra、MultiMarkdown、 Maruku等。这些衍生版本要么基于工具,如Pandoc;要么基于网站,如GitHub和Wikipedia,在语法上基本兼容,但在一些语法和渲染效果上有改动。来自[360百科](https://baike.so.com/doc/6949586-7171987.html) - -### VsCode -强大地自定义功能,已经成为程序员最爱编辑器。 -Microsoft在2015年4月30日Build 开发者大会上正式宣布了 Visual Studio Code 项目:一个运行于 Mac OS X、Windows和Linux之上的,针对于编写现代 Web 和云应用的跨平台源代码编辑器。 -该编辑器也集成了所有一款现代编辑器所应该具备的特性,包括语法高亮(syntax high lighting),可定制的热键绑定(customizable keyboard bindings),括号匹配(bracket matching)以及代码片段收集(snippets)。Somasegar 也告诉笔者这款编辑器也拥有对 Git 的开箱即用的支持。引用[360百科](https://baike.so.com/doc/24428308-25261478.html) - -### MarkDown遇上VsCode -#### 有两种方法预览markdown渲染效果 -* Ctrl+Shift+P 打开命令框输入Markdown即可匹配到一系列的MarkDown命令,选择其中的打开预览或打开侧边预览 -* 直接使用快捷键。打开侧边预览 -> Ctrl+K 松开接 V -* 打开预览 ->Ctrl+shift V - diff --git a/_posts/2020-02-24-ubuntu.md b/_posts/2020-02-24-ubuntu.md new file mode 100644 index 0000000000..f744720af5 --- /dev/null +++ b/_posts/2020-02-24-ubuntu.md @@ -0,0 +1,241 @@ +# Ubuntu编译并安装新驱动程序 + +## 内容 +>以编译模块的方法在ubuntu内核中增加一个新的设备驱动程序,功能为实现简单的字符设备(如键盘)读写。 + +## 环境 +>ubuntu版本:16.04.6 +>内核版本:4.15.0-74-generic +>虚拟机:VMware + +## 步骤 +#### 1.安装源码和工具包 +>执行命令查看是否安装源码。 +> +>```shell +>ls -l /usr/src +>``` +>执行命令查看内核版本。 +> +>```shell +>uname -r +>``` +>查看当前内核是否有对应的源码,若无需要去官网下载当前内核版本对应的源码,并将其解压至/usr/src文件夹中。[清华开源镜像站](https://mirrors.tuna.tsinghua.edu.cn/kernel/) +> +>下载工具包: +> +>```shell +>apt-get install build-essential +>``` + +#### 2.编译驱动程序hello.c +>hello.c +> +>```c +>#include +>#include +>#include +>#include +>#include +>#include +>#include +> +>MODULE_LICENSE("GPL"); +>static int device_file_major_number = 0; +>static const char device_name[] = "hello_driver"; +> +>int my_open(struct inode *, struct file *); +>int my_release(struct inode *, struct file *); +>ssize_t my_read(struct file *, char __user *, size_t , loff_t *); +>ssize_t my_write(struct file *, const char __user *, size_t , loff_t *); +> +>struct file_operations fops = { +> .owner=THIS_MODULE, +> .read=my_read, +> .write=my_write, +> .release=my_release, +> .open=my_open, +>}; +>#define BUF_SIZE 100 +>struct cdd_cdev{ +> struct cdev cdev; +> struct device *dev_device; +> u8 led; +> char kbuf[BUF_SIZE]; +>}; +> +>int my_open(struct inode *inode, struct file *filp) +>{ +> struct cdd_cdev *pcdevp = NULL; +> printk("enter my_open()!\n"); +> pcdevp = container_of(inode->i_cdev, struct cdd_cdev, cdev); +> printk("led = %d\n", pcdevp->led); +> filp->private_data = pcdevp; +> return 0; +>} +> +>int my_release(struct inode *inode, struct file *filp) +>{ +> printk("enter my_release()!\n"); +> return 0; +>} +> +>ssize_t my_read (struct file *filp, char __user *buf, size_t count, loff_t *offset) +>{ +> int ret = 0; +> struct cdd_cdev *cdevp = filp->private_data; +> printk("enter my_read()!\n"); +> ret = copy_to_user(buf, cdevp->kbuf, count); +> printk("kernel kbuf content:%s\n", cdevp->kbuf); +> return ret; +>} +>int my_write(struct file *filp, const char __user *buf, size_t count, loff_t *offset) +>{ +> int ret = 0; +> struct cdd_cdev *cdevp = filp->private_data; +> printk("enter my_write()!\n"); +> ret = copy_from_user(cdevp->kbuf, buf, count); +> return ret; +>} +> +> +> +>int __init my_init(void) +>{ +> int result = 0; +> printk( KERN_NOTICE "hello-driver: my_init() is called." ); +> result = register_chrdev( 0, device_name, &fops ); +> if( result < 0 ) +> { +> printk( KERN_WARNING "hello-driver: can\'t register character device with errorcode = %i", result ); +> return result; +> } +> device_file_major_number = result; +> printk( KERN_NOTICE "hello-driver: registered character device with major number = %i and minor numbers 0...255" +> , device_file_major_number ); +> return 0; +>} +> +>void __exit my_exit(void) +>{ +> printk( KERN_NOTICE "hello-driver: my_exit() is called" ); +> if(device_file_major_number != 0) +> { +> unregister_chrdev(device_file_major_number, device_name); +> } +>} +> +>module_init(my_init); +>module_exit(my_exit); +>``` +> +>+ 编写Makefile文件 +> +> ```makefile +> ifeq ($(KERNELRELEASE),) #ifeq后面一定要加空格 +> #非命令行前面不能以tab开头,必须以空格开头 +> KERNELDIR ?= /lib/modules/$(shell uname -r)/build +> M=$(PWD) modules +> PWD := $(shell pwd) +> modules: +> $(MAKE) -C $(KERNELDIR) M=$(PWD) modules #必须以tab开头 +> modules_install: +> $(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install #必须以tab开头 +> clean: +> rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions Module* modules* #必须以tab开头 +> .PHONY: modules modules_install clean +> else +> obj-m :=hello.o #空格开头 +> endif +> ``` +> +>备注: +>1. gcc编译方式只适用于2.4版本以下的内核,编译2.4以上版本的内核需使用make编译。 +>2. 源文件需以.c为后缀,笔者曾尝试编译.cc文件,结果报错。 +>3. Makefile文件名的M必须为大写,否则编译出错。 +>4. 编写Makefile文件时只需把上述代码中的hello替换为自己编写的源文件名除去.c后缀。 +>5. 以root用户执行make命令。 +> + +#### 3.执行make,编译源码 +>```shell +>make +>``` +> +>![make](https://raw.githubusercontent.com/Milaaaaaa/Milaaaaaa.github.io/master/images/2020_02_24/make.png) +> +>编译成功后输出如图,若输出结果与图示不同,则极大可能编译失败。如若输出很多的Entering directory xxx 以及 Leaving directory directory xxx,最后并显示Error时,很可能是因为内核源码版本有问题。笔者在最开始使用的是最新版Ubuntu18.04和5.3.0版本的内核,但make的时候一直出错,在几度崩溃后笔者选择在凌晨2点的夜里带着无尽的怒火关闭了电脑上床入睡(顺带做了一晚上的梦...),并在第二天决定更换稍微旧一点的版本,即本文开端的环境所述,最终make顺利编译成功。 + +#### 4.安装模块 +>执行命令,安装成功后应无任何输出。 +>```shell +>insmod hello.ko +>``` + +#### 5.创建设备文件 +>因为笔者在源码的注册设备文件函数register_chrdev()中传入的第一个参数为0,系统会为新设备随机分配一个未使用的主设备号,所以在创建设备文件前需要获得文件主设备号。 +>```shell +>cat /proc/dev | grep hello +>``` +>得到文件主设备号后我们接着创建设备文件 +>```shell +>mknod /dev/hello c 主设备号 从设备号(可设为0) +>``` +> + +#### 6.编写测试程序 +>当做到这一步时,即将接近尾声! +> +>test.c +> +>``` +>#include +>#include +>#include +>#include +>#include +> +>#define N 512 +>char buf[N]; +> +>int main(){ +> int fd; +> if((fd=open("/dev/hello",O_RDWR))<0){ +> printf("open error!\n"); +> return -1; +> } +> if(read(fd,buf,N)<0){ +> printf("read error!\n"); +> return -1; +> } +> printf("read from /dev/hello is : %s\n",buf); +> printf("input second buf:"); +> scanf("%[^\n]",buf); //忽略空格直至换行 +> if(write(fd,buf,N+1)<0){ +> printf("write error!\n"); +> return -1; +> } +> if(read(fd,buf,N)<0){ +> printf("read error!\n"); +> return -1; +> } +> printf("second read from /dev/hello is : %s\n",buf); +> close(fd); +> return 0; +>} +> +>``` +> +>编译测试文件并执行 +> +>```shell +>gcc test.c -o test +>``` +>```shell +>./test +>``` +>Congratulation ! +> +>End +> +>------ diff --git a/_posts/2020-1-28-redis_distributed_locks.md b/_posts/2020-1-28-redis_distributed_locks.md deleted file mode 100644 index 5533996356..0000000000 --- a/_posts/2020-1-28-redis_distributed_locks.md +++ /dev/null @@ -1,229 +0,0 @@ ---- -layout: post -title: "redis分布式锁3种实现方式对比分析总结" -date: 2020-1-28 -tags: [后台开发] -comments: true -author: lemonchann ---- - -大家春节在家抢红包玩的不亦乐乎,抢红包服务看起来非常简单,实际上要做好这个服务,特别是money相关服务是不允许出错的,想想看每个红包的数字都是真金白银,要求服务的鲁棒性非常高,背后包含着很多后台服务技术细节。 - - - -抛砖引玉,今天就来说说其中一个技术细节,也是在我另一篇文章[Linux后台开发C++学习路线技能加点](https://zhuanlan.zhihu.com/p/102048769)中提到但没展开讲的,高并发服务编程中的**redis分布式锁**。 - -这里罗列出**3种redis实现的分布式锁**,并分别对比说明各自特点。 - - - -## Redis单实例分布式锁 - -### 实现一: SETNX实现的分布式锁 - -setnx用法参考redis[官方文档](https://redis.io/commands/setnx) - -#### 语法 - -`SETNX key value` - -将`key`设置值为`value`,如果`key`不存在,这种情况下等同SET命令。 当`key`存在时,什么也不做。`SETNX`是”**SET** if **N**ot e**X**ists”的简写。 - -返回值: - -- 1 设置key成功 -- 0 设置key失败 - -#### 加锁步骤 - -1. ```SETNX lock.foo ``` - - 如果客户端获得锁,`SETNX`返回`1`,加锁成功。 - - 如果`SETNX`返回`0`,那么该键已经被其他的客户端锁定。 - -2. 接上一步,`SETNX`返回`0`加锁失败,此时,调用`GET lock.foo`获取时间戳检查该锁是否已经过期: - - - 如果没有过期,则休眠一会重试。 - - - 如果已经过期,则可以获取该锁。具体的:调用`GETSET lock.foo `基于当前时间设置新的过期时间。 - - **注意**: 这里设置的时候因为在`SETNX`与`GETSET`之间有个窗口期,在这期间锁可能已被其他客户端抢去,所以这里需要判断`GETSET`的返回值,他的返回值是SET之前旧的时间戳: - - - 若旧的时间戳已过期,则表示加锁成功。 - - 若旧的时间戳还未过期(说明被其他客户端抢去并设置了时间戳),代表加锁失败,需要等待重试。 - -#### 解锁步骤 - -解锁相对简单,只需`GET lock.foo`时间戳,判断是否过期,过期就调用删除`DEL lock.foo` - - - -### 实现二:SET实现的分布式锁 - -set用法参考[官方文档](https://redis.io/commands/set) - -#### 语法 - -`SET key value [EX seconds|PX milliseconds] [NX|XX]` - -将键`key`设定为指定的“字符串”值。如果 `key` 已经保存了一个值,那么这个操作会直接覆盖原来的值,并且忽略原始类型。当`set`命令执行成功之后,之前设置的过期时间都将失效。 - -从2.6.12版本开始,redis为`SET`命令增加了一系列选项: - -- `EX` *seconds* – Set the specified expire time, in seconds. -- `PX` *milliseconds* – Set the specified expire time, in milliseconds. -- `NX` – Only set the key if it does not already exist. -- `XX` – Only set the key if it already exist. -- `EX` *seconds* – 设置键key的过期时间,单位时秒 -- `PX` *milliseconds* – 设置键key的过期时间,单位是毫秒 -- `NX` – 只有键key不存在的时候才会设置key的值 -- `XX` – 只有键key存在的时候才会设置key的值 - -版本\>= 6.0 - -- `KEEPTTL` -- 保持 key 之前的有效时间TTL - -#### 加锁步骤 - -一条命令即可加锁: `SET resource_name my_random_value NX PX 30000` - -The command will set the key only if it does not already exist (NX option), with an expire of 30000 milliseconds (PX option). The key is set to a value “my*random*value”. This value must be unique across all clients and all lock requests. - -这个命令只有当`key` 对应的键不存在resource_name时(NX选项的作用)才生效,同时设置30000毫秒的超时,成功设置其值为my_random_value,这是个在所有redis客户端加锁请求中全局唯一的随机值。 - -#### 解锁步骤 - -解锁时需要确保my_random_value和加锁的时候一致。下面的Lua脚本可以完成 - -```lau -if redis.call("get",KEYS[1]) == ARGV[1] then - return redis.call("del",KEYS[1]) -else - return 0 -end -``` - -这段Lua脚本在执行的时候要把前面的`my_random_value`作为`ARGV[1]`的值传进去,把`resource_name`作为`KEYS[1]`的值传进去。释放锁其实包含三步操作:’GET’、判断和’DEL’,用Lua脚本来实现能保证这三步的原子性。 - - - -## Redis集群分布式锁 - - - -### 实现三:Redlock - -前面两种分布式锁的实现都是针对单redis master实例,既不是有互为备份的slave节点也不是多master集群,如果是redis集群,每个redis master节点都是独立存储,这种场景用前面两种加锁策略有锁的安全性问题。 - -比如下面这种场景: - -> 1. 客户端1从Master获取了锁。 -> 2. Master宕机了,存储锁的key还没有来得及同步到Slave上。 -> 3. Slave升级为Master。 -> 4. 客户端2从新的Master获取到了对应同一个资源的锁。 -> -> 于是,客户端1和客户端2同时持有了同一个资源的锁。锁的安全性被打破。 - -针对这种多redis服务实例的场景,redis作者antirez设计了**Redlock** (Distributed locks with Redis)算法,就是我们接下来介绍的。 - -### 加锁步骤 - -**集群加锁的总体思想是尝试锁住所有节点,当有一半以上节点被锁住就代表加锁成功。集群部署你的数据可能保存在任何一个redis服务节点上,一旦加锁必须确保集群内任意节点被锁住,否则也就失去了加锁的意义。** - -具体的: - -1. 获取当前时间(毫秒数)。 -2. 按顺序依次向N个Redis节点执行**获取锁**的操作。这个获取操作跟前面基于单Redis节点的**获取锁**的过程相同,包含随机字符串`my_random_value`,也包含过期时间(比如`PX 30000`,即锁的有效时间)。为了保证在某个Redis节点不可用的时候算法能够继续运行,这个**获取锁**的操作还有一个超时时间(time out),它要远小于锁的有效时间(几十毫秒量级)。客户端在向某个Redis节点获取锁失败以后,应该立即尝试下一个Redis节点。这里的失败,应该包含任何类型的失败,比如该Redis节点不可用,或者该Redis节点上的锁已经被其它客户端持有(注:Redlock原文中这里只提到了Redis节点不可用的情况,但也应该包含其它的失败情况)。 -3. 计算整个获取锁的过程总共消耗了多长时间,计算方法是用当前时间减去第1步记录的时间。如果客户端从大多数Redis节点(>= N/2+1)成功获取到了锁,并且获取锁总共消耗的时间没有超过锁的有效时间(lock validity time),那么这时客户端才认为最终获取锁成功;否则,认为最终获取锁失败。 -4. 如果最终获取锁成功了,那么这个锁的有效时间应该重新计算,它等于最初的锁的有效时间减去第3步计算出来的获取锁消耗的时间。 -5. 如果最终获取锁失败了(可能由于获取到锁的Redis节点个数少于N/2+1,或者整个获取锁的过程消耗的时间超过了锁的最初有效时间),那么客户端应该立即向所有Redis节点发起**释放锁**的操作(即前面介绍的Redis Lua脚本)。 - -### 解锁步骤 - -客户端向所有Redis节点发起释放锁的操作,不管这些节点当时在获取锁的时候成功与否。 - -### 算法实现 - -上面描述的算法已经有现成的实现,各种语言版本。 - -- [Redlock-rb](https://github.com/antirez/redlock-rb) (Ruby implementation). There is also a [fork of Redlock-rb](https://github.com/leandromoreira/redlock-rb) that adds a gem for easy distribution and perhaps more. -- [Redlock-py](https://github.com/SPSCommerce/redlock-py) (Python implementation). -- [Aioredlock](https://github.com/joanvila/aioredlock) (Asyncio Python implementation). -- [Redlock-php](https://github.com/ronnylt/redlock-php) (PHP implementation). -- [PHPRedisMutex](https://github.com/malkusch/lock#phpredismutex) (further PHP implementation) -- [cheprasov/php-redis-lock](https://github.com/cheprasov/php-redis-lock) (PHP library for locks) -- [Redsync](https://github.com/go-redsync/redsync) (Go implementation). -- [Redisson](https://github.com/mrniko/redisson) (Java implementation). -- [Redis::DistLock](https://github.com/sbertrang/redis-distlock) (Perl implementation). -- [Redlock-cpp](https://github.com/jacket-code/redlock-cpp) (C++ implementation). -- [Redlock-cs](https://github.com/kidfashion/redlock-cs) (C#/.NET implementation). -- [RedLock.net](https://github.com/samcook/RedLock.net) (C#/.NET implementation). Includes async and lock extension support. -- [ScarletLock](https://github.com/psibernetic/scarletlock) (C# .NET implementation with configurable datastore) -- [Redlock4Net](https://github.com/LiZhenNet/Redlock4Net) (C# .NET implementation) -- [node-redlock](https://github.com/mike-marcacci/node-redlock) (NodeJS implementation). Includes support for lock extension. - -### 比如我用的C++实现 - -[源码在这](https://github.com/jacket-code/redlock-cpp) - -#### 创建分布式锁管理类CRedLock - -```c++ -CRedLock * dlm = new CRedLock(); -dlm->AddServerUrl("127.0.0.1", 5005); -dlm->AddServerUrl("127.0.0.1", 5006); -dlm->AddServerUrl("127.0.0.1", 5007); -``` - -#### 加锁并设置超时时间 - -```c++ -CLock my_lock; -bool flag = dlm->Lock("my_resource_name", 1000, my_lock); -``` - -#### 加锁并保持直到释放 - -```c++ -CLock my_lock; -bool flag = dlm->ContinueLock("my_resource_name", 1000, my_lock); -``` - -`my_resource_name`是加锁标识;`1000`是锁的有效期,单位毫秒。 - -#### 加锁失败返回false, 加锁成功返回`Lock`结构如下 - -```c++ -class CLock { -public: - int m_validityTime; => 9897.3020019531 // 当前锁可以存活的时间, 毫秒 - sds m_resource; => my_resource_name // 要锁住的资源名称 - sds m_val; => 53771bfa1e775 // 锁住资源的进程随机名字 -}; -``` - -#### 解锁 - -```c++ -dlm->Unlock(my_lock); -``` - - - -## 总结 - -综上所述,三种实现方式。 - -- 单redis实例场景,分布式锁实现一和实现二都可以,实现二更简洁推荐用实现二,用实现三也可以,但是实现三有点复杂略显笨重。 -- 多redis实例场景推荐用实现三最安全,不过实现三也不是完美无瑕,也有针对这种算法缺陷的讨论(节点宕机同步时延、时间同步假设),大家还需要根据自身业务场景灵活选择或定制自己的分布式锁。 - - - -## 参考 - -[Distributed locks with Redis](https://redis.io/topics/distlock) - -[How to do distributed locking](https://martin.kleppmann.com/2016/02/08/how-to-do-distributed-locking.html) - -[基于Redis的分布式锁到底安全吗](http://zhangtielei.com/posts/blog-redlock-reasoning.html) \ No newline at end of file diff --git a/_posts/2020-1-29-red_packet_thinking_lock.md b/_posts/2020-1-29-red_packet_thinking_lock.md deleted file mode 100644 index 8ea4d8187d..0000000000 --- a/_posts/2020-1-29-red_packet_thinking_lock.md +++ /dev/null @@ -1,92 +0,0 @@ ---- -layout: post -title: "后台服务高并发编程-抢红包" -date: 2020-1-27 -tags: [后台开发] -comments: true -author: lemonchann ---- - -今年春节响应国家号召在家宅着抵抗疫情,拜年也改用微信红包,春节发了很多也抢了很多微信红包,也算支持了公司业务,想到WXG的小伙伴丰厚的年终奖我柠檬了,微信支付融入生活,抢红包已经是非常平常的事情。 - -抢红包这一简单的动作,每一次都是对红包服务后台的一次请求,在春节期间海量的服务请求下,其实是一个很典型的高并发编程模型。后台开发程序员都有一个共识:**实现一个功能很容易,难的是大量请求下提高服务性能**。 - -在程序员眼里,大家抢的不是红包,是红包后台服务的**锁** !这里的**锁**不是我们日常生活中的锁,后台服务编程中锁的概念: - -> 实现多个进程或线程互斥的访问共享资源的一种机制 - -### 今天和大家聊聊后台服务编程中的锁。 - -## 业务模型 - -为便于说明,我们简化模型,约定抢红包服务是多线程服务,抢红包操作包含以下3个步骤: - -1. 查询数据库内红包余额 -2. 扣除抢到的红包金额 -3. 更新红包余额到数据库 - -假设发了100块钱红包,1000个人1秒内同时来抢(高并发),如果不加锁是这样的情况: - -- 第一个人查余额得到100元,他在此基础上扣除抢到的假设2元,准备步骤3更新到数据库。 -- 在第一个人更新进去之前,此时剩下的人查到的余额也是100,他们各自扣除抢到的金额,准备按步骤3更新。 -- 导致最后的红包余额只记录了最后一次更新的数据。 -- 很明显,这就可能出现1000个人都抢到红包,但是红包余额还没分完的情况,这就乱了。 - -怎么解决这个问题呢? 就用到我们上面说的**加锁**来解决。 - - - -## 有哪些锁 - -实现锁的方式有很多,这里列举几种常见的分类 - -### 悲观锁 - -> 顾名思义就是悲观的做最坏打算的锁机制,占有锁期间独占资源。 - -悲观锁把抢红包这三个步骤打包成一个整体做成互斥操作,**“在我抢了没更新数据之前你别来查余额,查到也不准确”**。也可以类比数据库的**事务**来理解。 - -> **事务必须具备以下四个属性,简称ACID 属性:** -> `原子性(Atomicity)`:事务是一个完整的操作。事务的各步操作是不可分的(原子的);要么都执 行,要么都不执行 -> `一致性(Consistency)`:当事务完成时,数据必须处于一致状态 -> `隔离性(Isolation)`:对数据进行修改的所有并发事务是彼此隔离的,这表明事务必须是独立的,它不应以任何方式依赖于或影响其他事务 -> `永久性(Durability)`:事务完成后,它对数据库的修改被永久保持,事务日志能够保持事务的永久性 - -它悲观的认为你每次去抢红包必然有其他人也同时在抢,所以你这条线程在抢的时候要独占资源,其他线程需要阻塞挂起等待你抢完才能进来抢,挂起的线程就干不了其他事了。 - -> 鲁迅先生说过,浪费CPU资源就是浪费生命! - -而一旦你抢完红包释放了锁,其他在等待中的线程又要抢占资源、抢到了还要恢复线程上下文。 - -CPU不断的切换线程上下文非常浪费服务器资源,严重的会导致不能及时处理后续抢红包请求,需要想办法提高效率,于是有了**乐观锁** - -### 乐观锁 - -> 乐观锁是对悲观锁的改进,乐观的认为加锁的时候没有竞争,乐观锁不阻塞线程。 - -一种实现乐观锁的方法是**数据库内红包余额增加版本号**,初始版本号是0,每次抢完红包版本号加1后再去更新余额,**只有更新的版本号大于数据库内的版本号才认为是合法的,予以更新;否则不予更新,线程不阻塞可以稍后重试,**避免频繁切换线程上下文。 - -乐观锁在抢红包的步骤1、2不做加锁判断,在步骤3的时候才做加锁判断版本号。 - -- 第一个人抢到版本号是0的红包,第二个人也抢到版本号是0的红包 -- 第一个人更新红包余额并设置版本号为1 -- 第二个人更新红包余额设置版本号为1的时候发现余额版本号已经为1,更新失败 -- 第二个人更新失败后,**线程不阻塞,继续处理其他抢红包抢请求**,按**一定策略重试**(超时重试、有限次数重试)第二个人的更新操作 -- 其他请求以此类推 - -可以看到,乐观锁在加锁失败的时候不挂起线程等待,避免了线程上下文频繁的切换,提高红包服务处理性能。 - -### 分布式锁 - -上面两种锁的形式都是基于对数据库的更新来做的,在大请求高并发的时候,频繁的存取数据库,尤其是乐观锁重试会对数据库产生很大的冲击,在实际生产环境要尽量减少对数据库的访问。 - -Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。也可以用redis实现**分布式锁**,与数据库交互两次:第一次获取红包余额,第二次抢完更新红包状态。抢红包和中间过程更新操作都在内存中进行,这可比数据库操作快了几个数量级,显著改善服务并发性能。 - -redis分布式锁: - -> 利用Redis的SET操作在内存中保存key-value键值对,加锁就是获取这个键值对的值,解锁就是删除这个键值对。 - -分布式锁也不阻塞线程,关于这种分布式锁的实现不在这里展开说明,参考我另一篇公众号文章,[redis分布式锁3种实现方式分析](1) - -#### 更多原创技术干货分享在我的公众号:柠檬橙学编程 欢迎关注。 - diff --git a/_posts/2020-1-4-learn_cpp.md b/_posts/2020-1-4-learn_cpp.md deleted file mode 100644 index 17daddc8ce..0000000000 --- a/_posts/2020-1-4-learn_cpp.md +++ /dev/null @@ -1,262 +0,0 @@ ---- -layout: post -title: "Linux后台开发C++学习路线技能加点" -date: 2020-1-1 -tags: [c++] -comments: true -author: lemonchann ---- - -最近在知乎经常被邀请回答类似如何学习C++和C++后台开发应该具体储备哪些基础技能的问题。 - -本身我从事的的C++后台开发的工作,目前在腾讯负责社交产品相关后台开发,所以写这篇文章,分享自己的C++后台开发学习路径和点过的技能树,希望能给想从事后台开发的同学一点参考,若能帮你少走些弯路就更好。 - -工欲善其事必先利其器,好的书籍能让学习事半功倍,所以每个技能点之后我会推荐一些书,都是我读过且口碑不错的书,供参考。 - -**分享的是我的学习路径,如果你也能顺着这个学习路径认真学一遍,我想在后台开发技术上你已经有一个很不错的技术积累,加上项目练习通过大部分大厂面试是没有问题的。后续还会继续分享关于C++编程和后台开发技术,感兴趣的同学可以关注我和专栏。** - -## 计算机基础综合 - -考过CS或者软件工程研究生的同学可能对这个标题不陌生,是的,我说的就是专业课代号408的**计算机基础综合**。这门专业课包含:数据结构、计算机组成原理、计算机网路、操作系统。 - -为什么提起这门课程呢,因为基础知识太重要了!这是科班区别于培训班的最大不同,理论知识不一定马上能用于项目上,但当与人讨论起某个技术问题时你能够知道它深层次的原因,看问题的角度会更加全面和系统。 - -打个比方,你可能听过堆栈的名词,但知道它的具体结构和不同吗?学完数据结构就明白了;你知道计算机会算加减乘除,但具体是如何实现的呢?组成原理会告诉你;知道程序执行的时候怎么区分指令地址和数据地址的吗?操作系统会告诉你答案。 - -所以如果你大学不是计算机相关专业,或者是本专业但是没有完全吃透基础的话,强烈建议你务必抽时间好好学习这几门课程。 - -#### 推荐书: - -**计算机基础综合**推荐看大学的计算机专业教材就可以:数据结构、计算机组成原理、计算机网路、操作系统。 - -- 数据结构  - -> 1.教材:[《数据结构》](https://www.baidu.com/s?wd=《数据结构》&tn=SE_PcZhidaonwhc_ngpagmjz&rsv_dl=gh_pc_zhidao)[严蔚敏](https://www.baidu.com/s?wd=严蔚敏&tn=SE_PcZhidaonwhc_ngpagmjz&rsv_dl=gh_pc_zhidao) 清华大学出版社  -> -> 2.辅导书:《算法与数据结构考研试题精析(第二版)》[机械工业出版社](https://www.baidu.com/s?wd=机械工业出版社&tn=SE_PcZhidaonwhc_ngpagmjz&rsv_dl=gh_pc_zhidao)  - -- 计算机组成原理   - -> 教材:[《计算机组成原理》](https://www.baidu.com/s?wd=《计算机组成原理》&tn=SE_PcZhidaonwhc_ngpagmjz&rsv_dl=gh_pc_zhidao)[唐朔飞](https://www.baidu.com/s?wd=唐朔飞&tn=SE_PcZhidaonwhc_ngpagmjz&rsv_dl=gh_pc_zhidao) [高等教育出版社](https://www.baidu.com/s?wd=高等教育出版社&tn=SE_PcZhidaonwhc_ngpagmjz&rsv_dl=gh_pc_zhidao)  -> -> 辅导书: -> -> [《计算机组成原理考研指导》](https://www.baidu.com/s?wd=《计算机组成原理考研指导》&tn=SE_PcZhidaonwhc_ngpagmjz&rsv_dl=gh_pc_zhidao)徐爱萍 清华大学出版社  -> -> 《计算机组成原理--学习指导与习题解答》[唐朔飞](https://www.baidu.com/s?wd=唐朔飞&tn=SE_PcZhidaonwhc_ngpagmjz&rsv_dl=gh_pc_zhidao) [高等教育出版社](https://www.baidu.com/s?wd=高等教育出版社&tn=SE_PcZhidaonwhc_ngpagmjz&rsv_dl=gh_pc_zhidao)   - -- 操作系统  - -> 教材:[《计算机操作系统(修订版)》](https://www.baidu.com/s?wd=《计算机操作系统(修订版)》&tn=SE_PcZhidaonwhc_ngpagmjz&rsv_dl=gh_pc_zhidao)汤子瀛 [西安电子科技大学出版社](https://www.baidu.com/s?wd=西安电子科技大学出版社&tn=SE_PcZhidaonwhc_ngpagmjz&rsv_dl=gh_pc_zhidao)   -> -> 辅导书:《操作系统考研辅导教程(计算机专业研究生入学考试全真题解) 》电子科技大学出版社  -> -> 《操作系统考研指导》清华大学出版社  - -- 计算机网络  - -> 教材:《计算机网络(第五版)》谢希仁 电子工业出版社   -> -> 辅导书:《计算机网络知识要点与习题解析》哈尔滨工程大学出版社  - -#### 视频教材 - -看上面的课本教程估计非常枯燥,下面是我觉得讲的不错的国内大学公开课我听过一部分,讲的都是计算机专业的基础内容,如果你没有系统的学过或者学的不好,都是非常建议刷一遍视频课的。 - -[武汉大学-数据结构 MOOC网络课程 ](https://www.icourse163.org/course/WHU-1001539003) - -[华中科技大学-计算机组成原理](https://www.icourse163.org/course/HUST-1003159001) - -[电子科技大学-计算机组成原理](https://www.icourse163.org/course/UESTC-1001543002) - -[华中科技大学-操作系统原理](https://www.icourse163.org/course/HUST-1003405007) - -[哈尔滨工业大学-计算机网络](https://www.icourse163.org/course/HIT-154005) - -**这一小节写的有点多,因为基础实在是太重要了!科班和非科班的差距不是谁学的编程语言多,也不是谁框架用的溜,本质区别是理论知识储备差别和用CS思维独立思考分析解决问题的能力。** - - - -## C++和C语法基础 - -**语法是一门语言的基础。**C++的基础语句和语法和C是很像的,最大的不同在class和异常处理机制,还有模板的应用,所以有C基础语法学起来是很快,没有C基础也没关系,啃完下面推荐的书也差不多,光说不练假把式,看完之后趁热把课后习题敲一遍并且自己编译通过才算看完。 - -#### 推荐书: - -[《C++ Primer 中文版(第 5 版)》](https://book.douban.com/subject/25708312/) 经典的入门书籍,不要拿大学教材XX强来对比,不是一个等级。 - - - -## 标准库STL学习 - -**STL提供了丰富的算法库支持和各种容器。**C++标准库提供了包括最基础的标准输入输出`iostrem`、各种容器`vector、set、string` ,熟练掌握标准库,不用重复造轮子(练手学习目的的造轮子除外)写出更C++的代码。 - -#### 推荐书: - -[《C++ Primer 中文版(第 5 版)》](https://book.douban.com/subject/25708312/) - -[《STL源码剖析》]( https://book.douban.com/subject/1110934/ ) - - - -## C++进阶 - -**学完了上面的C++基础只是会用,要用好还需要不断学习进阶。**站在巨人的肩膀上写出更健壮高效的代码,你没踩过的坑前人已经踩过一遍,关于一些语言细节和更好的编码习惯,有很多优秀的书籍可以学习。 - -#### 推荐书 - -[《Effective C++》](https://book.douban.com/subject/1842426/) 改善程序与设计的55个具体做法,非常值得一看,老手和新手的差别由此产生! - -[《More Effective C++(中文版》](https://book.douban.com/subject/5908727/) - -> 同一个作者,继Effective C++之后,Scott Meyers于1996推出这本《More Effective C++(35个改善编程与设计的有效方法)》“续集”。条款变得比较少,页数倒是多了一些,原因是这次选材比“一集”更高阶,尤其是第5章。Meyers将此章命名为技术。 - -[《Inside the C++ Object Model》](https://book.douban.com/subject/1484262/) 这本书还有中文版本,翻译质量也很高[《深度探索C++对象模型》](https://book.douban.com/subject/1091086/) - - - -## C++11新标准 - -**新标准提供了解决现有问题更优雅、更C++的实现**。现行的大部分C++软件还是C++98的标准,C++98是C++的第一个标准,经历这么多年的发展,从前你需要从Boost库(一个在C++98年代的准C++标准)获得的对C++的扩充支持的大部分功能已经纳入了C++11和甚至C++2X更新的标准当中,与时俱进拿起更先进的生产工具,工具就是效率。 - -#### 推荐书: - -[《深入理解C++11》](https://book.douban.com/subject/24738301/) - - - -## Linux系统基础和shell script - -**如今几乎所有的互联网服务都是跑在linux系统上面的。**对Linux系统一无所知那更加谈不上后台开发了,所以要先学习linux系统操作,不如文件管理,系统命令,文件系统,权限管理,系统服务等。 - -至于shell script 就类似win的批处理脚本,相信我,你在linux下干活早晚会需要它,所以趁早系统学起来。 - -#### 推荐书: - -[《鸟哥的Linux私房菜基础学习篇》](https://book.douban.com/subject/4889838/) 这个系列还有一个服务器架设篇,前期学习个人感觉没必要看 - -[《Linux Shell脚本攻略》](https://book.douban.com/subject/6889456/) - -[《Shell脚本学习指南》](https://read.douban.com/ebook/124173616/?dcs=subject-rec&dcm=douban&dct=6889456) - - - -## Linux环境高级编程 - -**普通用户只需懂系统操作,软件开发人员还要懂编程接口。**上一阶段你已经能够完成熟练操作Linux系统,知道一些常规的系统命令和服务,并且能够利用shell script写一些小工具提高日常开发效率。 - -我们的目标是星辰大海,作为软件工程师,还需要更加深入的掌握linux系统编程技巧,**学习系统编程接口、系统调用API、内存管理、进程间通信(IPC)**,这是本阶段的学习目的。 - -#### 推荐书: - -[《UNIX环境高级编程》](https://book.douban.com/subject/1788421/) 这本是linux编程必看的APUE,强烈推荐通读一遍,后续值得反复翻阅。 - -[《Linux/UNIX系统编程手册》](https://book.douban.com/subject/25809330/) 这本书和APUE有点重复,我看完APUE这本就跳着看了,平常可以看目录查阅。 - - - -## TCP/IP协议 - -目前网络通信中应用最广泛的协议就是IP TCP协议,后面Unix提供的TCP套接字也是基于协议实现,所以很有必要系统的学习 TCP/IP 协议。 - -#### 推荐书: - -大学的计算机网络教程 - -[《TCP/IP详解 卷1:协议》](https://book.douban.com/subject/1088054/) - -[《TCP/IP详解 卷2:实现》](https://book.douban.com/subject/1087767/) - -[《TCP/IP详解 卷3:TCP事务协议、HTTP、NNTP和UNIX域协议》](https://book.douban.com/subject/1058634/) - -这几本书很厚,可以先看卷1、卷3 - - - -## Linux网络编程套接字 - -在同一台机器上进程间的通信(IPC)有多种方式,可以是通过**消息队列、FIFO、共享内存**等方式。网络编程套接字是指:分布在不同机器上的程序通过系统提供的网络通信接口,跨越网络将不同机器上的进程连接起来,实现跨机器的网络通信。一般有**UDP套接字、TCP套接字、Unix Domain,当然,如果你是通信从业者对SCTP套接字肯定也不会陌生。** - -#### 推荐书: - -[《UNIX网络编程 卷1:套接字联网API(第3版)》](https://book.douban.com/subject/4859464/) - -[《UNIX网络编程 卷2:进程间通信(第2版)》](https://book.douban.com/subject/26434599/) - - - -## 数据库和存储 - -**程序运行数据都在易失性的内存中,需要持久化存储时就需要数据库。**一个后台服务系统一般来说都需要考虑数据落地和持久性存储的问题,这时就会涉及到数据库选型和应用,数据库分为关系型数据库和非关系型数据库。 - -**关系型数据库:**指采用了关系模型来组织数据的数据库,代表是MySql。 -关系模型指的就是二维表格模型,而一个关系型数据库就是由二维表及其之间的联系所组成的一个数据组织。 - -**非关系型数据库:**以键值对存储,且结构不固定,每一个元组可以有不一样的字段,每个元组可以根据需要增加一些自己的键值对,不局限于固定的结构,可以减少一些时间和空间的开销。代表有redis、memcached,腾讯内部组件ckv也是非关系型数据库。 - -#### 推荐书: - -[《SQL必知必会》](https://book.douban.com/subject/24250054/) - -[《高性能MySQL》](https://book.douban.com/subject/23008813/) - -[redis官方文档](https://redis.io/documentation) [redis中文网](http://redis.cn/) - -> 关于redis还有很多应用,比如基于redis的分布式锁的应用,高并发抢红包模型等,这个后面可以写一篇关于分布式锁的原理和应用文章。 - - - -## 算法基础 - -**计算机算法就是利用编程语言编写出计算机能理解的解决问题的方法。** - -好的算法能更简洁高效的解决问题,如今不论是校招还是社招,大厂笔试都会考察算法,即使不是为了笔试作为软件从业者也应该经常练习算法,保持手感。学习算法是学习解决问题的通用性方法有助于提高逻辑思维能力。 - -#### 学习方法 - -**就我个人经验来说,不推荐直接啃书的方式学习算法,建议看书的同时结合刷在线编程算法题的方式。** - -具体的:边看数据结构或算法导论,同时在[牛客](https://www.nowcoder.com/activity/oj)或者 [leetcode](https://leetcode-cn.com/ )上刷题,因为看书太枯燥很容易失去耐心,在线刷题的好处是你可以每天定目标,享受每个题目通过的快感,有正向反馈更容易坚持下来。 - - - -## 架构能力 - -**架构能力是利用已有知识来设计整个后台服务系统的能力。**不仅要求掌握技能的维度还要深度,需要能根据不同需求和系统约束,制定不同的设计方案。 - -这时候考虑的东西会更多,包括服务模型的设计:是多进程还是多线程甚至协程微线程,分布式还是集中式; - -存储的选型:考虑数据库选型用哪个?需要根据存储的数据特征和应用场景来区分,如果是社交应用的数据用非关系型数据库来存储可能更好,如果是电商订单类型的数据,那么用关系型数据库来存储可能更好; - -当然,还有后台系统的其他方方面面需要考虑,不一一举例了。 - -## 更多的练习 - -**说了这么多,最最重要的还是练习练习练习。**理论知识储备是必要条件,移动互联网时代大家接触到的碎片化信息太杂太乱,我个人经验,高浓度的知识精华还是需要在大师的书本中汲取,所以看书是最正确和快速的学习路径,没有捷径可走。 - -不过光看书也是不行,编程能力和技术是也是一门现代手艺活,还需要日常不断的打磨手艺,正如**一万小时定律**: - -> 人们眼中的天才之所以卓越非凡,并非天资超人一等,而是付出了持续不断的努力。1万小时的锤炼是任何人从平凡变成世界级大师的必要条件。要成为某个领域的专家,需要10000小时,按比例计算就是:如果每天工作八个小时,一周工作五天,那么成为一个领域的专家至少需要五年。这就是一万小时定律。 - -怎么打磨提高编程技术能力呢?找项目,**找感兴趣的**东西用代码去实现它,兴趣是最好的老师,这点在编程和技术学习上也完全适用。 - -人们总倾向于去做快速获得的愉悦感的事情,比如打一盘游戏30分钟就能获得快感。相反,技术碎片的提高是一个长期的过程,三分钟热度肯定是难以成功的。 - -所以要用技术做自己感兴趣的东西和带趣味性的编程,比如写个爬虫小程序抓取网站数据或者写个小游戏,再或者自己造轮子给自己用,并乐此不疲的优化轮子。这样每走一步都能获得一点成就感,激励自己继续走下去,慢慢的一定会有质的飞跃。 - -## 一个网站 - -这个网站一定要告诉大家,网站就是个C++百科全书,类似Linux的man手册,平常开发查忘记了函数名或者容器用法直接搜索非常方便。 - -网址:C++参考: [cppreference](https://en.cppreference.com/w/cpp) - - - -## 待续 - -一口气写下来肯定还不够完善,文章会保持更新和修改,想到了再补充吧。感兴趣可以关注我的微信公众号 **柠檬橙学编程** 更多干货和有趣的技术分享。 - -**我整理了文中提到和推荐的电子书与视频教材**,都是好几年学习过程中收集的,关注微信公众号 **柠檬橙学编程** 回复 **1024** 免费分享给大家。 - -![资料截图.png](https://i.loli.net/2020/01/16/Sg9MvLO2bTutU46.png) - diff --git a/_posts/todolist.txt b/_posts/todolist.txt deleted file mode 100644 index ff376426d8..0000000000 --- a/_posts/todolist.txt +++ /dev/null @@ -1,2 +0,0 @@ -进程 线程 协程的对比python vs go -github c++项目推荐 diff --git a/about.md b/about.md index 18f1ad776d..b235ddd228 100644 --- a/about.md +++ b/about.md @@ -1,20 +1,3 @@ ---- -layout: page -title: About -permalink: /about/ ---- - -lemonchann的个人博客。 - -### 技能 - -Linux后端分布式高性能服务开发,差一点精通C++,Python小玩具,Go见习。 - -### 经历 - -软件工程师(Software Engineer),电子信息工程学士学位( Electronic and Information Engineering ),通信设备服务端程序开发和互联网服务后台开发,现就职腾讯(Tencent)公司从事社交产品服务器后台开发工作。 - -### 版权声明 - -博客文章存档于**[此处](https://github.com/lemonchann/lemonchann.github.io/tree/master/_posts)** ,所有文章若无特别声明均使用[CC BY-SA 4.0 International License(知识共享署名-相同方式共享 4.0 国际许可协议)](http://creativecommons.org/licenses/by-sa/4.0/)授权。 +# About +## None diff --git "a/images/2018-10-12-Play_with_vscode_PlantUML_preview/\346\227\266\345\272\217\345\233\276.png" "b/images/2018-10-12-Play_with_vscode_PlantUML_preview/\346\227\266\345\272\217\345\233\276.png" deleted file mode 100644 index b5f1b97638..0000000000 Binary files "a/images/2018-10-12-Play_with_vscode_PlantUML_preview/\346\227\266\345\272\217\345\233\276.png" and /dev/null differ diff --git "a/images/2018-10-12-Play_with_vscode_PlantUML_preview/\346\264\273\345\212\250\345\233\276.png" "b/images/2018-10-12-Play_with_vscode_PlantUML_preview/\346\264\273\345\212\250\345\233\276.png" deleted file mode 100644 index ad35e266a8..0000000000 Binary files "a/images/2018-10-12-Play_with_vscode_PlantUML_preview/\346\264\273\345\212\250\345\233\276.png" and /dev/null differ diff --git "a/images/2018-10-12-Play_with_vscode_PlantUML_preview/\347\212\266\346\200\201\345\233\276.png" "b/images/2018-10-12-Play_with_vscode_PlantUML_preview/\347\212\266\346\200\201\345\233\276.png" deleted file mode 100644 index 4e6f337f80..0000000000 Binary files "a/images/2018-10-12-Play_with_vscode_PlantUML_preview/\347\212\266\346\200\201\345\233\276.png" and /dev/null differ diff --git "a/images/2018-10-12-Play_with_vscode_PlantUML_preview/\347\224\250\344\276\213\345\233\276.png" "b/images/2018-10-12-Play_with_vscode_PlantUML_preview/\347\224\250\344\276\213\345\233\276.png" deleted file mode 100644 index f92fac7ead..0000000000 Binary files "a/images/2018-10-12-Play_with_vscode_PlantUML_preview/\347\224\250\344\276\213\345\233\276.png" and /dev/null differ diff --git "a/images/2018-10-12-Play_with_vscode_PlantUML_preview/\347\261\273\345\233\276.png" "b/images/2018-10-12-Play_with_vscode_PlantUML_preview/\347\261\273\345\233\276.png" deleted file mode 100644 index fee087367f..0000000000 Binary files "a/images/2018-10-12-Play_with_vscode_PlantUML_preview/\347\261\273\345\233\276.png" and /dev/null differ diff --git "a/images/2018-6-21-Markdown_brief_syntactic/Markdown\350\257\255\346\263\225\347\256\200\346\230\216\347\254\224\350\256\2601.png" "b/images/2018-6-21-Markdown_brief_syntactic/Markdown\350\257\255\346\263\225\347\256\200\346\230\216\347\254\224\350\256\2601.png" deleted file mode 100644 index 6130c18bd4..0000000000 Binary files "a/images/2018-6-21-Markdown_brief_syntactic/Markdown\350\257\255\346\263\225\347\256\200\346\230\216\347\254\224\350\256\2601.png" and /dev/null differ diff --git "a/images/2018-6-21-Markdown_brief_syntactic/Markdown\350\257\255\346\263\225\347\256\200\346\230\216\347\254\224\350\256\2602.png" "b/images/2018-6-21-Markdown_brief_syntactic/Markdown\350\257\255\346\263\225\347\256\200\346\230\216\347\254\224\350\256\2602.png" deleted file mode 100644 index 2d9f2bd05d..0000000000 Binary files "a/images/2018-6-21-Markdown_brief_syntactic/Markdown\350\257\255\346\263\225\347\256\200\346\230\216\347\254\224\350\256\2602.png" and /dev/null differ diff --git a/images/2019-11-18-new_gitbook_tutors/gitbook_pdf.png b/images/2019-11-18-new_gitbook_tutors/gitbook_pdf.png deleted file mode 100644 index d58d52f05f..0000000000 Binary files a/images/2019-11-18-new_gitbook_tutors/gitbook_pdf.png and /dev/null differ diff --git a/images/2019-11-18-new_gitbook_tutors/gitbook_serve.png b/images/2019-11-18-new_gitbook_tutors/gitbook_serve.png deleted file mode 100644 index 24e0433084..0000000000 Binary files a/images/2019-11-18-new_gitbook_tutors/gitbook_serve.png and /dev/null differ diff --git "a/images/2019-11-18-new_gitbook_tutors/gitbook\347\251\272\351\227\264.png" "b/images/2019-11-18-new_gitbook_tutors/gitbook\347\251\272\351\227\264.png" deleted file mode 100644 index 6bc2b14fab..0000000000 Binary files "a/images/2019-11-18-new_gitbook_tutors/gitbook\347\251\272\351\227\264.png" and /dev/null differ diff --git "a/images/2019-11-18-new_gitbook_tutors/\345\205\263\350\201\224github.png" "b/images/2019-11-18-new_gitbook_tutors/\345\205\263\350\201\224github.png" deleted file mode 100644 index e231d248fb..0000000000 Binary files "a/images/2019-11-18-new_gitbook_tutors/\345\205\263\350\201\224github.png" and /dev/null differ diff --git "a/images/2019-11-18-new_gitbook_tutors/\347\216\257\345\242\203\345\217\230\351\207\217\350\256\276\347\275\2561.PNG" "b/images/2019-11-18-new_gitbook_tutors/\347\216\257\345\242\203\345\217\230\351\207\217\350\256\276\347\275\2561.PNG" deleted file mode 100644 index 7b9b695cc0..0000000000 Binary files "a/images/2019-11-18-new_gitbook_tutors/\347\216\257\345\242\203\345\217\230\351\207\217\350\256\276\347\275\2561.PNG" and /dev/null differ diff --git "a/images/2019-11-18-new_gitbook_tutors/\347\216\257\345\242\203\345\217\230\351\207\217\350\256\276\347\275\2562.PNG" "b/images/2019-11-18-new_gitbook_tutors/\347\216\257\345\242\203\345\217\230\351\207\217\350\256\276\347\275\2562.PNG" deleted file mode 100644 index c872c5b52e..0000000000 Binary files "a/images/2019-11-18-new_gitbook_tutors/\347\216\257\345\242\203\345\217\230\351\207\217\350\256\276\347\275\2562.PNG" and /dev/null differ diff --git "a/images/2019-12-27-cpp_reference/tcp\346\217\241\346\211\213\344\270\216\345\245\227\346\216\245\345\255\227\345\257\271\345\272\224.png" "b/images/2019-12-27-cpp_reference/tcp\346\217\241\346\211\213\344\270\216\345\245\227\346\216\245\345\255\227\345\257\271\345\272\224.png" deleted file mode 100644 index b26ad5aa96..0000000000 Binary files "a/images/2019-12-27-cpp_reference/tcp\346\217\241\346\211\213\344\270\216\345\245\227\346\216\245\345\255\227\345\257\271\345\272\224.png" and /dev/null differ diff --git "a/images/2019-12-27-cpp_reference/\345\215\225\344\270\200\347\273\247\346\211\277.png" "b/images/2019-12-27-cpp_reference/\345\215\225\344\270\200\347\273\247\346\211\277.png" deleted file mode 100644 index 89fd87ed5a..0000000000 Binary files "a/images/2019-12-27-cpp_reference/\345\215\225\344\270\200\347\273\247\346\211\277.png" and /dev/null differ diff --git "a/images/2019-12-27-cpp_reference/\345\215\225\344\270\200\347\273\247\346\211\2771.png" "b/images/2019-12-27-cpp_reference/\345\215\225\344\270\200\347\273\247\346\211\2771.png" deleted file mode 100644 index 33119449c7..0000000000 Binary files "a/images/2019-12-27-cpp_reference/\345\215\225\344\270\200\347\273\247\346\211\2771.png" and /dev/null differ diff --git "a/images/2019-12-27-cpp_reference/\345\244\232\351\207\215\347\273\247\346\211\277.png" "b/images/2019-12-27-cpp_reference/\345\244\232\351\207\215\347\273\247\346\211\277.png" deleted file mode 100644 index 2ace1a3050..0000000000 Binary files "a/images/2019-12-27-cpp_reference/\345\244\232\351\207\215\347\273\247\346\211\277.png" and /dev/null differ diff --git "a/images/2019-12-27-cpp_reference/\345\244\232\351\207\215\347\273\247\346\211\2771.png" "b/images/2019-12-27-cpp_reference/\345\244\232\351\207\215\347\273\247\346\211\2771.png" deleted file mode 100644 index dc8b68fc70..0000000000 Binary files "a/images/2019-12-27-cpp_reference/\345\244\232\351\207\215\347\273\247\346\211\2771.png" and /dev/null differ diff --git "a/images/2019-12-27-cpp_reference/\345\244\232\351\207\215\347\273\247\346\211\2772.png" "b/images/2019-12-27-cpp_reference/\345\244\232\351\207\215\347\273\247\346\211\2772.png" deleted file mode 100644 index 9fda71fc16..0000000000 Binary files "a/images/2019-12-27-cpp_reference/\345\244\232\351\207\215\347\273\247\346\211\2772.png" and /dev/null differ diff --git "a/images/2019-12-27-cpp_reference/\346\210\220\345\221\230\345\207\275\346\225\260\346\214\207\351\222\210.png" "b/images/2019-12-27-cpp_reference/\346\210\220\345\221\230\345\207\275\346\225\260\346\214\207\351\222\210.png" deleted file mode 100644 index bb8558ef96..0000000000 Binary files "a/images/2019-12-27-cpp_reference/\346\210\220\345\221\230\345\207\275\346\225\260\346\214\207\351\222\210.png" and /dev/null differ diff --git "a/images/2019-12-27-cpp_reference/\346\210\220\345\221\230\350\231\232\345\207\275\346\225\260\346\214\207\351\222\210.png" "b/images/2019-12-27-cpp_reference/\346\210\220\345\221\230\350\231\232\345\207\275\346\225\260\346\214\207\351\222\210.png" deleted file mode 100644 index aa843f7f8e..0000000000 Binary files "a/images/2019-12-27-cpp_reference/\346\210\220\345\221\230\350\231\232\345\207\275\346\225\260\346\214\207\351\222\210.png" and /dev/null differ diff --git "a/images/2019-12-27-cpp_reference/\346\224\276\347\275\256new\345\257\271\350\261\241.png" "b/images/2019-12-27-cpp_reference/\346\224\276\347\275\256new\345\257\271\350\261\241.png" deleted file mode 100644 index 09ee8e7b8b..0000000000 Binary files "a/images/2019-12-27-cpp_reference/\346\224\276\347\275\256new\345\257\271\350\261\241.png" and /dev/null differ diff --git "a/images/2020-1-29-red_packet_thinking_lock/\351\242\230\345\233\276.png" "b/images/2020-1-29-red_packet_thinking_lock/\351\242\230\345\233\276.png" deleted file mode 100644 index 5e8813af04..0000000000 Binary files "a/images/2020-1-29-red_packet_thinking_lock/\351\242\230\345\233\276.png" and /dev/null differ diff --git "a/images/2020-1-4-learn_cpp/\350\265\204\346\226\231\346\210\252\345\233\276.png" "b/images/2020-1-4-learn_cpp/\350\265\204\346\226\231\346\210\252\345\233\276.png" deleted file mode 100644 index fe23155b01..0000000000 Binary files "a/images/2020-1-4-learn_cpp/\350\265\204\346\226\231\346\210\252\345\233\276.png" and /dev/null differ diff --git "a/images/2020-2-21-sourcegraph/\345\212\240\350\275\275\346\211\251\345\261\225\347\250\213\345\272\217.png" "b/images/2020-2-21-sourcegraph/\345\212\240\350\275\275\346\211\251\345\261\225\347\250\213\345\272\217.png" deleted file mode 100644 index 2130182704..0000000000 Binary files "a/images/2020-2-21-sourcegraph/\345\212\240\350\275\275\346\211\251\345\261\225\347\250\213\345\272\217.png" and /dev/null differ diff --git "a/images/2020-2-21-sourcegraph/\345\220\257\345\212\250\346\217\222\344\273\266.png" "b/images/2020-2-21-sourcegraph/\345\220\257\345\212\250\346\217\222\344\273\266.png" deleted file mode 100644 index 3f46ead082..0000000000 Binary files "a/images/2020-2-21-sourcegraph/\345\220\257\345\212\250\346\217\222\344\273\266.png" and /dev/null differ diff --git "a/images/2020-2-21-sourcegraph/\345\267\245\347\250\213\346\226\207\344\273\266\346\265\217\350\247\210.png" "b/images/2020-2-21-sourcegraph/\345\267\245\347\250\213\346\226\207\344\273\266\346\265\217\350\247\210.png" deleted file mode 100644 index 6bff34e645..0000000000 Binary files "a/images/2020-2-21-sourcegraph/\345\267\245\347\250\213\346\226\207\344\273\266\346\265\217\350\247\210.png" and /dev/null differ diff --git "a/images/2020-2-21-sourcegraph/\345\272\224\347\224\250\345\225\206\345\272\227.png" "b/images/2020-2-21-sourcegraph/\345\272\224\347\224\250\345\225\206\345\272\227.png" deleted file mode 100644 index 5177cfdf1c..0000000000 Binary files "a/images/2020-2-21-sourcegraph/\345\272\224\347\224\250\345\225\206\345\272\227.png" and /dev/null differ diff --git "a/images/2020-2-21-sourcegraph/\346\217\222\344\273\266\344\270\255\345\277\203.png" "b/images/2020-2-21-sourcegraph/\346\217\222\344\273\266\344\270\255\345\277\203.png" deleted file mode 100644 index a01c8cbb0e..0000000000 Binary files "a/images/2020-2-21-sourcegraph/\346\217\222\344\273\266\344\270\255\345\277\203.png" and /dev/null differ diff --git "a/images/2020-2-21-sourcegraph/\346\237\245\346\211\276\345\256\232\344\271\211.png" "b/images/2020-2-21-sourcegraph/\346\237\245\346\211\276\345\256\232\344\271\211.png" deleted file mode 100644 index 4955d9b06d..0000000000 Binary files "a/images/2020-2-21-sourcegraph/\346\237\245\346\211\276\345\256\232\344\271\211.png" and /dev/null differ diff --git "a/images/2020-2-21-sourcegraph/\346\237\245\346\211\276\345\274\225\347\224\250.png" "b/images/2020-2-21-sourcegraph/\346\237\245\346\211\276\345\274\225\347\224\250.png" deleted file mode 100644 index f3ced1ae55..0000000000 Binary files "a/images/2020-2-21-sourcegraph/\346\237\245\346\211\276\345\274\225\347\224\250.png" and /dev/null differ diff --git a/images/2020_02_24/init b/images/2020_02_24/init new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/images/2020_02_24/init @@ -0,0 +1 @@ + diff --git a/images/2020_02_24/make.png b/images/2020_02_24/make.png new file mode 100644 index 0000000000..258b24a0da Binary files /dev/null and b/images/2020_02_24/make.png differ diff --git a/images/favicon.ico b/images/favicon.ico index 9c654ec23b..f79e7063cf 100644 Binary files a/images/favicon.ico and b/images/favicon.ico differ diff --git a/images/github_pages/jekyll error EASSE.png b/images/github_pages/jekyll error EASSE.png deleted file mode 100644 index 1cacb5e778..0000000000 Binary files a/images/github_pages/jekyll error EASSE.png and /dev/null differ diff --git a/images/github_pages/jekyll error.PNG b/images/github_pages/jekyll error.PNG deleted file mode 100644 index c7c9f28f25..0000000000 Binary files a/images/github_pages/jekyll error.PNG and /dev/null differ diff --git "a/images/github_pages/jekyll serve erro\351\224\231\350\257\2572.PNG" "b/images/github_pages/jekyll serve erro\351\224\231\350\257\2572.PNG" deleted file mode 100644 index b156fc912f..0000000000 Binary files "a/images/github_pages/jekyll serve erro\351\224\231\350\257\2572.PNG" and /dev/null differ diff --git "a/images/github_pages/jekyll server\346\210\220\345\212\237.PNG" "b/images/github_pages/jekyll server\346\210\220\345\212\237.PNG" deleted file mode 100644 index 99757542e4..0000000000 Binary files "a/images/github_pages/jekyll server\346\210\220\345\212\237.PNG" and /dev/null differ diff --git "a/images/github_pages/jekyll\345\256\211\350\243\205.PNG" "b/images/github_pages/jekyll\345\256\211\350\243\205.PNG" deleted file mode 100644 index 4a673313c1..0000000000 Binary files "a/images/github_pages/jekyll\345\256\211\350\243\205.PNG" and /dev/null differ diff --git "a/images/github_pages/\345\256\211\350\243\205ruby.PNG" "b/images/github_pages/\345\256\211\350\243\205ruby.PNG" deleted file mode 100644 index cf4d6ec9f3..0000000000 Binary files "a/images/github_pages/\345\256\211\350\243\205ruby.PNG" and /dev/null differ