├── .gitignore ├── README.md ├── docs └── zh_CN │ ├── .gitignore │ ├── .misc │ ├── .ext │ ├── .site │ └── deprecated │ │ ├── merlin │ │ ├── anti-gfw.rst │ │ └── index.rst │ │ └── shadowsocks.rst │ ├── Makefile │ ├── _fragments │ ├── comment-system.rst │ ├── disqus.rst │ ├── next-step-to-wechat-mp.rst │ └── wechat-reward.rst │ ├── _images │ ├── about │ │ └── recommendation │ │ │ └── 963e4a40f8b937288fa1d6374c50ca5d.png │ ├── appendices │ │ ├── bit-octet │ │ │ ├── 25c354d0c0818a898f0ba66bfccf7302.png │ │ │ └── 4133b65cd2dd48e7be23a8c5bcb10180.gif │ │ └── recommended-books │ │ │ ├── 03a9b09d4c3b8ae1e7c412df427b5f81.jpg │ │ │ ├── 135c03447fbe7397f1ccc57d57be9b88.jpg │ │ │ ├── 288dbc60e22f8345c37ccae07b4d22f1.jpg │ │ │ ├── 9675f146c91a9114a1056028bf2e8d7f.jpg │ │ │ └── c0db2cecebc3b7a2498a68a400e4f708.jpg │ ├── distributed │ │ └── vrrp-vip-floating │ │ │ ├── 3661c2082103036ecb23a3f29be740be.gif │ │ │ ├── 53524cf41abce963473ce0e7fc6ba399.jpg │ │ │ └── a35831e7a7910e0b945c47187a99caf6.jpg │ ├── index │ │ ├── ec5a057f9cb7124f3fae962035072d92.svg │ │ └── fa0282b4b713b843e36395e574c066b6.png │ ├── practices │ │ ├── 1c50f1e9f0bf98f7f495b14377869f71.png │ │ ├── 75d2afbd89bb1516a5f6f12cfda33bad.png │ │ └── c │ │ │ └── endianness │ │ │ ├── a993cff0c201d6645e72b88e38831dc0.png │ │ │ └── e785ff930df62e39597e8b0b4409d50e.png │ ├── protocols │ │ ├── data-link-layer │ │ │ ├── 129372fbd3cfab17acedd6632303680d.png │ │ │ ├── 2191e6281e268396eaf4d18303ab9fb5.png │ │ │ ├── 72936c895af9726f87498ffbe292accd.png │ │ │ ├── 77c9104cf45312384fe61f198739136b.png │ │ │ ├── 967793342e62b831ef0ff7127a4b6537.png │ │ │ ├── 97c13f044de260baf0ed8051091dd251.png │ │ │ ├── 9c11e1fe6649cd4d5fb31a0869cf6545.png │ │ │ └── c40d1f04fd8f51b47cab3a2387d50bfa.png │ │ ├── ethernet-switching │ │ │ ├── 151c80dff5fa653e7d7b563adfba7c41.png │ │ │ ├── 175f7e911cc3a09f0f88487c91ae0143.png │ │ │ ├── 3026a7ee9579986199ce1c6971fb02ae.png │ │ │ ├── 49e8d8c6daff998f64eea9541fdc6ac2.jpg │ │ │ ├── 53cf4917a5902a9a82c038b28a6fd332.gif │ │ │ ├── 7fc0203c170eca22891e36ced4f8e5cf.jpg │ │ │ ├── 8a367213e20260730a4c41dea1a18e68.png │ │ │ ├── 928e0063dc9a2c642e0125a75f52639c.png │ │ │ ├── acb0a0ebc8a69fb9ce5a21ac74ef35ae.png │ │ │ ├── b19011363b3ff0b28385c915b380d71c.jpg │ │ │ ├── d9b3b635c3812953fae1ad2d0c34ca90.png │ │ │ └── f3040c8f5ccbf7852c9d7a0945daf057.png │ │ ├── ethernet │ │ │ ├── 4f8f9e4be6c4202234738affb2b19778.png │ │ │ ├── 7315024ce1bc2ba86f9419e24f1fb27b.png │ │ │ ├── 825d32a1e84c6f1ba1c6970fd677e56a.jpg │ │ │ ├── 96ea51c90a1bd203d59bc8d247e38204.png │ │ │ ├── aedd5053f3b00748b3fae089741d3b5d.jpg │ │ │ └── fb28fd42d6a7e8d61ebfab093e8e906d.png │ │ ├── experiment-linux-routing │ │ │ ├── 50aa9738351bf0d1a92d880542933bc7.png │ │ │ ├── 67c7cba4b4aed0b856624a30ffce8f41.png │ │ │ ├── d065b9ab37eef77473f1f796667e062e.png │ │ │ ├── d53d263de098a395a56d790fdcd02398.png │ │ │ ├── d736840c59690004cf61687db83736eb.png │ │ │ └── e6abba96aadc0edda29aa4df235d981a.png │ │ ├── icmp │ │ │ └── 476c9d2e44224eaa078f80bdbad440f9.gif │ │ ├── ip │ │ │ ├── 4548924d47a16edfb69b5c4026549b4b.png │ │ │ ├── 80c31d33ca6dc57bbda98b146552926c.svg │ │ │ └── bed8aacc992dc152c1bf79ff7c5a9033.png │ │ ├── network-layer │ │ │ ├── 43f85526b7f730866cb087574696dd46.png │ │ │ ├── a13531e70d79522933ce39e3294cdb25.png │ │ │ ├── a6c0bc01c575cc19d29aca64a681ac72.png │ │ │ └── da4c3f29e3c36011339479ddee156a71.png │ │ ├── physical-layer │ │ │ ├── 372a633a4d70a5044455623ad0f56a91.png │ │ │ ├── 3fed1fb3ce11f3e73c606d99dd37272c.png │ │ │ ├── 55477e2f396cb3ed5769a228d98e29db.png │ │ │ ├── 6626019fc6bba63931bc654ccef8d04f.png │ │ │ ├── 6bb1c239ba0f6fa29d1dbee74b5d4448.png │ │ │ ├── 7e77f008253e632cce8dd8e27e160908.png │ │ │ ├── 8a17cc71d646cc1ef651f8979a1a7fa7.png │ │ │ └── d2096209ec8b549234642b9e21219d00.png │ │ ├── ping │ │ │ ├── 31beaa9ddfb5278c7cd98dc4c8624a5b.png │ │ │ └── c633276d3679c45943a4f2d7c2b55e05.png │ │ └── quic │ │ │ ├── a1d7e443d6b493c707e5261876d31f2d.png │ │ │ └── b6c3265b63fd50ce949c3df89a6326d2.png │ ├── security │ │ └── symmetric-asymmetric │ │ │ ├── 0fc9c1c151e9b0ea164b3244d0a4bdac.png │ │ │ ├── 2b448b9c7af85c164f8124ba77e826bf.png │ │ │ ├── 6d1c5facbb0c313428c23e0ec173ac94.png │ │ │ ├── 80ad9b50cce03bf499b54fc0456a33e3.jpg │ │ │ └── f944fcc9e487f4ded786d568ef2e6d86.png │ ├── services │ │ ├── consul │ │ │ └── quick-start │ │ │ │ └── connect │ │ │ │ ├── 1615e82037d8b9c312f12c9428e37482.png │ │ │ │ ├── 8ddad7d692e93846d55018e8ee727116.png │ │ │ │ └── df8c118bfac75e09bb4e3defcbd07ae4.png │ │ ├── haproxy │ │ │ ├── 6a1276e4ac55c2597729ae0551084ffd.gif │ │ │ ├── bb0878dce5b5e85224e64c2f6208d69a.png │ │ │ ├── bb73a4fcd260578b645659c6dfd968f1.png │ │ │ └── fa48a31d52eaa2d04a30e8ddf1dcafe3.png │ │ ├── merlin │ │ │ └── anti-gfw │ │ │ │ ├── 2b2a753196dc5087e6519268953ce0cd.png │ │ │ │ ├── 47a9b4ceb53bd0231893eae60bef5742.png │ │ │ │ ├── a2a8ec24265b7950f5143c3d548b4537.png │ │ │ │ ├── cdf98ae07152776dc5c93de2146dc9ff.png │ │ │ │ └── f5d96be6de654a4ef65bebab5cd31e29.png │ │ ├── port-forwarding │ │ │ ├── 16bcc9128d1c522ad386d584d1bbb63d.png │ │ │ ├── 355c9c3d956d2b9aab7156a5caa8f76c.png │ │ │ └── 9fe45fe01680a9bc1a724b97694ffcb7.png │ │ ├── shadowsocks │ │ │ ├── 11b6df4f704be99f50a2317d4b9fe5c9.png │ │ │ ├── 1a7062411c7f928fc8a66b826d55fd59.png │ │ │ ├── 414a1496fcf6ff2ebeb8adab6b1c8bec.png │ │ │ ├── 4834c68c408cab86dffc0b3e1883fd23.png │ │ │ ├── 52b3f5f2d83dbcad3388f4e75a0f74a6.png │ │ │ ├── 54a6f208109c0d2f797a7a90ead24bfe.png │ │ │ ├── 7fd2db7ae2ff76b72c80fb37ec2a5704.png │ │ │ ├── 87f0c64ca5e4550c99d90611b9291a20.png │ │ │ ├── b0dee7132ba67802f5d75b6ee0eef32e.png │ │ │ └── d6532d5c297cbb741d28e2608bac7aef.png │ │ └── tomcat │ │ │ └── 357b06b730ccb543ff3220f6fdae39a4.png │ ├── toolkit │ │ └── man │ │ │ └── 5dfc3c544562c605f94c8949f87ff6b6.png │ └── translations │ │ ├── cap-theorem-and-distributed-database-management-systems │ │ ├── 202900b8dd5509bfc006cc006a62ccd7.png │ │ ├── 2b4954e5f88028a22c36dd62f4850832.png │ │ ├── 41ac78eba143a642a487a7e11092c2fb.jpeg │ │ ├── 4b8685b22f8665a961ac6a87da8595c5.png │ │ └── bd690aa7a6d02942ed9b66ec2e0cd329.png │ │ ├── linux-tcp-backlog │ │ └── ba9dbb181b283f5c03d650146c8ab15c.png │ │ └── raft-paper │ │ ├── 0a7a377ab90034e62883a6049bd6d73e.png │ │ ├── 2f2d0eea6c824382b881ad77dcc38061.png │ │ ├── 4e9c5586479135670f0c9758df14c259.png │ │ ├── 6b7f4bdd4ab11b6c9c348307778753f7.png │ │ ├── 8e91b9306a84ae3e3685d75ae024ebfe.png │ │ ├── a34814fd407d73bf93700403ad42e926.png │ │ ├── a63f12ba8d5b7d68ca1a016257370022.png │ │ ├── d8a50a2705e4b3d0bac2084961d9e22d.png │ │ └── fa933b96f1cb688befc825c3d82c167d.png │ ├── _src │ ├── _static │ ├── css │ │ ├── hide-ad.css │ │ └── search-box.css │ ├── golang-core-course.jpg │ ├── linux-performance-course.jpg │ ├── logo.png │ ├── qq-group-qrcode-lnp.jpg │ ├── web-front-end-course.jpg │ ├── wechat-mp-qrcode.png │ ├── wechat-reward-g-concise.png │ ├── wechat-reward-g.png │ ├── wechat-reward-lnp.png │ ├── zedhz-course-qrcode.jpg │ └── zedhz-course.jpg │ ├── _templates │ ├── baidu_tongji.html │ ├── baidu_ziyuan.html │ ├── busuanzi.html │ ├── course-ad.html │ ├── course-ad2.html │ ├── disqus.html │ ├── google_analytics.html │ ├── layout.html │ ├── livere.html │ ├── more.html │ ├── reward.html │ ├── sf-namecard-fasionchan.html │ └── wechat-mp-qrcode.html │ ├── about │ ├── contact.rst │ └── index.rst │ ├── acknowledgements │ ├── index.rst │ └── shoulders.rst │ ├── appendices │ ├── blogs.rst │ ├── index.rst │ ├── recommendation │ │ ├── antfin-sre.rst │ │ ├── gf-devops.rst │ │ ├── index.rst │ │ └── list.rst │ ├── recommended-books.rst │ └── resources.rst │ ├── conf.py │ ├── distributed │ ├── index.rst │ └── vrrp-vip-floating.rst │ ├── index.rst │ ├── indexes.rst │ ├── make.bat │ ├── performance │ ├── index.rst │ └── web-pressure-test.rst │ ├── practices │ ├── endianness.rst │ ├── ethernet-programming-c.rst │ ├── ethernet-programming-py.rst │ ├── go-restful-api.rst │ ├── index.rst │ ├── ping-by-icmp-c.rst │ ├── ping-by-icmp-py.rst │ ├── restful-api-by-flask.rst │ └── send-email-by-smtp-py.rst │ ├── protocols │ ├── data-link-layer.rst │ ├── ethernet-switching.rst │ ├── ethernet.rst │ ├── experiment-linux-routing.rst │ ├── index.rst │ ├── ip.rst │ ├── network-layer.rst │ ├── physical-layer.rst │ └── quic.rst │ ├── scripts │ ├── auto-build.sh │ ├── build-deploy.sh │ ├── build.sh │ └── setup.sh │ ├── security │ ├── index.rst │ └── symmetric-asymmetric-encryption.rst │ ├── services │ ├── consul │ │ ├── index.rst │ │ └── quick-start │ │ │ ├── agent.rst │ │ │ ├── checks.rst │ │ │ ├── connect.rst │ │ │ ├── index.rst │ │ │ ├── install.rst │ │ │ ├── join.rst │ │ │ ├── kv.rst │ │ │ ├── services.rst │ │ │ └── ui.rst │ ├── etcd │ │ └── index.rst │ ├── haproxy.rst │ ├── index.rst │ ├── nginx.rst │ ├── ssh-port-forwarding.rst │ └── tomcat.rst │ ├── toolkit │ ├── curl.rst │ ├── ifconfig.rst │ ├── index.rst │ ├── ip.rst │ ├── iperf.rst │ ├── man.rst │ ├── nc.rst │ ├── rinetd.rst │ ├── socat.rst │ └── tcpdump.rst │ └── translations │ ├── cap-theorem-and-distributed-database-management-systems.rst │ ├── index.rst │ ├── linux-tcp-backlog.rst │ ├── raft-paper.rst │ └── socat-linux-unix-tcp-port-forwarding.rst ├── readthedocs.yml ├── requirements ├── docs-dev.txt └── docs.txt └── src ├── c ├── .gitignore ├── endianness │ ├── endianness.c │ └── show.c ├── ethernet │ ├── others │ │ └── send_ether.v1.c │ ├── send_ether.c │ └── show_mac.c ├── icmp │ └── ping │ │ └── ping.c ├── tcp │ └── clock │ │ ├── Makefile │ │ └── server.c └── udp │ ├── echo │ ├── Makefile │ ├── client.c │ └── server.c │ └── multicast │ └── clock │ ├── Makefile │ ├── client.c │ └── server.c ├── go ├── grpc │ └── server-streaming │ │ └── ticker │ │ ├── .gitignore │ │ ├── Makefile │ │ ├── client.go │ │ ├── server.go │ │ ├── tick.pb.go │ │ └── tick.proto ├── restful │ └── go-restful │ │ └── kvs │ │ └── kvs.go └── udp │ └── forwarder │ └── udp-forwarder.go ├── nodejs └── websocket │ ├── client.js │ ├── package.json │ └── server.js └── python ├── .gitignore ├── ethernet ├── send_ether.py └── show_mac.py ├── icmp └── ping │ └── ping.py ├── restful └── flask │ └── kvs │ ├── kvs.py │ └── requirements.txt ├── smtp └── send_email.py └── udp └── echo ├── client.py └── server.py /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.swp 3 | .vscode/ 4 | node_modules/ 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Linux网络编程 2 | 3 | - [首页](https://network.fasionchan.com/zh_CN/latest/) 4 | - [网络协议](https://network.fasionchan.com/zh_CN/latest/protocols/index.html) 5 | - [编程实践](https://network.fasionchan.com/zh_CN/latest/practices/index.html) 6 | - [网络服务](https://network.fasionchan.com/zh_CN/latest/services/index.html) 7 | - [分布式计算](https://network.fasionchan.com/zh_CN/latest/distributed/index.html) 8 | - [性能调优](https://network.fasionchan.com/zh_CN/latest/performance/index.html) 9 | - [工具箱](https://network.fasionchan.com/zh_CN/latest/toolkit/index.html) 10 | - [译文](https://network.fasionchan.com/zh_CN/latest/translations/index.html) 11 | - [内推职位](https://network.fasionchan.com/zh_CN/latest/appendices/recommendation/list.html) 12 | - [附录](https://network.fasionchan.com/zh_CN/latest/appendices/index.html) 13 | 14 | 订阅更新,获取更多学习资料,请关注我们的 [微信公众号](https://network.fasionchan.com/zh_CN/latest/about/contact.html#wechat-mp) : 15 | 16 | ![小菜学编程](https://cdn.fasionchan.com/coding-fan-wechat-soso-qrcode.png?x-oss-process=image/resize,w_400) 17 | -------------------------------------------------------------------------------- /docs/zh_CN/.gitignore: -------------------------------------------------------------------------------- 1 | _build 2 | opt/ 3 | var/ 4 | -------------------------------------------------------------------------------- /docs/zh_CN/.misc/.ext: -------------------------------------------------------------------------------- 1 | > autodoc: automatically insert docstrings from modules (y/n) [n]: 2 | > doctest: automatically test code snippets in doctest blocks (y/n) [n]: 3 | > intersphinx: link between Sphinx documentation of different projects (y/n) [n]: 4 | > todo: write "todo" entries that can be shown or hidden on build (y/n) [n]: 5 | > coverage: checks for documentation coverage (y/n) [n]: 6 | > imgmath: include math, rendered as PNG or SVG images (y/n) [n]: 7 | > mathjax: include math, rendered in the browser by MathJax (y/n) [n]: 8 | > ifconfig: conditional inclusion of content based on config values (y/n) [n]: 9 | > viewcode: include links to the source code of documented Python objects (y/n) [n]: 10 | > githubpages: create .nojekyll file to publish the document on GitHub pages (y/n) [n]: 11 | -------------------------------------------------------------------------------- /docs/zh_CN/.misc/.site: -------------------------------------------------------------------------------- 1 | http://blog.coderclock.com/ 2 | -------------------------------------------------------------------------------- /docs/zh_CN/.misc/deprecated/merlin/index.rst: -------------------------------------------------------------------------------- 1 | .. 梅林(Merlin)路由固件 2 | FileName: index.rst 3 | Author: Fasion Chan 4 | Created: 2019-02-28 19:20:23 5 | @contact: fasionchan@gmail.com 6 | @version: $Id$ 7 | 8 | Description: 9 | 10 | Changelog: 11 | 12 | ==================== 13 | 梅林(Merlin)路由固件 14 | ==================== 15 | 16 | .. toctree:: 17 | :titlesonly: 18 | 19 | 梅林科学上网秘籍 20 | 21 | 22 | .. comments 23 | comment something out below 24 | 25 | .. meta:: 26 | :description lang=zh: 27 | :keywords: 28 | 29 | -------------------------------------------------------------------------------- /docs/zh_CN/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | SPHINXPROJ = Linux 8 | SOURCEDIR = . 9 | BUILDDIR = _build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) -------------------------------------------------------------------------------- /docs/zh_CN/_fragments/comment-system.rst: -------------------------------------------------------------------------------- 1 | .. comment system 2 | FileName: comment-system.rst 3 | Author: Fasion Chan 4 | Created: 2018-03-26 21:33:34 5 | @contact: fasionchan@gmail.com 6 | @version: $Id$ 7 | 8 | Description: 9 | 10 | Changelog: 11 | 12 | .. raw:: html 13 | 14 |
15 | 16 | .. comments 17 | comment something out below 18 | 19 | -------------------------------------------------------------------------------- /docs/zh_CN/_fragments/disqus.rst: -------------------------------------------------------------------------------- 1 | .. disqus 2 | FileName: disqus.rst 3 | Author: Fasion Chan 4 | Created: 2018-03-26 21:33:34 5 | @contact: fasionchan@gmail.com 6 | @version: $Id$ 7 | 8 | Description: 9 | 10 | Changelog: 11 | 12 | .. raw:: html 13 | 14 |
15 | 16 | .. comments 17 | comment something out below 18 | 19 | -------------------------------------------------------------------------------- /docs/zh_CN/_fragments/next-step-to-wechat-mp.rst: -------------------------------------------------------------------------------- 1 | .. 微信公众号 2 | Author: fasion 3 | Created time: 2018-02-01 20:13:35 4 | Last Modified by: fasion 5 | Last Modified time: 2020-03-18 08:29:32 6 | 7 | 订阅更新,获取更多学习资料,请关注我们的 :ref:`wechat-mp` : 8 | 9 | .. figure:: https://cdn.fasionchan.com/coding-fan-wechat-soso-qrcode.png 10 | :width: 400px 11 | :alt: 微信搜索:小菜学编程 12 | 13 | .. comments 14 | comment something out below 15 | -------------------------------------------------------------------------------- /docs/zh_CN/_fragments/wechat-reward.rst: -------------------------------------------------------------------------------- 1 | .. 给赞打赏 2 | Author: fasion 3 | Created time: 2018-02-03 20:16:18 4 | Last Modified by: fasion 5 | Last Modified time: 2020-03-18 08:32:24 6 | 7 | .. figure:: https://cdn.fasionchan.com/coding-fan-geizan.png 8 | :width: 400px 9 | :alt: 微信搜索:小菜学编程 10 | 11 | .. comments 12 | comment something out blow 13 | -------------------------------------------------------------------------------- /docs/zh_CN/_images/about/recommendation/963e4a40f8b937288fa1d6374c50ca5d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/about/recommendation/963e4a40f8b937288fa1d6374c50ca5d.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/appendices/bit-octet/25c354d0c0818a898f0ba66bfccf7302.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/appendices/bit-octet/25c354d0c0818a898f0ba66bfccf7302.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/appendices/bit-octet/4133b65cd2dd48e7be23a8c5bcb10180.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/appendices/bit-octet/4133b65cd2dd48e7be23a8c5bcb10180.gif -------------------------------------------------------------------------------- /docs/zh_CN/_images/appendices/recommended-books/03a9b09d4c3b8ae1e7c412df427b5f81.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/appendices/recommended-books/03a9b09d4c3b8ae1e7c412df427b5f81.jpg -------------------------------------------------------------------------------- /docs/zh_CN/_images/appendices/recommended-books/135c03447fbe7397f1ccc57d57be9b88.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/appendices/recommended-books/135c03447fbe7397f1ccc57d57be9b88.jpg -------------------------------------------------------------------------------- /docs/zh_CN/_images/appendices/recommended-books/288dbc60e22f8345c37ccae07b4d22f1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/appendices/recommended-books/288dbc60e22f8345c37ccae07b4d22f1.jpg -------------------------------------------------------------------------------- /docs/zh_CN/_images/appendices/recommended-books/9675f146c91a9114a1056028bf2e8d7f.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/appendices/recommended-books/9675f146c91a9114a1056028bf2e8d7f.jpg -------------------------------------------------------------------------------- /docs/zh_CN/_images/appendices/recommended-books/c0db2cecebc3b7a2498a68a400e4f708.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/appendices/recommended-books/c0db2cecebc3b7a2498a68a400e4f708.jpg -------------------------------------------------------------------------------- /docs/zh_CN/_images/distributed/vrrp-vip-floating/3661c2082103036ecb23a3f29be740be.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/distributed/vrrp-vip-floating/3661c2082103036ecb23a3f29be740be.gif -------------------------------------------------------------------------------- /docs/zh_CN/_images/distributed/vrrp-vip-floating/53524cf41abce963473ce0e7fc6ba399.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/distributed/vrrp-vip-floating/53524cf41abce963473ce0e7fc6ba399.jpg -------------------------------------------------------------------------------- /docs/zh_CN/_images/distributed/vrrp-vip-floating/a35831e7a7910e0b945c47187a99caf6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/distributed/vrrp-vip-floating/a35831e7a7910e0b945c47187a99caf6.jpg -------------------------------------------------------------------------------- /docs/zh_CN/_images/index/fa0282b4b713b843e36395e574c066b6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/index/fa0282b4b713b843e36395e574c066b6.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/practices/1c50f1e9f0bf98f7f495b14377869f71.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/practices/1c50f1e9f0bf98f7f495b14377869f71.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/practices/75d2afbd89bb1516a5f6f12cfda33bad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/practices/75d2afbd89bb1516a5f6f12cfda33bad.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/practices/c/endianness/a993cff0c201d6645e72b88e38831dc0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/practices/c/endianness/a993cff0c201d6645e72b88e38831dc0.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/practices/c/endianness/e785ff930df62e39597e8b0b4409d50e.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/practices/c/endianness/e785ff930df62e39597e8b0b4409d50e.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/protocols/data-link-layer/129372fbd3cfab17acedd6632303680d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/protocols/data-link-layer/129372fbd3cfab17acedd6632303680d.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/protocols/data-link-layer/2191e6281e268396eaf4d18303ab9fb5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/protocols/data-link-layer/2191e6281e268396eaf4d18303ab9fb5.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/protocols/data-link-layer/72936c895af9726f87498ffbe292accd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/protocols/data-link-layer/72936c895af9726f87498ffbe292accd.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/protocols/data-link-layer/77c9104cf45312384fe61f198739136b.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/protocols/data-link-layer/77c9104cf45312384fe61f198739136b.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/protocols/data-link-layer/967793342e62b831ef0ff7127a4b6537.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/protocols/data-link-layer/967793342e62b831ef0ff7127a4b6537.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/protocols/data-link-layer/97c13f044de260baf0ed8051091dd251.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/protocols/data-link-layer/97c13f044de260baf0ed8051091dd251.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/protocols/data-link-layer/9c11e1fe6649cd4d5fb31a0869cf6545.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/protocols/data-link-layer/9c11e1fe6649cd4d5fb31a0869cf6545.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/protocols/data-link-layer/c40d1f04fd8f51b47cab3a2387d50bfa.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/protocols/data-link-layer/c40d1f04fd8f51b47cab3a2387d50bfa.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/protocols/ethernet-switching/151c80dff5fa653e7d7b563adfba7c41.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/protocols/ethernet-switching/151c80dff5fa653e7d7b563adfba7c41.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/protocols/ethernet-switching/175f7e911cc3a09f0f88487c91ae0143.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/protocols/ethernet-switching/175f7e911cc3a09f0f88487c91ae0143.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/protocols/ethernet-switching/3026a7ee9579986199ce1c6971fb02ae.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/protocols/ethernet-switching/3026a7ee9579986199ce1c6971fb02ae.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/protocols/ethernet-switching/49e8d8c6daff998f64eea9541fdc6ac2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/protocols/ethernet-switching/49e8d8c6daff998f64eea9541fdc6ac2.jpg -------------------------------------------------------------------------------- /docs/zh_CN/_images/protocols/ethernet-switching/53cf4917a5902a9a82c038b28a6fd332.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/protocols/ethernet-switching/53cf4917a5902a9a82c038b28a6fd332.gif -------------------------------------------------------------------------------- /docs/zh_CN/_images/protocols/ethernet-switching/7fc0203c170eca22891e36ced4f8e5cf.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/protocols/ethernet-switching/7fc0203c170eca22891e36ced4f8e5cf.jpg -------------------------------------------------------------------------------- /docs/zh_CN/_images/protocols/ethernet-switching/8a367213e20260730a4c41dea1a18e68.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/protocols/ethernet-switching/8a367213e20260730a4c41dea1a18e68.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/protocols/ethernet-switching/928e0063dc9a2c642e0125a75f52639c.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/protocols/ethernet-switching/928e0063dc9a2c642e0125a75f52639c.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/protocols/ethernet-switching/acb0a0ebc8a69fb9ce5a21ac74ef35ae.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/protocols/ethernet-switching/acb0a0ebc8a69fb9ce5a21ac74ef35ae.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/protocols/ethernet-switching/b19011363b3ff0b28385c915b380d71c.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/protocols/ethernet-switching/b19011363b3ff0b28385c915b380d71c.jpg -------------------------------------------------------------------------------- /docs/zh_CN/_images/protocols/ethernet-switching/d9b3b635c3812953fae1ad2d0c34ca90.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/protocols/ethernet-switching/d9b3b635c3812953fae1ad2d0c34ca90.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/protocols/ethernet-switching/f3040c8f5ccbf7852c9d7a0945daf057.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/protocols/ethernet-switching/f3040c8f5ccbf7852c9d7a0945daf057.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/protocols/ethernet/4f8f9e4be6c4202234738affb2b19778.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/protocols/ethernet/4f8f9e4be6c4202234738affb2b19778.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/protocols/ethernet/7315024ce1bc2ba86f9419e24f1fb27b.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/protocols/ethernet/7315024ce1bc2ba86f9419e24f1fb27b.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/protocols/ethernet/825d32a1e84c6f1ba1c6970fd677e56a.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/protocols/ethernet/825d32a1e84c6f1ba1c6970fd677e56a.jpg -------------------------------------------------------------------------------- /docs/zh_CN/_images/protocols/ethernet/96ea51c90a1bd203d59bc8d247e38204.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/protocols/ethernet/96ea51c90a1bd203d59bc8d247e38204.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/protocols/ethernet/aedd5053f3b00748b3fae089741d3b5d.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/protocols/ethernet/aedd5053f3b00748b3fae089741d3b5d.jpg -------------------------------------------------------------------------------- /docs/zh_CN/_images/protocols/ethernet/fb28fd42d6a7e8d61ebfab093e8e906d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/protocols/ethernet/fb28fd42d6a7e8d61ebfab093e8e906d.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/protocols/experiment-linux-routing/50aa9738351bf0d1a92d880542933bc7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/protocols/experiment-linux-routing/50aa9738351bf0d1a92d880542933bc7.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/protocols/experiment-linux-routing/67c7cba4b4aed0b856624a30ffce8f41.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/protocols/experiment-linux-routing/67c7cba4b4aed0b856624a30ffce8f41.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/protocols/experiment-linux-routing/d065b9ab37eef77473f1f796667e062e.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/protocols/experiment-linux-routing/d065b9ab37eef77473f1f796667e062e.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/protocols/experiment-linux-routing/d53d263de098a395a56d790fdcd02398.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/protocols/experiment-linux-routing/d53d263de098a395a56d790fdcd02398.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/protocols/experiment-linux-routing/d736840c59690004cf61687db83736eb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/protocols/experiment-linux-routing/d736840c59690004cf61687db83736eb.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/protocols/experiment-linux-routing/e6abba96aadc0edda29aa4df235d981a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/protocols/experiment-linux-routing/e6abba96aadc0edda29aa4df235d981a.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/protocols/icmp/476c9d2e44224eaa078f80bdbad440f9.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/protocols/icmp/476c9d2e44224eaa078f80bdbad440f9.gif -------------------------------------------------------------------------------- /docs/zh_CN/_images/protocols/ip/4548924d47a16edfb69b5c4026549b4b.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/protocols/ip/4548924d47a16edfb69b5c4026549b4b.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/protocols/ip/bed8aacc992dc152c1bf79ff7c5a9033.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/protocols/ip/bed8aacc992dc152c1bf79ff7c5a9033.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/protocols/network-layer/43f85526b7f730866cb087574696dd46.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/protocols/network-layer/43f85526b7f730866cb087574696dd46.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/protocols/network-layer/a13531e70d79522933ce39e3294cdb25.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/protocols/network-layer/a13531e70d79522933ce39e3294cdb25.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/protocols/network-layer/a6c0bc01c575cc19d29aca64a681ac72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/protocols/network-layer/a6c0bc01c575cc19d29aca64a681ac72.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/protocols/network-layer/da4c3f29e3c36011339479ddee156a71.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/protocols/network-layer/da4c3f29e3c36011339479ddee156a71.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/protocols/physical-layer/372a633a4d70a5044455623ad0f56a91.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/protocols/physical-layer/372a633a4d70a5044455623ad0f56a91.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/protocols/physical-layer/3fed1fb3ce11f3e73c606d99dd37272c.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/protocols/physical-layer/3fed1fb3ce11f3e73c606d99dd37272c.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/protocols/physical-layer/55477e2f396cb3ed5769a228d98e29db.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/protocols/physical-layer/55477e2f396cb3ed5769a228d98e29db.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/protocols/physical-layer/6626019fc6bba63931bc654ccef8d04f.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/protocols/physical-layer/6626019fc6bba63931bc654ccef8d04f.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/protocols/physical-layer/6bb1c239ba0f6fa29d1dbee74b5d4448.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/protocols/physical-layer/6bb1c239ba0f6fa29d1dbee74b5d4448.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/protocols/physical-layer/7e77f008253e632cce8dd8e27e160908.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/protocols/physical-layer/7e77f008253e632cce8dd8e27e160908.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/protocols/physical-layer/8a17cc71d646cc1ef651f8979a1a7fa7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/protocols/physical-layer/8a17cc71d646cc1ef651f8979a1a7fa7.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/protocols/physical-layer/d2096209ec8b549234642b9e21219d00.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/protocols/physical-layer/d2096209ec8b549234642b9e21219d00.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/protocols/ping/31beaa9ddfb5278c7cd98dc4c8624a5b.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/protocols/ping/31beaa9ddfb5278c7cd98dc4c8624a5b.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/protocols/ping/c633276d3679c45943a4f2d7c2b55e05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/protocols/ping/c633276d3679c45943a4f2d7c2b55e05.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/protocols/quic/a1d7e443d6b493c707e5261876d31f2d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/protocols/quic/a1d7e443d6b493c707e5261876d31f2d.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/protocols/quic/b6c3265b63fd50ce949c3df89a6326d2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/protocols/quic/b6c3265b63fd50ce949c3df89a6326d2.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/security/symmetric-asymmetric/0fc9c1c151e9b0ea164b3244d0a4bdac.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/security/symmetric-asymmetric/0fc9c1c151e9b0ea164b3244d0a4bdac.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/security/symmetric-asymmetric/2b448b9c7af85c164f8124ba77e826bf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/security/symmetric-asymmetric/2b448b9c7af85c164f8124ba77e826bf.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/security/symmetric-asymmetric/6d1c5facbb0c313428c23e0ec173ac94.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/security/symmetric-asymmetric/6d1c5facbb0c313428c23e0ec173ac94.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/security/symmetric-asymmetric/80ad9b50cce03bf499b54fc0456a33e3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/security/symmetric-asymmetric/80ad9b50cce03bf499b54fc0456a33e3.jpg -------------------------------------------------------------------------------- /docs/zh_CN/_images/security/symmetric-asymmetric/f944fcc9e487f4ded786d568ef2e6d86.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/security/symmetric-asymmetric/f944fcc9e487f4ded786d568ef2e6d86.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/services/consul/quick-start/connect/1615e82037d8b9c312f12c9428e37482.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/services/consul/quick-start/connect/1615e82037d8b9c312f12c9428e37482.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/services/consul/quick-start/connect/8ddad7d692e93846d55018e8ee727116.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/services/consul/quick-start/connect/8ddad7d692e93846d55018e8ee727116.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/services/consul/quick-start/connect/df8c118bfac75e09bb4e3defcbd07ae4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/services/consul/quick-start/connect/df8c118bfac75e09bb4e3defcbd07ae4.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/services/haproxy/6a1276e4ac55c2597729ae0551084ffd.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/services/haproxy/6a1276e4ac55c2597729ae0551084ffd.gif -------------------------------------------------------------------------------- /docs/zh_CN/_images/services/haproxy/bb0878dce5b5e85224e64c2f6208d69a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/services/haproxy/bb0878dce5b5e85224e64c2f6208d69a.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/services/haproxy/bb73a4fcd260578b645659c6dfd968f1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/services/haproxy/bb73a4fcd260578b645659c6dfd968f1.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/services/haproxy/fa48a31d52eaa2d04a30e8ddf1dcafe3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/services/haproxy/fa48a31d52eaa2d04a30e8ddf1dcafe3.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/services/merlin/anti-gfw/2b2a753196dc5087e6519268953ce0cd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/services/merlin/anti-gfw/2b2a753196dc5087e6519268953ce0cd.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/services/merlin/anti-gfw/47a9b4ceb53bd0231893eae60bef5742.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/services/merlin/anti-gfw/47a9b4ceb53bd0231893eae60bef5742.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/services/merlin/anti-gfw/a2a8ec24265b7950f5143c3d548b4537.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/services/merlin/anti-gfw/a2a8ec24265b7950f5143c3d548b4537.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/services/merlin/anti-gfw/cdf98ae07152776dc5c93de2146dc9ff.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/services/merlin/anti-gfw/cdf98ae07152776dc5c93de2146dc9ff.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/services/merlin/anti-gfw/f5d96be6de654a4ef65bebab5cd31e29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/services/merlin/anti-gfw/f5d96be6de654a4ef65bebab5cd31e29.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/services/port-forwarding/16bcc9128d1c522ad386d584d1bbb63d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/services/port-forwarding/16bcc9128d1c522ad386d584d1bbb63d.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/services/port-forwarding/355c9c3d956d2b9aab7156a5caa8f76c.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/services/port-forwarding/355c9c3d956d2b9aab7156a5caa8f76c.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/services/port-forwarding/9fe45fe01680a9bc1a724b97694ffcb7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/services/port-forwarding/9fe45fe01680a9bc1a724b97694ffcb7.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/services/shadowsocks/11b6df4f704be99f50a2317d4b9fe5c9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/services/shadowsocks/11b6df4f704be99f50a2317d4b9fe5c9.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/services/shadowsocks/1a7062411c7f928fc8a66b826d55fd59.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/services/shadowsocks/1a7062411c7f928fc8a66b826d55fd59.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/services/shadowsocks/414a1496fcf6ff2ebeb8adab6b1c8bec.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/services/shadowsocks/414a1496fcf6ff2ebeb8adab6b1c8bec.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/services/shadowsocks/4834c68c408cab86dffc0b3e1883fd23.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/services/shadowsocks/4834c68c408cab86dffc0b3e1883fd23.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/services/shadowsocks/52b3f5f2d83dbcad3388f4e75a0f74a6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/services/shadowsocks/52b3f5f2d83dbcad3388f4e75a0f74a6.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/services/shadowsocks/54a6f208109c0d2f797a7a90ead24bfe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/services/shadowsocks/54a6f208109c0d2f797a7a90ead24bfe.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/services/shadowsocks/7fd2db7ae2ff76b72c80fb37ec2a5704.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/services/shadowsocks/7fd2db7ae2ff76b72c80fb37ec2a5704.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/services/shadowsocks/87f0c64ca5e4550c99d90611b9291a20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/services/shadowsocks/87f0c64ca5e4550c99d90611b9291a20.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/services/shadowsocks/b0dee7132ba67802f5d75b6ee0eef32e.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/services/shadowsocks/b0dee7132ba67802f5d75b6ee0eef32e.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/services/shadowsocks/d6532d5c297cbb741d28e2608bac7aef.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/services/shadowsocks/d6532d5c297cbb741d28e2608bac7aef.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/services/tomcat/357b06b730ccb543ff3220f6fdae39a4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/services/tomcat/357b06b730ccb543ff3220f6fdae39a4.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/toolkit/man/5dfc3c544562c605f94c8949f87ff6b6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/toolkit/man/5dfc3c544562c605f94c8949f87ff6b6.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/translations/cap-theorem-and-distributed-database-management-systems/202900b8dd5509bfc006cc006a62ccd7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/translations/cap-theorem-and-distributed-database-management-systems/202900b8dd5509bfc006cc006a62ccd7.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/translations/cap-theorem-and-distributed-database-management-systems/2b4954e5f88028a22c36dd62f4850832.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/translations/cap-theorem-and-distributed-database-management-systems/2b4954e5f88028a22c36dd62f4850832.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/translations/cap-theorem-and-distributed-database-management-systems/41ac78eba143a642a487a7e11092c2fb.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/translations/cap-theorem-and-distributed-database-management-systems/41ac78eba143a642a487a7e11092c2fb.jpeg -------------------------------------------------------------------------------- /docs/zh_CN/_images/translations/cap-theorem-and-distributed-database-management-systems/4b8685b22f8665a961ac6a87da8595c5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/translations/cap-theorem-and-distributed-database-management-systems/4b8685b22f8665a961ac6a87da8595c5.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/translations/cap-theorem-and-distributed-database-management-systems/bd690aa7a6d02942ed9b66ec2e0cd329.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/translations/cap-theorem-and-distributed-database-management-systems/bd690aa7a6d02942ed9b66ec2e0cd329.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/translations/linux-tcp-backlog/ba9dbb181b283f5c03d650146c8ab15c.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/translations/linux-tcp-backlog/ba9dbb181b283f5c03d650146c8ab15c.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/translations/raft-paper/0a7a377ab90034e62883a6049bd6d73e.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/translations/raft-paper/0a7a377ab90034e62883a6049bd6d73e.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/translations/raft-paper/2f2d0eea6c824382b881ad77dcc38061.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/translations/raft-paper/2f2d0eea6c824382b881ad77dcc38061.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/translations/raft-paper/4e9c5586479135670f0c9758df14c259.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/translations/raft-paper/4e9c5586479135670f0c9758df14c259.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/translations/raft-paper/6b7f4bdd4ab11b6c9c348307778753f7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/translations/raft-paper/6b7f4bdd4ab11b6c9c348307778753f7.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/translations/raft-paper/8e91b9306a84ae3e3685d75ae024ebfe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/translations/raft-paper/8e91b9306a84ae3e3685d75ae024ebfe.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/translations/raft-paper/a34814fd407d73bf93700403ad42e926.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/translations/raft-paper/a34814fd407d73bf93700403ad42e926.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/translations/raft-paper/a63f12ba8d5b7d68ca1a016257370022.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/translations/raft-paper/a63f12ba8d5b7d68ca1a016257370022.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/translations/raft-paper/d8a50a2705e4b3d0bac2084961d9e22d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/translations/raft-paper/d8a50a2705e4b3d0bac2084961d9e22d.png -------------------------------------------------------------------------------- /docs/zh_CN/_images/translations/raft-paper/fa933b96f1cb688befc825c3d82c167d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_images/translations/raft-paper/fa933b96f1cb688befc825c3d82c167d.png -------------------------------------------------------------------------------- /docs/zh_CN/_src: -------------------------------------------------------------------------------- 1 | ../../src -------------------------------------------------------------------------------- /docs/zh_CN/_static/css/hide-ad.css: -------------------------------------------------------------------------------- 1 | .rtd-pro-footer-wrapper.body { 2 | display: none; 3 | } 4 | 5 | div.ethical-alabaster { 6 | display: none; 7 | } 8 | -------------------------------------------------------------------------------- /docs/zh_CN/_static/css/search-box.css: -------------------------------------------------------------------------------- 1 | #searchbox { 2 | margin-bottom: 12px; 3 | } 4 | 5 | #searchbox .searchformwrapper { 6 | overflow: hidden; 7 | } 8 | 9 | #searchbox .search div { 10 | display: inline-block; 11 | } 12 | 13 | div.sphinxsidebar #searchbox input[type="text"] { 14 | width: 120px; 15 | } 16 | -------------------------------------------------------------------------------- /docs/zh_CN/_static/golang-core-course.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_static/golang-core-course.jpg -------------------------------------------------------------------------------- /docs/zh_CN/_static/linux-performance-course.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_static/linux-performance-course.jpg -------------------------------------------------------------------------------- /docs/zh_CN/_static/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_static/logo.png -------------------------------------------------------------------------------- /docs/zh_CN/_static/qq-group-qrcode-lnp.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_static/qq-group-qrcode-lnp.jpg -------------------------------------------------------------------------------- /docs/zh_CN/_static/web-front-end-course.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_static/web-front-end-course.jpg -------------------------------------------------------------------------------- /docs/zh_CN/_static/wechat-mp-qrcode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_static/wechat-mp-qrcode.png -------------------------------------------------------------------------------- /docs/zh_CN/_static/wechat-reward-g-concise.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_static/wechat-reward-g-concise.png -------------------------------------------------------------------------------- /docs/zh_CN/_static/wechat-reward-g.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_static/wechat-reward-g.png -------------------------------------------------------------------------------- /docs/zh_CN/_static/wechat-reward-lnp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_static/wechat-reward-lnp.png -------------------------------------------------------------------------------- /docs/zh_CN/_static/zedhz-course-qrcode.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_static/zedhz-course-qrcode.jpg -------------------------------------------------------------------------------- /docs/zh_CN/_static/zedhz-course.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-fans/linux-network-programming/d4fec7d2fb4585302469c616c530b3b86440c86c/docs/zh_CN/_static/zedhz-course.jpg -------------------------------------------------------------------------------- /docs/zh_CN/_templates/baidu_tongji.html: -------------------------------------------------------------------------------- 1 | {% set baidu_analytics_id='3d7584e34115fda9fc343709c57a7130' %} 2 | 3 | 12 | -------------------------------------------------------------------------------- /docs/zh_CN/_templates/baidu_ziyuan.html: -------------------------------------------------------------------------------- 1 | 15 | -------------------------------------------------------------------------------- /docs/zh_CN/_templates/busuanzi.html: -------------------------------------------------------------------------------- 1 | 2 | 本站总访问量 3 | -------------------------------------------------------------------------------- /docs/zh_CN/_templates/course-ad.html: -------------------------------------------------------------------------------- 1 |

大牛课程

2 | 3 | 我已加入学习,邀你一起! 4 | -------------------------------------------------------------------------------- /docs/zh_CN/_templates/course-ad2.html: -------------------------------------------------------------------------------- 1 |
2 |

大牛课程

3 | 4 | {% for course in [ 5 | { 6 | "url": "https://time.geekbang.org/column/intro/140?code=watzFY59C5wIYB3ECn%2FScBaIFq5k8pPz9UU8ADR%2Fd4s%3D&utm_term=SPoster", 7 | "url": "https://time.geekbang.org/column/intro/140?code=watzFY59C5wIYB3ECn%2FScBaIFq5k8pPz9UU8ADR%2Fd4s%3D", 8 | "path": "_static/linux-performance-course.jpg", 9 | }, 10 | { 11 | "url": "https://time.geekbang.org/column/intro/112?code=S1Gimo52SvlZRR-d1JmFhwo3qiM%2FeyKiszh4wwpkW70%3D&utm_term=SPoster", 12 | "url": "https://time.geekbang.org/column/intro/112?code=S1Gimo52SvlZRR-d1JmFhwo3qiM%2FeyKiszh4wwpkW70%3D", 13 | "path": "_static/golang-core-course.jpg", 14 | }, 15 | { 16 | "url": "https://time.geekbang.org/column/intro/154?code=VicNYaXq1%2Ff9xQ-rrWlMfr%2FPoyYAw4D8eN8mB5SZTjA%3D&utm_term=SPoster", 17 | "url": "https://time.geekbang.org/column/intro/154?code=VicNYaXq1%2Ff9xQ-rrWlMfr%2FPoyYAw4D8eN8mB5SZTjA%3D", 18 | "path": "_static/web-front-end-course.jpg", 19 | }, 20 | { 21 | "url": "https://time.geekbang.org/column/intro/48?code=vPMg2o7CvYAvCtdAV7DY5UvvS1DzcRNcImRZy3KzttE%3D&utm_term=SPoster", 22 | "url": "https://time.geekbang.org/column/intro/48?code=vPMg2o7CvYAvCtdAV7DY5UvvS1DzcRNcImRZy3KzttE%3D", 23 | "path": "_static/zedhz-course.jpg", 24 | }, 25 | ] %} 26 | 27 | 28 | 29 | {% endfor %} 30 | 31 |
32 | 33 | 41 | -------------------------------------------------------------------------------- /docs/zh_CN/_templates/disqus.html: -------------------------------------------------------------------------------- 1 | {% set disqus_domain='linux-network-programming.disqus.com' %} 2 | 3 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /docs/zh_CN/_templates/google_analytics.html: -------------------------------------------------------------------------------- 1 | {% set google_analytics_id='UA-113160431-1' %} 2 | 3 | 4 | 5 | 12 | -------------------------------------------------------------------------------- /docs/zh_CN/_templates/layout.html: -------------------------------------------------------------------------------- 1 | {% extends "!layout.html" %} 2 | 3 | {% block extrahead %} 4 | {% include 'google_analytics.html' %} 5 | {{ super() }} 6 | {% endblock extrahead %} 7 | 8 | {% block document %} 9 | {{ super() }} 10 | {% endblock %} 11 | 12 | {% block content %} 13 |
14 | 15 |
16 | 17 | {{ super() }} 18 | {% endblock %} 19 | 20 | {% block footer %} 21 | 35 | 36 | {% if theme_github_banner|lower != 'false' %} 37 | 38 | Fork me on GitHub 39 | 40 | {% endif %} 41 | 42 | {% include 'baidu_tongji.html' %} 43 | {% include 'baidu_ziyuan.html' %} 44 | {% include 'disqus.html' %} 45 | {% endblock %} 46 | 47 | {# 48 | {% include 'livere.html' %} 49 | {% include 'busuanzi.html' %} 50 | #} 51 | -------------------------------------------------------------------------------- /docs/zh_CN/_templates/livere.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | 16 | 17 |
18 | 19 | -------------------------------------------------------------------------------- /docs/zh_CN/_templates/more.html: -------------------------------------------------------------------------------- 1 |

更多阅读

2 | 28 | -------------------------------------------------------------------------------- /docs/zh_CN/_templates/reward.html: -------------------------------------------------------------------------------- 1 |

微信打赏

2 | 3 | -------------------------------------------------------------------------------- /docs/zh_CN/_templates/sf-namecard-fasionchan.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /docs/zh_CN/_templates/wechat-mp-qrcode.html: -------------------------------------------------------------------------------- 1 |

微信公众号

2 | 3 | -------------------------------------------------------------------------------- /docs/zh_CN/about/contact.rst: -------------------------------------------------------------------------------- 1 | .. 交流 2 | FileName: contact.rst 3 | Author: Fasion Chan 4 | Created: 2018-01-27 20:09:58 5 | @contact: fasionchan@gmail.com 6 | @version: $Id$ 7 | 8 | Description: 9 | 10 | Changelog: 11 | 12 | ==== 13 | 交流 14 | ==== 15 | 16 | GitHub 17 | ====== 18 | 19 | 本项目所有示例代码托管在 ``GitHub`` 上,仓库是: 20 | `linux-network-programming `_ 。 21 | 22 | 建议初学者亲自动手,将所有示例程序编写一遍,加深理解。 23 | **编程没有捷径** ,唯有带着 **好奇心** 探索程序背后的秘密,多动手勤练习,方能编写出你的理想世界。 24 | 25 | 如需与我们交流,也可以在在本项目中 `新建一个Issue `_ , 26 | 以这种形式进行讨论。 27 | 内容可以包括但不局限于: 28 | 29 | - ``BUG`` 反馈 30 | - 建议 31 | - 提问 32 | 33 | 点击左边 ``Star`` 按钮,关注本项目。 34 | 对于后续任何更新,尽在掌握! 35 | 36 | .. _wechat-mp: 37 | 38 | 微信公众号 39 | ========== 40 | 41 | .. figure:: /_static/wechat-mp-qrcode.png 42 | :align: center 43 | 44 | *小菜学编程* 45 | 46 | 我们维护了一个微信公众号—— **小菜学编程** ,欢迎扫二维码关注我们。 47 | 48 | 对于后续更新,我们会以公众号文章的形式进行推送,这是订阅我们内容的最佳渠道。 49 | 也欢迎通过公众号给我们留言,同样可以包括但不局限于: 50 | 51 | - ``BUG`` 反馈 52 | - 建议 53 | - 提问 54 | 55 | QQ交流群 56 | ======== 57 | 58 | .. figure:: /_static/qq-group-qrcode-lnp.jpg 59 | :width: 270px 60 | :align: center 61 | 62 | 我们维护了一个 ``QQ`` 群( `183196643 `_ ),用于日常的交流讨论。 63 | 64 | 与 ``Linux`` 网络编程相关的话题,都可以在群里讨论,无须局限于本项目。 65 | 对于学习或者工作中遇到的疑难问题,欢迎到群里提问。 66 | 也欢迎各位热心老司机为新手们答疑解惑。 67 | 68 | 邮件 69 | ==== 70 | 71 | 当然了,更书面的形式也支持,你可以给我们:`发送邮件 `_ 。 72 | 73 | .. comments 74 | comment something out blow 75 | 76 | -------------------------------------------------------------------------------- /docs/zh_CN/about/index.rst: -------------------------------------------------------------------------------- 1 | .. 关于 2 | FileName: index.rst 3 | Author: Fasion Chan 4 | Created: 2018-01-27 20:08:14 5 | @contact: fasionchan@gmail.com 6 | @version: $Id$ 7 | 8 | Description: 9 | 10 | Changelog: 11 | 12 | ==== 13 | 关于 14 | ==== 15 | 16 | .. toctree:: 17 | :titlesonly: 18 | 19 | 交流 20 | 推荐书单 21 | 内推职位 22 | 23 | .. comments 24 | comment something out blow 25 | -------------------------------------------------------------------------------- /docs/zh_CN/acknowledgements/index.rst: -------------------------------------------------------------------------------- 1 | .. 鸣谢 2 | FileName: index.rst 3 | Author: Fasion Chan 4 | Created: 2018-01-27 15:43:10 5 | @contact: fasionchan@gmail.com 6 | @version: $Id$ 7 | 8 | Description: 9 | 10 | Changelog: 11 | 12 | 鸣谢 13 | ==== 14 | 15 | .. toctree:: 16 | :maxdepth: 2 17 | 18 | 巨人肩膀 19 | 20 | 21 | .. comments 22 | comment something out below 23 | 24 | http://www.sphinx-doc.org/en/stable/markup/code.html#directive-code-block 25 | http://pygments.org/docs/lexers/ 26 | http://docs.readthedocs.io/en/latest/getting_started.html 27 | -------------------------------------------------------------------------------- /docs/zh_CN/acknowledgements/shoulders.rst: -------------------------------------------------------------------------------- 1 | .. 巨人肩膀 2 | FileName: shoulders.rst 3 | Author: Fasion Chan 4 | Created: 2018-01-27 15:47:28 5 | @contact: fasionchan@gmail.com 6 | @version: $Id$ 7 | 8 | Description: 9 | 10 | Changelog: 11 | 12 | ======== 13 | 巨人肩膀 14 | ======== 15 | 16 | 创作工具 17 | ======== 18 | 19 | - **代码高亮** 使用 `Pygments `_ ,`支持语言 `_ 非常全面; 20 | 21 | .. comments 22 | comment something out blow 23 | 24 | -------------------------------------------------------------------------------- /docs/zh_CN/appendices/blogs.rst: -------------------------------------------------------------------------------- 1 | .. 2 | Author: fasion 3 | Created time: 2019-10-09 09:42:17 4 | Last Modified by: fasion 5 | Last Modified time: 2019-10-09 11:15:17 6 | 7 | ======== 8 | 推荐博客 9 | ======== 10 | 11 | `kaiyuan.me `_ 12 | 13 | `www.hollischuang.com `_ 14 | -------------------------------------------------------------------------------- /docs/zh_CN/appendices/index.rst: -------------------------------------------------------------------------------- 1 | .. 附录 2 | FileName: index.rst 3 | Author: Fasion Chan 4 | Created: 2018-01-27 14:24:28 5 | @contact: fasionchan@gmail.com 6 | @version: $Id$ 7 | 8 | Description: 9 | 10 | Changelog: 11 | 12 | ==== 13 | 附录 14 | ==== 15 | 16 | .. toctree:: 17 | :titlesonly: 18 | 19 | 推荐书单 20 | 推荐博客 21 | 内推职位 22 | 内推职位列表 23 | 24 | .. comments 25 | comment something out blow 26 | 27 | -------------------------------------------------------------------------------- /docs/zh_CN/appendices/recommendation/antfin-sre.rst: -------------------------------------------------------------------------------- 1 | .. 【内推】蚂蚁金服-蚂蚁金融云SRE 2 | FileName: antfin-sre.rst 3 | Author: Fasion Chan 4 | Created: 2018-01-28 10:11:27 5 | @contact: fasionchan@gmail.com 6 | @version: $Id$ 7 | 8 | Description: 9 | 10 | Changelog: 11 | 12 | .. meta:: 13 | :description lang=zh: 14 | 蚂蚁金服内推招聘岗位,金融云SRE,工作地杭州、上海均可。 15 | :keywords: 内推, 蚂蚁金服, antfin, sre, 金融云, 面试 16 | 17 | ============================== 18 | 【内推】蚂蚁金服-蚂蚁金融云SRE 19 | ============================== 20 | 21 | .. figure:: /_images/about/recommendation/963e4a40f8b937288fa1d6374c50ca5d.png 22 | :width: 150px 23 | :align: center 24 | 25 | 职位描述 26 | ======== 27 | 28 | #. 负责蚂蚁金融云平台的运维保障,包括交付、监控、变更、应急响应、故障恢复,是生产系统的Owner; 29 | #. 负责蚂蚁公有云/专有云站点建设、发布部署、监控巡检、变更管控等运维体系的建设,对效能提升有深刻的理解和实践; 30 | #. 为蚂蚁金融云产品的稳定、高效运行负责,支撑金融云整体业务快速发展; 31 | #. 具备研发能力,通过研发解决运维体系的稳定性、效率、成本管理等问题; 32 | 33 | 任职要求 34 | ======== 35 | 36 | #. 大学本科及以上学历,计算机或者相关专业; 37 | #. 知名互联网企业三年以上应用运维经验,具备 `Java` 、 `Python`_ 研发能力优先; 38 | #. 深入理解 `Linux`_ 系统,运维体系结构,精于稳定性提升、效能提升; 39 | #. 具有良好的团队协作、沟通能力,乐于分享,良好的客户服务意识; 40 | #. 能够承受较大的工作压力,以结果和行动为准则,努力追求成功; 41 | 42 | 工作地点 43 | ======== 44 | 45 | - 杭州 46 | - 上海 47 | 48 | 申请方式 49 | ======== 50 | 51 | 请将简历投递至邮箱: 52 | `fasionchan+lnp.antfin-sre@gmail.com `_ 53 | ,我们会尽快处理! 54 | 55 | .. _Linux: https://learn-linux.readthedocs.io/zh_CN/latest/ 56 | .. _Python: https://python-book.readthedocs.io/zh_CN/latest/ 57 | 58 | .. comments 59 | comment something out below 60 | 61 | -------------------------------------------------------------------------------- /docs/zh_CN/appendices/recommendation/gf-devops.rst: -------------------------------------------------------------------------------- 1 | .. 【内推 2 | FileName: gf-devops.rst 3 | Author: Fasion Chan 4 | Created: 2019-01-23 10:38:41 5 | @contact: fasionchan@gmail.com 6 | @version: $Id$ 7 | 8 | Description: 9 | 10 | Changelog: 11 | 12 | .. meta:: 13 | :description lang=zh: 14 | :keywords: 内推, 广发证券, devops, 运维研发, Linux, Python, Go, 面试 15 | 16 | =============================== 17 | 【内推】广发证券-数字化运维研发 18 | =============================== 19 | 20 | 25k-45k / 广州 / 本科及以上 / 经验3-5年 / 硕士校招亦可 / 全职 / 环境好 / 福利多 21 | 22 | 任职要求 23 | ======== 24 | 25 | #. 熟悉Linux、Windows操作系统; 26 | #. 优秀的Python语言开发能力,PHP、Java亦可,有Web开发能力; 27 | #. 熟练常用的自动化运维工具,例如Ansible、SaltStack、Puppet等; 28 | #. 熟悉常用的持续集成工具Jenkins、TeamCity、Git等; 29 | #. 熟悉常用的监控工具,例如Zabbix、Nagios等; 30 | #. 良好的学习、沟通和协调能力,有高度的责任心和团队合作精神; 31 | #. 有运维平台、监控报警等系统开发经验者优先; 32 | #. 有互联网行业及金融行业经验优先; 33 | 34 | 申请方式 35 | ======== 36 | 37 | 请将简历投递至邮箱: 38 | `fasionchan+lnp.gf-devops@gmail.com `_ 39 | ,我们会尽快处理! 40 | 41 | .. comments 42 | comment something out below 43 | 44 | -------------------------------------------------------------------------------- /docs/zh_CN/appendices/recommendation/index.rst: -------------------------------------------------------------------------------- 1 | .. 内推职位 2 | FileName: index.rst 3 | Author: Fasion Chan 4 | Created: 2018-01-27 22:38:52 5 | @contact: fasionchan@gmail.com 6 | @version: $Id$ 7 | 8 | Description: 9 | 10 | Changelog: 11 | 12 | ======== 13 | 内推职位 14 | ======== 15 | 16 | 蚂蚁金服 17 | ======== 18 | 19 | - :doc:`蚂蚁金融云SRE ` 20 | 21 | 广发证券 22 | ======== 23 | 24 | - :doc:`数字化运维研发 ` 25 | 26 | .. comments 27 | comment something out blow 28 | 29 | -------------------------------------------------------------------------------- /docs/zh_CN/appendices/recommendation/list.rst: -------------------------------------------------------------------------------- 1 | .. 内推职位列表 2 | FileName: list.rst 3 | Author: Fasion Chan 4 | Created: 2019-02-19 19:23:04 5 | @contact: fasionchan@gmail.com 6 | @version: $Id$ 7 | 8 | Description: 9 | 10 | Changelog: 11 | 12 | .. meta:: 13 | :description lang=zh: 14 | :keywords: 15 | 16 | ============ 17 | 内推职位列表 18 | ============ 19 | 20 | .. toctree:: 21 | :titlesonly: 22 | 23 | 蚂蚁金融云SRE 24 | 广发证券数字化运维研发 25 | 26 | .. comments 27 | comment something out below 28 | 29 | -------------------------------------------------------------------------------- /docs/zh_CN/appendices/recommended-books.rst: -------------------------------------------------------------------------------- 1 | .. 推荐书单 2 | FileName: recommended-books.rst 3 | Author: Fasion Chan 4 | Created: 2018-07-09 20:14:35 5 | @contact: fasionchan@gmail.com 6 | @version: $Id$ 7 | 8 | Description: 9 | 10 | Changelog: 11 | 12 | ======== 13 | 推荐书单 14 | ======== 15 | 16 | 网络协议 17 | ======== 18 | 19 | .. figure:: /_images/appendices/recommended-books/03a9b09d4c3b8ae1e7c412df427b5f81.jpg 20 | :width: 160px 21 | :target: https://book.douban.com/subject/1088054/ 22 | 23 | *TCP/IP详解 卷1:协议* 24 | 👉 `豆瓣 `__ / 25 | 26 | .. figure:: /_images/appendices/recommended-books/9675f146c91a9114a1056028bf2e8d7f.jpg 27 | :width: 160px 28 | :target: https://book.douban.com/subject/10746113/ 29 | 30 | *HTTP权威指南* 31 | 👉 `豆瓣 `__ / 32 | 33 | 网络编程 34 | ======== 35 | 36 | .. figure:: /_images/appendices/recommended-books/c0db2cecebc3b7a2498a68a400e4f708.jpg 37 | :width: 160px 38 | :target: https://book.douban.com/subject/1500149/ 39 | 40 | *UNIX网络编程 第1卷:套接口API* 41 | 👉 `豆瓣 `__ / 42 | 43 | .. figure:: /_images/appendices/recommended-books/135c03447fbe7397f1ccc57d57be9b88.jpg 44 | :width: 160px 45 | :target: https://book.douban.com/subject/6058986/ 46 | 47 | *TCP/IP高效编程* 48 | 👉 `豆瓣 `__ / 49 | 50 | 下一步 51 | ====== 52 | 53 | .. include:: /_fragments/next-step-to-wechat-mp.rst 54 | 55 | .. include:: /_fragments/wechat-reward.rst 56 | 57 | .. include:: /_fragments/disqus.rst 58 | 59 | .. comments 60 | comment something out below 61 | 62 | .. meta:: 63 | :description lang=zh: 64 | :keywords: 65 | -------------------------------------------------------------------------------- /docs/zh_CN/appendices/resources.rst: -------------------------------------------------------------------------------- 1 | .. 素材库 2 | FileName: resources.rst 3 | Author: Fasion Chan 4 | Created: 2018-02-05 19:02:08 5 | @contact: fasionchan@gmail.com 6 | @version: $Id$ 7 | 8 | Description: 9 | 10 | Changelog: 11 | 12 | ====== 13 | 素材库 14 | ====== 15 | 16 | 图片 17 | ==== 18 | 19 | .. figure:: /_images/appendices/bit-octet/25c354d0c0818a898f0ba66bfccf7302.png 20 | 21 | *比特与字节* 22 | 23 | .. figure:: /_images/appendices/bit-octet/4133b65cd2dd48e7be23a8c5bcb10180.gif 24 | 25 | *比特与数值* 26 | 27 | .. figure:: /_images/protocols/ip/4548924d47a16edfb69b5c4026549b4b.png 28 | 29 | .. figure:: /_images/protocols/ip/80c31d33ca6dc57bbda98b146552926c.svg 30 | 31 | .. comments 32 | comment something out blow 33 | 34 | https://www.google.com/webmasters/tools/submit-url?hl=zh-CN 35 | https://ziyuan.baidu.com/linksubmit/url 36 | 37 | https://www.edrawsoft.com/orderedrawmax.php 38 | http://staruml.io/download 39 | https://www.visual-paradigm.com/editions/ 40 | https://modeling-languages.com/uml-tools/#MAC 41 | http://www.excelsoftware.com/maca&dproducts.html 42 | https://www.quora.com/What-are-the-best-UML-tools-for-Mac-OS-X 43 | -------------------------------------------------------------------------------- /docs/zh_CN/distributed/index.rst: -------------------------------------------------------------------------------- 1 | .. 分布式计算 2 | FileName: index.rst 3 | Author: Fasion Chan 4 | Created: 2018-10-09 20:53:04 5 | @contact: fasionchan@gmail.com 6 | @version: $Id$ 7 | 8 | Description: 9 | 10 | Changelog: 11 | 12 | 分布式计算 13 | ========== 14 | 15 | .. toctree:: 16 | :titlesonly: 17 | 18 | CAP定理 19 | VRRP虚IP漂移 20 | 21 | .. comments 22 | comment something out below 23 | 24 | -------------------------------------------------------------------------------- /docs/zh_CN/distributed/vrrp-vip-floating.rst: -------------------------------------------------------------------------------- 1 | .. VRRP虚IP漂移 2 | FileName: vrrp-vip-floating.rst 3 | Author: Fasion Chan 4 | Created: 2018-10-10 14:16:09 5 | @contact: fasionchan@gmail.com 6 | @version: $Id$ 7 | 8 | Description: 9 | 10 | Changelog: 11 | 12 | .. meta:: 13 | :keywords: VRRP, VIP, virtual IP, 虚IP, 虚IP漂移, 虚IP高可用 14 | 15 | ============ 16 | VRRP虚IP漂移 17 | ============ 18 | 19 | 简介 20 | ==== 21 | 22 | `VRRP`_ 是 `Virtual Router Redundancy Protocol` 的简称,即 **虚拟路由冗余协议** 。 23 | 24 | `VRRP`_ 最早被设计来解决网关的高可用问题: 25 | 26 | 我们知道,计算机进行网络通讯时,需要网关来传输网络报文。 27 | 每台机器只能配置一个网关地址,这时网关的可靠性就非常重要了。 28 | 如果网关不幸故障了,那么使用该网关的所有机器都将受影响——断网了! 29 | 30 | 解决网关单点问题的思路非常直观——部署一个备用网关,在主网关故障时切换过去。 31 | 32 | 然而,由于机器只能配置一个网关地址,因此每次切换网关都需要修改该配置。 33 | 这个解决方案没能做到自动化,并不优雅。 34 | 35 | 这时, `VRRP`_ 应运而生!接下来,以一个简单的例子介绍 `VRRP`_ 是如何工作的: 36 | 37 | .. figure:: /_images/distributed/vrrp-vip-floating/a35831e7a7910e0b945c47187a99caf6.jpg 38 | 39 | *VRRP最早用于网关高可用* 40 | 41 | 事情是这样的。 42 | 43 | 这个网络部署了两台 **路由** 进行互备,本网络内其他机器以这两台路由为网关进行网络通讯。 44 | 两台路由的 `IP` 地址分别是: `192.168.1.1` 以及 `192.168.1.2` 。 45 | 但路由并不直接通过这些地址提供转发服务,而是使用一个 **虚拟地址** `192.168.1.253` 。 46 | 其他计算机,如 `192.168.1.3` 将网关地址配置为 `192.168.1.253` 。 47 | 48 | 通过 `VRRP`_ ,两台路由互相进行 **健康检查** 。 49 | 当两台路由都是健康的情况下,只有主路由对外提供虚拟地址的 `ARP` 响应。 50 | 这时,发往虚拟地址 `192.168.1.253` 的流量都由主路由处理。 51 | 52 | 当主路由故障时,备用路由将检测到。 53 | 这时,备用路由开始通过 `ARP` 协议对外通告:虚拟地址 `192.168.1.253` 对应的 `MAC` 地址是我, 被我接管了! 54 | 55 | 接下来,发往虚拟地址 `192.168.1.253` 的流量就开始由备用路由处理了。 56 | 这时,虚拟地址 `192.168.1.253` 看上去就像是 **漂移** 到备用路由上一样。 57 | 换句话讲,网关成功进行切换,而且无需修改其他机器的网关配置! 58 | 59 | 主路由恢复后,将通过类似的手段,重新拿回流量的处理权。 60 | 这部分将不再赘述。 61 | 62 | 完整流程如下: 63 | 64 | #. 两台路由互相进行健康检查; 65 | #. 主路由对外响应虚拟地址的 `ARP` 请求,通告其 `MAC` 地址; 66 | #. 虚拟地址网络流量被主路由处理; 67 | #. 备用路由发现主路由故障,开始响应虚拟地址的 `ARP` 请求,通告其 `MAC` 地址; 68 | #. 虚拟地址网络流量被备用路由处理; 69 | #. 主路由恢复,重新响应 `ARP` 请求,夺回流量; 70 | #. 备用路由发现主路由恢复,停止响应 `ARP` 请求,释放流量处理权; 71 | 72 | 总结起来, `VRRP`_ 主要做两件事情: 73 | 74 | #. 通过 `ARP` 响应 `MAC` 地址实现虚 `IP` 漂移; 75 | #. 通过健康检查决定什么时候进行虚 `IP` 漂移; 76 | 77 | 应用场景 78 | ======== 79 | 80 | 本质上, `VRRP`_ 是用来实现高可用的,与网关无关。 81 | 82 | 我们可以将其应用于一些网络服务的高可用,如 `Web` 服务: 83 | 84 | .. figure:: /_images/distributed/vrrp-vip-floating/53524cf41abce963473ce0e7fc6ba399.jpg 85 | :width: 360px 86 | 87 | *Web服务高可用* 88 | 89 | 服务高可用方案有很多, `VRRP`_ 特别适用于以下场景: 90 | 91 | #. 服务对外只能呈现为单个 `IP` ; 92 | #. 同一时刻只允许一个实例对外服务; 93 | 94 | 此外, `VRRP`_ 也可用于实现负载均衡设施的高可用。 95 | 应用的高可用通过负载均衡设施解决,那么负载均衡设施如何实现高可用呢? 96 | 答案是—— `VRRP`_ ! 97 | 98 | 下面是一个非常典型的例子: 99 | 100 | .. figure:: /_images/distributed/vrrp-vip-floating/3661c2082103036ecb23a3f29be740be.gif 101 | 102 | *负载均衡设施高可用* 103 | 104 | 局限性 105 | ====== 106 | 107 | 由于 `VRRP`_ 依赖 `ARP` 实现 `IP` 漂移,因此相关机器必须在同个网络内, **不能跨网段** 。 108 | 109 | 下一步 110 | ====== 111 | 112 | .. include:: /_fragments/next-step-to-wechat-mp.rst 113 | 114 | .. include:: /_fragments/wechat-reward.rst 115 | 116 | .. include:: /_fragments/disqus.rst 117 | 118 | .. comments 119 | comment something out below 120 | 121 | .. _VRRP: https://en.wikipedia.org/wiki/Virtual_Router_Redundancy_Protocol 122 | -------------------------------------------------------------------------------- /docs/zh_CN/index.rst: -------------------------------------------------------------------------------- 1 | .. Linux网络编程 2 | FileName: index.rst 3 | Author: Fasion Chan 4 | Created: 2018-01-28 11:45:04 5 | @contact: fasionchan@gmail.com 6 | @version: $Id$ 7 | 8 | Description: 9 | 10 | Changelog: 11 | 12 | Note: 13 | You can adapt this file completely to your liking, but it should at least 14 | contain the root `toctree` directive. 15 | 16 | .. meta:: 17 | :description lang=zh: 18 | Linux网络编程入门教程,面向初学者,例子丰富,讲解详细。 19 | :keywords: Linux, 网络编程, 套接字编程, 网络协议, TCP/IP, 套接字, socket 20 | 21 | 22 | Linux网络编程 23 | ============= 24 | 25 | .. figure:: /_images/index/ec5a057f9cb7124f3fae962035072d92.svg 26 | 27 | .. toctree:: 28 | :titlesonly: 29 | 30 | 关于 31 | 网络协议 32 | 编程实践 33 | 网络服务 34 | 分布式计算 35 | 性能调优 36 | 信息安全 37 | 工具箱 38 | 译文 39 | 附录 40 | 索引 41 | 鸣谢 42 | 43 | .. comments 44 | comment something out below 45 | 46 | Indices and tables 47 | ================== 48 | 49 | * :ref:`genindex` 50 | * :ref:`modindex` 51 | * :ref:`search` 52 | -------------------------------------------------------------------------------- /docs/zh_CN/indexes.rst: -------------------------------------------------------------------------------- 1 | .. 索引 2 | FileName: indexes.rst 3 | Author: Fasion Chan 4 | Created: 2018-02-11 22:06:07 5 | @contact: fasionchan@gmail.com 6 | @version: $Id$ 7 | 8 | Description: 9 | 10 | Changelog: 11 | 12 | ==== 13 | 索引 14 | ==== 15 | 16 | .. comments 17 | 18 | .. _indexes-j: 19 | 20 | J 21 | = 22 | 23 | .. _indexes-m: 24 | 25 | M 26 | = 27 | 28 | - :ref:`mac-address-auto-learning` 29 | 30 | .. _indexes-s: 31 | 32 | S 33 | = 34 | 35 | - :ref:`data-link-layer` 36 | 37 | .. _indexes-w: 38 | 39 | W 40 | = 41 | 42 | - :ref:`nic` 43 | - :ref:`physical-layer` 44 | 45 | .. _indexes-y: 46 | 47 | Y 48 | = 49 | 50 | - :ref:`ethernet-switcher` 51 | - :ref:`ethernet-hub` 52 | - :ref:`ethernet-switching` 53 | - :ref:`ethernet-protocol` 54 | - :ref:`ethernet-frame` 55 | 56 | .. comments 57 | comment something out blow 58 | 59 | -------------------------------------------------------------------------------- /docs/zh_CN/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=. 11 | set BUILDDIR=_build 12 | set SPHINXPROJ=Linux 13 | 14 | if "%1" == "" goto help 15 | 16 | %SPHINXBUILD% >NUL 2>NUL 17 | if errorlevel 9009 ( 18 | echo. 19 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 20 | echo.installed, then set the SPHINXBUILD environment variable to point 21 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 22 | echo.may add the Sphinx directory to PATH. 23 | echo. 24 | echo.If you don't have Sphinx installed, grab it from 25 | echo.http://sphinx-doc.org/ 26 | exit /b 1 27 | ) 28 | 29 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% 30 | goto end 31 | 32 | :help 33 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% 34 | 35 | :end 36 | popd 37 | -------------------------------------------------------------------------------- /docs/zh_CN/performance/index.rst: -------------------------------------------------------------------------------- 1 | .. 性能调优 2 | FileName: index.rst 3 | Author: Fasion Chan 4 | Created: 2018-10-26 18:52:32 5 | @contact: fasionchan@gmail.com 6 | @version: $Id$ 7 | 8 | Description: 9 | 10 | Changelog: 11 | 12 | ======== 13 | 性能调优 14 | ======== 15 | 16 | .. toctree:: 17 | :titlesonly: 18 | 19 | Web压力测试 20 | 21 | 22 | .. comments 23 | comment something out below 24 | 25 | .. meta:: 26 | :description lang=zh: 27 | :keywords: 28 | 29 | -------------------------------------------------------------------------------- /docs/zh_CN/performance/web-pressure-test.rst: -------------------------------------------------------------------------------- 1 | .. Web压力测试 2 | FileName: web-pressure-test.rst 3 | Author: Fasion Chan 4 | Created: 2018-10-26 08:54:41 5 | @contact: fasionchan@gmail.com 6 | @version: $Id$ 7 | 8 | Description: 9 | 10 | Changelog: 11 | 12 | .. meta:: 13 | :description lang=zh: 14 | :keywords: web, pressure test, 压力测试 15 | 16 | =========== 17 | Web压力测试 18 | =========== 19 | 20 | .. comments 21 | comment something out below 22 | 23 | -------------------------------------------------------------------------------- /docs/zh_CN/practices/endianness.rst: -------------------------------------------------------------------------------- 1 | .. 字节序 2 | FileName: endianness.rst 3 | Author: Fasion Chan 4 | Created: 2019-01-20 10:52:10 5 | @contact: fasionchan@gmail.com 6 | @version: $Id$ 7 | 8 | Description: 9 | 10 | Changelog: 11 | 12 | .. meta:: 13 | :description lang=zh: 14 | 在大端系统,多字节数据类型起始字节先存储;相反,在小端系统,多字节数据类型末尾字节先存储。 15 | 如果无法人为确定当前系统字节序是大端还是小端,可以编写一个简单程序进行判断。 16 | htons,将短整数(两字节)从主机字节序转成网络字节序; 17 | htonl,将长整数(四字节)从主机字节序转成网络字节序; 18 | ntohs,将短整数(两字节)从网络字节序转成网络字节序; 19 | ntohl,将长整数(四字节)从网络字节序转成网络字节序。 20 | :keywords: endianness, big endian, little endian, 字节序, 大端小端, 网络字节序, htons, htonl, ntohs, ntohl 21 | 22 | ====== 23 | 字节序 24 | ====== 25 | 26 | **大端** ( *Big endian* ) 和 **小端** ( *Little Endian* )是计算机存储 **多字节** 数据的两种不同方式。 27 | 28 | 定义 29 | ==== 30 | 31 | 在 **大端** 系统,多字节数据类型 **起始字节先存储** ; 32 | 相反,在 **小端** 系统,多字节数据类型 **末尾字节先存储** 。 33 | 34 | 假设有一个 *4* 字节长整数变量 *y* ,值为 *0x01234567* (十六进制表示法) 。 35 | 在 **大端** 系统上,该变量保存为以下 *4* 个字节: *0x01* 、 *0x23* 、 *0x45* 、以及 *0x67* ; 36 | 在 **小端** 系统上,存储顺序刚好相反: 37 | 38 | .. figure:: /_images/practices/c/endianness/a993cff0c201d6645e72b88e38831dc0.png 39 | :width: 641px 40 | 41 | 辅助记忆 42 | ======== 43 | 44 | 记忆大端小端定义很容易搞混,通过以下图形可以更好地记住,非常形象: 45 | 46 | .. figure:: /_images/practices/c/endianness/e785ff930df62e39597e8b0b4409d50e.png 47 | 48 | 内存表现形式 49 | ============ 50 | 51 | 如果需要查看多字节数据类型在 **内存** 中的表现形式, 52 | 可以遍历数据每个字节,以 **十六进制** 将字节打印出来。 53 | 下面是一份示例代码: 54 | 55 | .. literalinclude:: /_src/c/endianness/show.c 56 | :caption: 57 | :name: src/c/show 58 | :language: c 59 | :lines: 13- 60 | :linenos: 61 | 62 | 字节序判断 63 | ========== 64 | 65 | 如果无法人为确定当前系统字节序是大端还是小端,可以编写一个简单程序进行判断: 66 | 67 | .. literalinclude:: /_src/c/endianness/endianness.c 68 | :caption: 69 | :name: src/c/endianness 70 | :language: c 71 | :lines: 13- 72 | :linenos: 73 | 74 | 原理很好理解,定义一个整数,值为 *1* ,然后判断其 **第一个字节** 的值。 75 | 76 | 网络字节序 77 | ========== 78 | 79 | 不同字节序系统进行网络通信,不加以注意是要乱套的。 80 | 81 | 为了解决这个问题,约定进行网络通信时统一采用 **大端** 字节序。 82 | 因此, **大端** 字节序也称为 **网络字节序** 。 83 | 84 | 封装网络报文时,需要在 **主机字节序** 和 **网络字节序** 之间转换。 85 | `C` 库提供了转换函数(宏): 86 | 87 | - `htons`_ ,将 **短整数** (两字节)从 **主机字节序** 转成 **网络字节序** ; 88 | - `htonl`_ ,将 **长整数** (四字节)从 **主机字节序** 转成 **网络字节序** ; 89 | - `ntohs`_ ,将 **短整数** (两字节)从 **网络字节序** 转成 **网络字节序** ; 90 | - `ntohl`_ ,将 **长整数** (四字节)从 **网络字节序** 转成 **网络字节序** ; 91 | 92 | 举个例子,在填充地址结构体端口字段时,需要通过 `htons`_ 进行转换: 93 | 94 | .. code-block:: c 95 | 96 | addr.sin_port = htons(80) 97 | 98 | 转换函数有 *4* 个之多,借助下表可以更好地记忆: 99 | 100 | .. csv-table:: 字节序转换助记 101 | :header: "字母", “含义” 102 | 103 | "h", "主机字节序" 104 | "n", "网络字节序" 105 | "s", "短整数(两字节)" 106 | "l", "长整数(四字节)" 107 | 108 | 优缺点 109 | ====== 110 | 111 | 这两种表示方式各有优缺点: 112 | 113 | 对于 **小端** 字节序,取不同长度整数的 **汇编指令** 处理方式相同:都是从第 *0* 字节开始。 114 | 此外,由于地址 **偏移量** 与 **字节** 的关系一一对应, **多精度** 数学例程很容易实现。 115 | 116 | 对于 **大端** 字节序,由于高位字节先存储,判断数字 **正负** 只需检查 **第一个字节** (偏移量为 *0* )。 117 | 因此,无需跳过一些字节以定位包含 **符号** 的字节,也无需知晓 **变量长度** 。 118 | 119 | 下一步 120 | ====== 121 | 122 | .. include:: /_fragments/next-step-to-wechat-mp.rst 123 | 124 | 参考文献 125 | ======== 126 | 127 | #. `Little Endian vs Big Endian `_ 128 | 129 | .. include:: /_fragments/wechat-reward.rst 130 | 131 | .. include:: /_fragments/disqus.rst 132 | 133 | .. _htons: http://man7.org/linux/man-pages/man3/htons.3.html 134 | .. _htonl: http://man7.org/linux/man-pages/man3/htonl.3.html 135 | .. _ntohs: http://man7.org/linux/man-pages/man3/ntohs.3.html 136 | .. _ntohl: http://man7.org/linux/man-pages/man3/ntohl.3.html 137 | 138 | .. comments 139 | comment something out below 140 | 141 | -------------------------------------------------------------------------------- /docs/zh_CN/practices/index.rst: -------------------------------------------------------------------------------- 1 | .. 编程实践 2 | FileName: index.rst 3 | Author: Fasion Chan 4 | Created: 2018-01-28 11:45:04 5 | @contact: fasionchan@gmail.com 6 | @version: $Id$ 7 | 8 | Description: 9 | 10 | Changelog: 11 | 12 | 编程实践 13 | ======== 14 | 15 | .. toctree:: 16 | :titlesonly: 17 | 18 | 字节序 19 | 网络IO模型 20 | 以太网编程实践(C语言) 21 | 以太网编程实践(Python语言) 22 | ICMP编程实践(C语言) 23 | ICMP编程实践(Python语言) 24 | 使用SMTP发送邮件(Python语言) 25 | 用Flask框架写RESTful API 26 | 用Go语言写RESTful API 27 | select、poll、epoll对比 28 | 29 | .. comments 30 | comment something out below 31 | -------------------------------------------------------------------------------- /docs/zh_CN/practices/send-email-by-smtp-py.rst: -------------------------------------------------------------------------------- 1 | .. 使用SMTP协议发送邮件(Python语言) 2 | FileName: send-email-by-smtp-py.rst 3 | Author: Fasion Chan 4 | Created: 2018-05-23 16:55:15 5 | @contact: fasionchan@gmail.com 6 | @version: $Id$ 7 | 8 | Description: 9 | 10 | Changelog: 11 | 12 | .. meta:: 13 | :keywords: smtp, smtplib, python, send email, 发送邮件 14 | 15 | ================================ 16 | 使用SMTP协议发送邮件(Python语言) 17 | ================================ 18 | 19 | smtplib 20 | ======= 21 | 22 | `Python` 标准库中, `smtplib `_ 模块提供 `SMTP` 协议发送接口,使用起来十分方便。 23 | 接下来,写一个用于发送邮件的函数,一睹为快: 24 | 25 | .. literalinclude:: /_src/python/smtp/send_email.py 26 | :caption: 27 | :name: python/smtp/send_email 28 | :language: python 29 | :lines: 21-64 30 | :linenos: 31 | 32 | 函数通过参数指定了发送一封邮件所需要的全部要素,依次是: 33 | 邮件服务器地址、端口、登录用户、登录密码、发送人邮箱(一般与登录用户相同)、收件人邮箱,邮件标题,邮件内容。 34 | 35 | 函数第 `21` 行先初始化一个连接对象。 36 | 注意到,类连接类通过 ``smtp_cls`` 参数化, 37 | 灵活支持不同连接类,如 ``smtp.SMTP`` 、 ``smtp.SMTP_SSL`` 等。 38 | 39 | 第 `24` 行用指定的地址端口连接邮件服务器。 40 | 紧接着,第 `25` 行用指定的用户密码进行登录。 41 | 至此,程序编写已经成功了一半。 42 | 43 | 第 `28` - `40` 行组装消息体,消息体包括:发件人,收件人,邮件标题,发送时间,邮件内容等要素。 44 | 消息体的格式如下: 45 | 46 | .. code-block:: text 47 | 48 | From: xxxx@qq.com 49 | To: yyyy@qq.com 50 | Subject: hello world 51 | Date: 23/5/2018 20:35 52 | 53 | first email sent by python 54 | 55 | 空行之后就是邮件内容,可以包括多行。 56 | 57 | 第 `43` 行将消息体发送到邮件服务器。这样,一封邮件就成功发送出去了,是不是很简单? 58 | 59 | SMTP服务器 60 | ========== 61 | 62 | 在调用 ``send_email`` 函数发送邮件前,需要获得邮件服务器的登录信息。 63 | 登录信息包括四要素,分别是:服务器地址,端口,登录用户以及登录密码。 64 | 65 | 很不幸,不同的邮件厂商,做法颇有不同。 66 | 下面以 `QQ邮箱 `_ 为例,介绍如何获得登录信息: 67 | 68 | 登录 `QQ邮箱 `_ ,点击 **设置** > **账号** , 69 | 找到 **POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV服务** , 70 | 按提示开启 `SMTP` 并取得授权码。 71 | 72 | .. figure:: /_images/practices/1c50f1e9f0bf98f7f495b14377869f71.png 73 | :width: 342px 74 | 75 | *授权码* 76 | 77 | 点击 `如何使用 Foxmail 等软件收发邮件? `_ , 78 | 指引里可以找到 `SMTP` 服务器地址以及端口信息: 79 | 80 | .. figure:: /_images/practices/75d2afbd89bb1516a5f6f12cfda33bad.png 81 | :width: 342px 82 | 83 | *地址端口* 84 | 85 | 至此,四要素集齐:服务器地址一般为 ``smtp.qq.com`` ,端口一般为 ``465`` , 86 | 登录用户就邮箱地址,密码就是授权码。 87 | 88 | .. warning:: 89 | 注意,SMTP服务器登录密码是生成的授权码,不是邮箱登录密码! 90 | 91 | 下一步 92 | ====== 93 | 94 | 小手动起来,使用 `Python` 发出你的第一封邮件吧! 95 | 96 | .. include:: /_fragments/next-step-to-wechat-mp.rst 97 | 98 | 参考文献 99 | ======== 100 | 101 | #. `smtplib — SMTP protocol client `_ 102 | 103 | .. include:: /_fragments/wechat-reward.rst 104 | 105 | .. include:: /_fragments/disqus.rst 106 | 107 | .. comments 108 | comment something out below 109 | 110 | -------------------------------------------------------------------------------- /docs/zh_CN/protocols/data-link-layer.rst: -------------------------------------------------------------------------------- 1 | .. 数据链路层 2 | FileName: data-link-layer.rst 3 | Author: Fasion Chan 4 | Created: 2018-01-28 11:45:04 5 | @contact: fasionchan@gmail.com 6 | @version: $Id$ 7 | 8 | Description: 9 | 10 | Changelog: 11 | 12 | .. meta:: 13 | :description lang=zh: 将两服务器通讯问题扩展到多服务器通讯问题,需要解决寻址以及复用/分用问题,这就是数据链路层的主要作用。 14 | :keywords: 数据链路层, 寻址, 复用, 分用 15 | 16 | .. _data-link-layer: 17 | 18 | ========== 19 | 数据链路层 20 | ========== 21 | 22 | .. note:: 23 | 为了简化接下来的讨论,我们站在物理层的基础上,所有数据发送省略控制比特 ``1010`` 和 ``0101`` 。 24 | 25 | 前一节讨论了一个理想化模型——两服务器通讯。 26 | 现在,我们把问题进一步拓展一下:多台机器如何实现两两通讯? 27 | 28 | 多服务器通讯问题 29 | ================ 30 | 31 | 下面,以三台服务器为例: 32 | 33 | .. figure:: /_images/protocols/data-link-layer/2191e6281e268396eaf4d18303ab9fb5.png 34 | 35 | *多服务器通讯模型:共用信道* 36 | 37 | 图中,有 ``3`` 台服务器,名字分别是: ``ant`` 、 ``bee`` 以及 ``cicada`` 。 38 | 为了通讯,我们设想三者均连接至一根共用导线,每台服务器都可以改变导线电平,也可以检测导线电平。 39 | 进一步假设,在硬件层面,多机器冲突仲裁机制已经实现并且可用。 40 | 这样,是否解决了多服务器通讯问题? 41 | 42 | .. _addressing: 43 | 44 | 寻址 45 | ==== 46 | 47 | 假设, ``ant`` 向 ``bee`` 发送(粗体)一个数据 ``11110000`` 。 48 | 由于导线是共享的,所有机器都可以检测到电平信号。 49 | 换句话讲, ``bee`` 和 ``cicada`` 都会收到这个数据 ``11110000`` ,而 ``cicada`` 本不应该接收这个数据! 50 | 另一方面, ``bee`` 收到数据后,也不知道数据到底是谁发送给它的。 51 | 52 | .. figure:: /_images/protocols/data-link-layer/129372fbd3cfab17acedd6632303680d.png 53 | 54 | *数据的困惑:我从哪来?要到哪去?* 55 | 56 | 因此,我们需要引入一些比特,用来标识数据的来源以及目的地。 57 | 我们的例子只有3台服务器,两个比特就足以唯一确定一台机器: 58 | 59 | .. csv-table:: 表格-1 60 | :header: "机器", "比特" 61 | 62 | "ant", "00" 63 | "bee", "01" 64 | "cicada", "10" 65 | 66 | 那么,发送数据时,额外加上两个比特用于表示来源机器,另外两个比特表示目标机器,问题不就解决了吗? 67 | 68 | .. figure:: /_images/protocols/data-link-layer/c40d1f04fd8f51b47cab3a2387d50bfa.png 69 | 70 | ``bee`` 收到数据后,检查前两个比特(红色),值为 ``00`` ,便知道是 ``ant`` 发出来的; 71 | 检查紧接着的两个比特(绿色),值为 ``01`` ,与自己匹配上,便愉快地收下了。 72 | 相反, ``cicada`` 收到数据后,发现 ``01`` 和自己 ``10`` 匹配不上,便丢弃这个数据。 73 | 74 | 新引入比特所起的作用,在计算机网络中称为 **寻址** 。 75 | 这两个比特也就称为 **地址** ,其中,红色为源地址,绿色为目的地址。 76 | 通过引入寻址,我们完美地解决了数据从哪来,到哪去的问题。 77 | 78 | .. _multiplexing-demultiplexing: 79 | 80 | 复用/分用 81 | ========= 82 | 83 | 信道只有一个,但是通讯需求是无穷无尽的——传输研究数值、文件打印、即时通讯,不一而足。 84 | 如何解决这个矛盾呢?套路还是一样的——引入新的比特。 85 | 86 | 假设,总的通讯需求就上面这3个,那么,2个额外的比特便解决了问题。 87 | 88 | .. csv-table:: 表格-2 89 | :header: "类型", "比特" 90 | 91 | "研究数据", "00" 92 | "文件打印", "01" 93 | "即时通讯", "10" 94 | 95 | 这时,假设 ``ant`` 向 ``bee`` 上报研究数据并打印一个文件: 96 | 97 | .. figure:: /_images/protocols/data-link-layer/9c11e1fe6649cd4d5fb31a0869cf6545.png 98 | 99 | *信道复用:使用额外比特区分数据类型* 100 | 101 | 这样,通过新引入的紫色比特,我们实现了在同个信道上进行不同的通讯! 102 | ``bee`` 接收到数据后,根据紫色比特,决定数据如何处理。 103 | 104 | 接下来,从理论的视角来审视这个场景: 105 | 106 | .. figure:: /_images/protocols/data-link-layer/967793342e62b831ef0ff7127a4b6537.png 107 | 108 | *复用信道* 109 | 110 | 信道只有一个,需要承载不同的通讯需求。 111 | 在发送端,通过加入紫色比特,将不同的数据通过一个共用信道发送出去,这个过程叫做 **复用** ( ``Multiplexing`` ); 112 | 在接收端,从共用信道上接收数据,然后检查紫色比特决定数据如何处理,这个过程叫做 **分用** ( ``Demultiplexing`` )。 113 | 在接下来的章节,我们将看到 ``复用`` - ``分用`` 这个概念贯彻计算机网络的始终。 114 | 115 | .. figure:: /_images/protocols/data-link-layer/72936c895af9726f87498ffbe292accd.png 116 | :width: 200px 117 | 118 | *复用/分用* 119 | 120 | 到目前为止,我们引入了 ``3`` 种不同的比特,分别是 **源地址** 、 **目的地址** 以及 **数据类型** 。 121 | 对于这些比特的位数以及含义的约定,便成为 **网络协议** 。 122 | 123 | 总结 124 | ==== 125 | 126 | 本节,我们解决了多台共用信道服务器间的通信问题,这相当于网络分层结构中的 **数据链路层** 。 127 | 数据链路层的主要作用包括: 128 | 129 | - :ref:`addressing` 130 | - :ref:`multiplexing-demultiplexing` 131 | 132 | 进度 133 | ==== 134 | 135 | .. figure:: /_images/protocols/data-link-layer/77c9104cf45312384fe61f198739136b.png 136 | 137 | *新技能Get✔️* 138 | 139 | 下一步 140 | ====== 141 | 142 | 下一节,我们开始学习一个真实的数据链路层协议—— :ref:`ethernet-protocol` 。 143 | 届时,我们将看到 :ref:`ethernet-protocol` 与本节虚构的协议别无二致。 144 | 145 | .. include:: /_fragments/next-step-to-wechat-mp.rst 146 | 147 | .. include:: /_fragments/wechat-reward.rst 148 | 149 | .. include:: /_fragments/disqus.rst 150 | 151 | .. comments 152 | comment something out below 153 | 154 | https://en.wikipedia.org/wiki/Medium_access_control 155 | 156 | 参考文献 157 | ======== 158 | -------------------------------------------------------------------------------- /docs/zh_CN/protocols/index.rst: -------------------------------------------------------------------------------- 1 | .. 网络协议 2 | FileName: index.rst 3 | Author: Fasion Chan 4 | Created: 2018-01-28 11:45:04 5 | @contact: fasionchan@gmail.com 6 | @version: $Id$ 7 | 8 | Description: 9 | 10 | Changelog: 11 | 12 | 网络协议 13 | ======== 14 | 15 | .. toctree:: 16 | :titlesonly: 17 | 18 | 物理层 19 | 数据链路层 20 | 以太网协议 21 | 以太网交换 22 | 网络层 23 | IP协议 24 | QUIC协议 25 | 26 | .. comments 27 | comment something out below 28 | 29 | -------------------------------------------------------------------------------- /docs/zh_CN/protocols/ip.rst: -------------------------------------------------------------------------------- 1 | .. IP协议 2 | FileName: ip.rst 3 | Author: Fasion Chan 4 | Created: 2019-02-17 11:09:15 5 | @contact: fasionchan@gmail.com 6 | @version: $Id$ 7 | 8 | Description: 9 | 10 | Changelog: 11 | 12 | .. meta:: 13 | :description lang=zh: 14 | 我们引入网络层,以实现全局寻址和数据路由需求,现在开始学习网络层协议——IP协议。 15 | IP报文头部包括:版本、首部长度、总长度、TTL、协议、检验和源地址、目的地址、可选选项等字段,结构如下。 16 | :keywords: ip, 协议, ip header, ip头部 17 | 18 | ====== 19 | IP协议 20 | ====== 21 | 22 | 我们引入 :doc:`network-layer` ,以实现 **全局寻址** 和 **数据路由** 需求,现在开始学习网络层协议—— `IP` 协议。 23 | 24 | IP报文 25 | ====== 26 | 27 | `IP` 报文结构如下图所示: 28 | 29 | .. figure:: /_images/protocols/ip/bed8aacc992dc152c1bf79ff7c5a9033.png 30 | 31 | 报文头部字段包括: 32 | 33 | - **版本** ( `version` ),用于标识 **协议版本** ,在协议发展迭代的同时保持高度可兼容性。 34 | 目前部署最成熟的是 `IPv4` , `IPv6` 则正快速发展中。 35 | - **首部长度** ( `internet header length` 或 `IHL` ),由于 `IP` 头部长度一定为 *4* 的整数倍, 36 | 这个字段以 *4* 字节为单位。典型的 `IP` 报文首部为 *20* 字节, *IHL=5* 。 37 | - **总长度** ( `total length` ),即 `IP` 报文总长度,字段长度为 *16* 位,因此 `IP` 报文最大长度为 :math:`2^{16} = 65535` 。 38 | - **源地址** ( `source address` ),据此接收方可以获悉发送源。 39 | - **目的地址** ( `destination address` ),中间节点据此转发报文。 40 | - **可选选项** ( `options` ),通过 **首部长度** 可以判断报文是否带可选选项。 41 | 42 | 下一步 43 | ====== 44 | 45 | .. toctree:: 46 | :titlesonly: 47 | 48 | 实验:Linux路由 49 | 50 | .. comments 51 | comment something out below 52 | 53 | -------------------------------------------------------------------------------- /docs/zh_CN/protocols/network-layer.rst: -------------------------------------------------------------------------------- 1 | .. 网络层 2 | FileName: network-layer.rst 3 | Author: Fasion Chan 4 | Created: 2018-04-05 10:12:26 5 | @contact: fasionchan@gmail.com 6 | @version: $Id$ 7 | 8 | Description: 9 | 10 | Changelog: 11 | 12 | .. meta:: 13 | :description lang=zh: 14 | 为解决数据链路层的局限性,需要引入新的一层——网络层以及新的地址——网络层地址。 15 | 网络层地址按网络拓扑分配,实现准确的全球寻址。 16 | 网络层转发设备,即路由器,根据路由表实现数据包精确转发。 17 | :keywords: 网络层, network layer, 广播风暴, 路由, 路由表 18 | 19 | ====== 20 | 网络层 21 | ====== 22 | 23 | :ref:`data-link-layer` 解决了多台共用信道计算机之间的通讯问题。 24 | 25 | 在这一层,每台计算机与 :ref:`ethernet-switcher` 或者 :ref:`ethernet-hub` 之类的设备连接,并用 :ref:`ethernet-protocol` 进行通信: 26 | 27 | .. figure:: /_images/protocols/network-layer/a6c0bc01c575cc19d29aca64a681ac72.png 28 | 29 | 以太网 30 | 31 | 数据链路层局限性 32 | ================ 33 | 34 | 随着接入的计算机不断增加,交换机一定遇到瓶颈。 35 | 试想,如果全世界的计算机都接入,需要造一台多大的交换机(或许就根本无法实现)! 36 | 37 | 聪明如你,通过多台交换机组网不就解决中心化问题了? 38 | 如下图,用一根网线将两台交换机连接起来: 39 | 40 | .. figure:: /_images/protocols/network-layer/a13531e70d79522933ce39e3294cdb25.png 41 | 42 | 多交换机组网 43 | 44 | 这样组网确实可以扩展以太网络的规模,但是远远达不到可以组建全球网络的水平。 45 | 46 | 瓶颈主要是以下几点: 47 | 48 | #. 广播风暴; 49 | #. 地址表规模(MAC地址分散性); 50 | 51 | 在 :doc:`ethernet-switching` 一节,我们知道 :doc:`data-link-layer` 转发设备(即 **交换机** )的工作原理。 52 | 交换机对于不认识的目的 `MAC` 地址,采取广播策略。 53 | 这意味着与陌生节点第一次通讯时,数据包需要 **广播到所有节点** 。 54 | 这便是 **广播风暴** ,网络规模越大,广播流量越恐怖。 55 | 56 | 为了保证地址的唯一性, `MAC` 地址按 **设备厂商** 划分并烧在网卡设备内。 57 | 某个组织内部使用的设备可能千差万别,因此没有办法对地址表进行合并。 58 | 合并要求地址是 **连续** 的,可形成 **地址段** 转发策略。 59 | 60 | 因此,我们需要在数据链路层的基础上,解决以上两大难题。 61 | 62 | .. _ip-routing: 63 | 64 | 网络层 65 | ====== 66 | 67 | 为了解决 :doc:`data-link-layer` 的局限性,需要引入新的一层,以及新的地址。 68 | 新的一层为 **网络层** ,新的地址就是 **网络层地址** 。 69 | 在网络层转发数据的中间节点,称为 **网络层路由** 。 70 | 网络层主要职责在于:实现 **全球寻址** 以及 **数据路由** 。 71 | 72 | 每台参与网络通讯的计算机分配一个唯一的地址,即 **网络层地址** 。 73 | 网络层地址按 **网络拓扑** 分配,保证组织内部的地址是连续的。 74 | 例如,给某个公司分配地址 `123.58.173.x` ,只有最后一个数字是不同的。 75 | 这样,一条转发配置便可为几百个地址服务。相应地,地址表规模也可下降若干数量级。 76 | 77 | 参考 :doc:`./data-link-layer` ,定义网络层的数据包结构,包含 **地址** 、 **数据** 以及 **类型** 等信息。 78 | **网络层包** 承载在 **数据链路层包** 之上,换句话讲,数据链路层包 **数据负载** 就是一个 **网络层包** 。 79 | 80 | **网络层路由** 存有 **路由表** ,规定了目的地址与与下一跳的对应关系。 81 | **路由表** 看起来与数据链路层 `MAC地址表` 颇为类似,但更加高级: 82 | 83 | 1. 支持 **地址段** 。一条记录配置某个区间地址的下一跳,有效降低路由表规模。 84 | 2. 支持 **高级学习算法** 。例如选择一条跳数最少的路径。 85 | 86 | 路由接到 **网络层包** 之后,以 **目的地址** 检索路由表决定如何发给下一跳: 87 | 88 | 89 | .. figure:: /_images/protocols/network-layer/da4c3f29e3c36011339479ddee156a71.png 90 | 91 | 数据包路由 92 | 93 | 中间路由接力转发,直到数据包到达目的地。 94 | 如果路由表找不到下一跳,路由不会广播数据包,而是悄悄丢弃,避免广播风暴。 95 | 96 | 总结 97 | ==== 98 | 99 | 本节,我们分析了 :doc:`data-link-layer` 以及 :doc:`ethernet` 的局限性。 100 | **广播风暴** 以及 `MAC` 地址表 **分散性** 严重制约了依赖以太网组建全球网络的可能性。 101 | 102 | 因此,需要引入新的一层—— **网络层** ,以实现 **全球寻址** 以及 高效的 **数据路由** 。 103 | 104 | 进度 105 | ==== 106 | 107 | .. figure:: /_images/protocols/network-layer/43f85526b7f730866cb087574696dd46.png 108 | 109 | *新技能Get✔️* 110 | 111 | 下一步 112 | ====== 113 | 114 | .. include:: /_fragments/next-step-to-wechat-mp.rst 115 | 116 | .. include:: /_fragments/wechat-reward.rst 117 | 118 | .. include:: /_fragments/disqus.rst 119 | 120 | .. comments 121 | comment something out below 122 | 123 | 124 | 图中四台机器 :ref:`mac-address` 如下表: 125 | 126 | .. csv-table:: 表格-1 MAC地址 127 | :header: "机器", "MAC地址" 128 | 129 | "左上", "MAC1" 130 | "左下", "MAC2" 131 | "右上", "MAC3" 132 | "右下", "MAC4" 133 | 134 | 交换机端口连接关系如下表: 135 | 136 | .. csv-table:: 表格-2 交换机端口连接 137 | :header: "交换机", "端口", "连接对象" 138 | 139 | "Switch 1", "1", "左上" 140 | "Switch 1", "2", "左下" 141 | "Switch 1", "3", "Switch 2" 142 | "Switch 2", "1", "右上" 143 | "Switch 2", "2", "右下" 144 | "Switch 2", "3", "Switch 1" 145 | 146 | 通过 :ref:`mac-address-auto-learning` ,两台交换机最终得到地址表如下: 147 | 148 | .. csv-table:: 表格-2 交换机端口连接 149 | :header: "交换机", "端口", "地址" 150 | 151 | "Switch 1", "1", "MAC1" 152 | "Switch 1", "2", "MAC2" 153 | "Switch 1", "3", "MAC3 MAC4" 154 | "Switch 2", "1", "MAC3" 155 | "Switch 2", "2", "MAC4" 156 | "Switch 2", "3", "MAC1 MAC2" 157 | 158 | 造成 **广播风暴** 的根源是 **地址学习** 策略的局限性。 159 | 如果转发配置可以在流量产生前做好,k 160 | -------------------------------------------------------------------------------- /docs/zh_CN/protocols/physical-layer.rst: -------------------------------------------------------------------------------- 1 | .. 物理层 2 | FileName: physical-layer.rst 3 | Author: Fasion Chan 4 | Created: 2018-01-28 11:45:04 5 | @contact: fasionchan@gmail.com 6 | @version: $Id$ 7 | 8 | Description: 9 | 10 | Changelog: 11 | 12 | .. meta:: 13 | :description lang=zh: 通过两服务器通讯问题引入物理层的讨论,物理层主要承担比特流传输的职责。 14 | :keywords: 物理层 15 | 16 | .. _physical-layer: 17 | 18 | ====== 19 | 物理层 20 | ====== 21 | 22 | 我们以一个非常简单的例子开始: 23 | 24 | 两服务器通讯问题 25 | ================ 26 | 27 | .. figure:: /_images/protocols/physical-layer/3fed1fb3ce11f3e73c606d99dd37272c.png 28 | 29 | *两服务器通讯问题* 30 | 31 | 如上图,有两台服务器,分别是 ``Server 1`` 和 ``Server 2`` 。 32 | 我们先做一个假设:计算机网络现在还没有被发明出来, 33 | 作为计算机科学家的你,想在这两台服务器间传递数据,怎么办? 34 | 35 | 这时,你可能会想到,用一根电缆把两台服务器连接起来: 36 | 37 | .. figure:: /_images/protocols/physical-layer/6bb1c239ba0f6fa29d1dbee74b5d4448.png 38 | 39 | *通过电缆实现通讯* 40 | 41 | 物理课大家都学过,电线可以分为 **低电平** 和 **高电平** 。 42 | 电平可以高低变化,这样不就可以传递信息了么: 43 | ``Server 1`` 控制电缆电平的高低, ``Server 2`` 检测电平的高低,这样就实现了 ``Server 1`` 往 ``Server 2`` 发送数据啦! 44 | 45 | 更进一步,可以将高低电平抽象成数学语言:我们用低电平表示 ``0`` ,高电平表示 ``1`` ,这样就得到一个理想化的信道: 46 | 47 | .. figure:: /_images/protocols/physical-layer/372a633a4d70a5044455623ad0f56a91.png 48 | 49 | *理想化信道* 50 | 51 | 通过信道,双方可以传递一些 ``01`` 比特流。 52 | 例子中,我们传输的比特流是 ``1111010101...`` (从右往左看)。 53 | 比特流可以编码任意信息: 54 | 比如,我们用 ``1111`` 表示告诉对方本地开机了,用 ``0000`` 告诉对方本地准备关机了。 55 | 56 | 到目前为止,我们是不是万事具备了呢? 57 | 一个比特流信道成为现实?——理论上是这样子的。 58 | 但是,现实世界往往要比理想化的模型复杂一些。 59 | 60 | 发送控制 61 | ======== 62 | 63 | .. figure:: /_images/protocols/physical-layer/8a17cc71d646cc1ef651f8979a1a7fa7.png 64 | 65 | *信道无穷无尽* 66 | 67 | 首先,如上图,信道是无穷无尽的。 68 | 因为,信道状态要么为 ``0`` ,要么为 ``1`` ,没有一种表示空闲的特殊状态。 69 | 70 | .. figure:: /_images/protocols/physical-layer/d2096209ec8b549234642b9e21219d00.png 71 | 72 | *结尾在哪?* 73 | 74 | 举个例子,如上图, ``Server 1`` 向 ``Server 2`` 发送比特序列 ``101101001101`` (从右往左读)。 75 | 最后一个比特是 ``1`` ,对应的电平是高电平。 76 | 发送完毕后,由于没有没有其他地方改变电缆的电平,所以还是维持高电平状态。 77 | 也就是说,信道看起来还是按照既定节拍,源源不断地发送 ``1`` (灰色部分), ``Server 2`` 怎么检测结尾在哪里? 78 | 79 | 我们可以定义一些特殊的比特序列,用于定义开头结尾: ``101010`` 表示开头, ``010101`` 表示结尾。 80 | 81 | .. figure:: /_images/protocols/physical-layer/7e77f008253e632cce8dd8e27e160908.png 82 | 83 | *引入控制比特* 84 | 85 | 这时, ``Server 1`` 先发送 ``101010`` (红色),告诉 ``Server 2`` 我要开始发数据了; 86 | 然后, ``Server 1`` 开始发送数据 ``1101011`` (黑色部分); 87 | 最后, ``Server 1`` 发送 ``010101`` (绿色),告诉 ``Server 2`` 数据发送完毕。 88 | 注意到,平时信道为 ``1`` (灰色),也就是代表空闲状态。 89 | 90 | 冲突仲裁 91 | ======== 92 | 93 | 如果两台服务器同时往信道里发送数据,会发生什么事情呢? 94 | 95 | .. figure:: /_images/protocols/physical-layer/6626019fc6bba63931bc654ccef8d04f.png 96 | 97 | *发送冲突:两台服务器同时发送数据* 98 | 99 | 肯定冲突了嘛!一台发 ``0`` ,一台发 ``1`` ,那你说信道到底是 ``0`` 还是 ``1`` ? 100 | 那么,冲突要怎么解决呢? 101 | 102 | 解决方式也简单,只需在硬件层面实现一种机制:在检测到两台服务器同时发送数据时,及时喊停,并协商到底由哪一方先发。 103 | 104 | 总结 105 | ==== 106 | 107 | 本节讨论了一个最简单的模型,解决两台服务器之间的通讯问题。 108 | 通过电缆,在两台机器间建立了一个理想的比特流传输信道。 109 | 这其实就是网络分层结构中最底层——物理层的作用: 110 | 111 | - 传输比特流 112 | - 依赖物理(电气)特性 113 | 114 | 这一层对开发人员来说,基本上是透明的,我们只需将其理解成一个比特流传输信道即可。 115 | 至于细节问题,高低电平啦,信号啦,各种物理特性啦,通通留给电子工程师去关心好啦! 116 | 117 | 进度 118 | ==== 119 | 120 | .. figure:: /_images/protocols/physical-layer/55477e2f396cb3ed5769a228d98e29db.png 121 | 122 | *新技能Get✔️* 123 | 124 | 下一步 125 | ====== 126 | 127 | 下一节,我们将通过 **多服务器通讯问题** 进入 :ref:`data-link-layer` 的学习。 128 | 129 | .. include:: /_fragments/next-step-to-wechat-mp.rst 130 | 131 | .. include:: /_fragments/wechat-reward.rst 132 | 133 | .. include:: /_fragments/disqus.rst 134 | 135 | .. comments 136 | comment something out blow 137 | 138 | 参考文献 139 | ======== 140 | -------------------------------------------------------------------------------- /docs/zh_CN/protocols/quic.rst: -------------------------------------------------------------------------------- 1 | .. 2 | Author: fasion 3 | Created time: 2019-09-23 09:51:51 4 | Last Modified by: fasion 5 | Last Modified time: 2020-02-08 15:48:39 6 | 7 | .. meta:: 8 | :keywords: quic, tcp, google, quick udp internet connections 9 | 10 | ==== 11 | QUIC 12 | ==== 13 | 14 | `QUIC`_ ,即 **快速UDP网络连接** ( *Quick UDP Internet Connections* ), 15 | 是由 `Google` 提出的 **实验性网络传输协议** ,位于 `OSI` 模型传输层。 16 | `QUIC` 旨在解决 `TCP` 协议的缺陷,并最终替代 `TCP` 协议, 17 | 以减少数据传输,降低连接建立延迟时间,加快网页传输速度。 18 | 19 | `QUIC` 主要特点有: 20 | 21 | - 多流设计; 22 | - 低等待延迟; 23 | - 加密性能更优; 24 | - 前向纠错; 25 | - 应用程序实现; 26 | - 连接保持; 27 | 28 | 多流设计 29 | ======== 30 | 31 | 采用 **多路复用** 思想,一个连接可以同时承载多个 **流** ( `stream` ),同时发起多个请求。 32 | 请求间完全 **独立** ,某个请求阻塞甚至报文出错均不影响其他请求。 33 | 34 | 对比 `HTTP` 长连接,由于 `TCP` 是只实现一个字节流,如果请求阻塞,新请求无法发起。 35 | 36 | 低等待延迟 37 | ========== 38 | 39 | 先考察典型的 `TLS` 连接建立过程: 40 | 41 | .. figure:: /_images/protocols/quic/b6c3265b63fd50ce949c3df89a6326d2.png 42 | 43 | 1. 首先,执行三次握手,建立 `TCP` 连接(蓝色部分); 44 | 2. 然后,执行 `TLS` 握手,建立 `TLS` 连接(黄色部分); 45 | 3. 此后开始传输业务数据; 46 | 47 | 客户端和服务器之间要进行好几轮协议交互,才能建立 `TLS` 连接,延迟相当严重。 48 | 平时访问 `https` 网站明显比 `http` 网站慢,三次握手和 `TLS` 握手难辞其咎。 49 | 50 | .. note:: 51 | 52 | 注意到,三次握手中的 `ACK` 包与 `ClientHello` 合并在一起发送。 53 | 这是 `TCP` 实现中使用的 **延迟确认** 技术,旨在减少协议开销,改善网络性能。 54 | 55 | 那么,能不能将 `TCP` 三次握手和 `TLS` 合并起来呢? 56 | 如果客户端在发送 `SYN` 包的同时将 `ClientHello` 一起发给服务端; 57 | 服务端响应 `SYN/ACK` 包时也带上相关 `TLS` 握手包,那么将可以节省一起往返时间! 58 | 59 | 这便是 `QUIC` 降低延迟的思路,但在 `SYN` 集成其他协议控制信息已然不可能。 60 | 因此, `QUIC` 采用基于 `UDP` 协议之上,在应用程序内实现传输控制协议的方案。 61 | 62 | .. figure:: /_images/protocols/quic/a1d7e443d6b493c707e5261876d31f2d.png 63 | 64 | 加密性能更优 65 | ============ 66 | 67 | 新的安全机制比 `TLS` 性能更好,而且具有各种攻击防御策略。 68 | 69 | 前向纠错 70 | ======== 71 | 72 | `TCP` 采用 **重传** 机制,而 `QUIC` 采用 **纠错** 机制。 73 | 74 | `TCP` 发生丢包时,需要一个等待延时判断发生了丢包,然后再启动重传机制,这个过程会造成一定的阻塞,影响传输时间。 75 | 76 | 而 `QUIC` 则采用一种更主动的方案,有点类似 `RAID5` ,每 `n` 个包额外发一个 **校验和包** 。 77 | 如果这 `n` 个包中丢了一个包,可以通过其他包和校验和恢复出来,完全不需要重传。 78 | 79 | 应用程序内实现 80 | ============== 81 | 82 | `QUIC` 直接基于 **客户端** (应用进程)实现,而非基于内核,可以快速迭代更新,不需要操作系统层面的改造,部署灵活。 83 | 这也是不使用基于迭代升级 `TCP` 方案的原因—— 84 | `TCP` 在操作系统内核中实现,很难进行大规模调整以及推广。 85 | 86 | 连接保持 87 | ======== 88 | 89 | `QUIC` 在客户端保存连接标识,当客户端 `IP` 或者端口发生变化时,可以快速恢复连接—— 90 | 客户端以标识请求服务端,服务端验证标识后感知客户端新地址端口并重新关联,继续通讯。 91 | 这对于改善移动端应用连接体验意义重大(从 `WiFi` 切换到流量)。 92 | 93 | 下一步 94 | ====== 95 | 96 | .. include:: /_fragments/next-step-to-wechat-mp.rst 97 | 98 | .. include:: /_fragments/wechat-reward.rst 99 | 100 | .. include:: /_fragments/disqus.rst 101 | 102 | .. comments 103 | comment something out blow 104 | 105 | .. _QUIC: https://en.wikipedia.org/wiki/QUIC 106 | -------------------------------------------------------------------------------- /docs/zh_CN/scripts/auto-build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # FileName: auto-build.sh 3 | # Author: Fasion Chan 4 | # @contact: fasionchan@gmail.com 5 | # @version: $Id$ 6 | # 7 | # Description: 8 | # 9 | # Changelog: 10 | # 11 | # 12 | 13 | SELF_PATH=`realpath "$0"` 14 | SCRIPT_DIR_PATH=`dirname "$SELF_PATH"` 15 | DOC_ROOT_PATH=`dirname "$SCRIPT_DIR_PATH"` 16 | PYENV_PATH="$DOC_ROOT_PATH/opt/pyenv" 17 | BUILD_PATH="$DOC_ROOT_PATH/_build" 18 | 19 | BIND_ADDR=lnp.local 20 | sudo ifconfig lo0 alias $BIND_ADDR up 21 | 22 | rm -rf "$BUILD_PATH" 23 | ( 24 | cd "$DOC_ROOT_PATH" 25 | PATH="$PYENV_PATH/bin:$PATH" "$PYENV_PATH/bin/sphinx-autobuild" -H $BIND_ADDR -p 58000 . "$BUILD_PATH/html" 26 | ) 27 | -------------------------------------------------------------------------------- /docs/zh_CN/scripts/build-deploy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Author: fasion 4 | # Created time: 2019-11-04 09:34:59 5 | # Last Modified by: fasion 6 | # Last Modified time: 2019-11-05 08:19:42 7 | 8 | SELF_PATH=`realpath "$0"` 9 | SCRIPT_DIR_PATH=`dirname "$SELF_PATH"` 10 | DOC_ROOT_PATH=`dirname "$SCRIPT_DIR_PATH"` 11 | DOCS_PATH=`dirname "$DOC_ROOT_PATH"` 12 | REPO_PATH=`dirname "$DOCS_PATH"` 13 | VAR_PATH="$DOC_ROOT_PATH/var" 14 | CLONE_PATH="$VAR_PATH/clone" 15 | 16 | if [ -e "$CLONE_PATH" ]; then 17 | read -p "delete clone repo $CLONE_PATH (y or n)? " value 18 | if [ "$value" == "y" ]; then 19 | rm -rf "$CLONE_PATH" 20 | else 21 | exit 1 22 | fi 23 | fi 24 | 25 | git clone $REPO_PATH $CLONE_PATH 26 | 27 | ( 28 | cd "$CLONE_PATH" && \ 29 | "$CLONE_PATH/docs/zh_CN/scripts/setup.sh" && \ 30 | "$CLONE_PATH/docs/zh_CN/scripts/build.sh" && \ 31 | ossutil -e oss-cn-shanghai.aliyuncs.com cp -f -r "$CLONE_PATH/docs/zh_CN/_build/html" oss://works-network/zh_CN/latest 32 | ) 33 | -------------------------------------------------------------------------------- /docs/zh_CN/scripts/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Author: fasion 4 | # Created time: 2019-11-04 08:38:35 5 | # Last Modified by: fasion 6 | # Last Modified time: 2019-11-04 08:44:15 7 | 8 | SELF_PATH=`realpath "$0"` 9 | SCRIPT_DIR_PATH=`dirname "$SELF_PATH"` 10 | DOC_ROOT_PATH=`dirname "$SCRIPT_DIR_PATH"` 11 | DOCS_PATH=`dirname "$DOC_ROOT_PATH"` 12 | REPO_PATH=`dirname "$DOCS_PATH"` 13 | PYENV_PATH="$DOC_ROOT_PATH/opt/pyenv" 14 | PIP_PATH="$PYENV_PATH/bin/pip" 15 | REAL_PYENV_PATH="$HOME/opt/pythons/pyenv.sphinx" 16 | PYENV_BIN_PATH="$PYENV_PATH/bin" 17 | 18 | ( 19 | cd "$DOC_ROOT_PATH" 20 | PATH="$PATH:$PYENV_BIN_PATH" make html 21 | ) 22 | -------------------------------------------------------------------------------- /docs/zh_CN/scripts/setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # FileName: setup.sh 3 | # Author: Fasion Chan 4 | # @contact: fasionchan@gmail.com 5 | # @version: $Id$ 6 | # 7 | # Description: 8 | # 9 | # Changelog: 10 | # 11 | # 12 | 13 | SELF_PATH=`realpath "$0"` 14 | SCRIPT_DIR_PATH=`dirname "$SELF_PATH"` 15 | DOC_ROOT_PATH=`dirname "$SCRIPT_DIR_PATH"` 16 | DOCS_PATH=`dirname "$DOC_ROOT_PATH"` 17 | REPO_PATH=`dirname "$DOCS_PATH"` 18 | PYENV_PATH="$DOC_ROOT_PATH/opt/pyenv" 19 | PIP_PATH="$PYENV_PATH/bin/pip" 20 | REAL_PYENV_PATH="$HOME/opt/pythons/pyenv.sphinx" 21 | 22 | if [ ! -e "$REAL_PYENV_PATH" ]; then 23 | mkdir -p "$REAL_PYENV_PATH" 24 | virtualenv -p python3 "$REAL_PYENV_PATH" 25 | fi 26 | 27 | if [ ! -e "$PYENV_PATH" ]; then 28 | mkdir -p `dirname "$PYENV_PATH"` 29 | ln -s "$REAL_PYENV_PATH" "$PYENV_PATH" 30 | fi 31 | 32 | "$PIP_PATH" install -r "$REPO_PATH/requirements/docs.txt" 33 | "$PIP_PATH" install -r "$REPO_PATH/requirements/docs-dev.txt" 34 | -------------------------------------------------------------------------------- /docs/zh_CN/security/index.rst: -------------------------------------------------------------------------------- 1 | .. 2 | Author: fasion 3 | Created time: 2020-03-17 17:00:25 4 | Last Modified by: fasion 5 | Last Modified time: 2020-03-18 09:36:17 6 | 7 | ======== 8 | 信息安全 9 | ======== 10 | 11 | .. toctree:: 12 | :titlesonly: 13 | 14 | 浅谈对称加密与非对称加密 15 | -------------------------------------------------------------------------------- /docs/zh_CN/security/symmetric-asymmetric-encryption.rst: -------------------------------------------------------------------------------- 1 | .. 2 | Author: fasion 3 | Created time: 2020-03-17 17:03:06 4 | Last Modified by: fasion 5 | Last Modified time: 2020-03-18 16:00:18 6 | 7 | .. meta:: 8 | :description lang=zh: 9 | :keywords: 对称加密, 非对称加密, AES, RSA, symmetric encryption, asymmetric encryption 10 | 11 | ======================== 12 | 浅谈对称加密与非对称加密 13 | ======================== 14 | 15 | 作为信息安全领域的基石,数据加密算法你或多或少应该用过。 16 | 可你知道数据加密分成 **对称加密** ( *symmetric encryption* ) 和 **非对称加密** ( *asymmetric encryption* ) 两种吗? 17 | 对称加密与非对称加密有什么区别?各自适用于什么场景? 18 | 19 | 对称加密 20 | ======== 21 | 22 | 在对称加密中,我们需要维护一个 **密钥** ( *secret key* )。 23 | 数据加密者根据加密算法用 **密钥** 对 **明文** 进行加密,得到不可读懂的 **密文** 。 24 | 数据解密者根据加密算法,用同样的 **密钥** 对密文进行解密,得到原来的明文。 25 | 26 | .. figure:: /_images/security/symmetric-asymmetric/0fc9c1c151e9b0ea164b3244d0a4bdac.png 27 | 28 | 如上图,在加密和解密的过程中,我们用到了同一个的 **密钥** ,这样就是 **对称加密算法** 中对称一词的由来。 29 | 那么,对称加密算法都有哪些呢?各自有什么特点呢? 30 | 31 | - *AES* ,高级加密标准,新一代加密算法标准,速度快,安全级别高; 32 | - *DES* ,数据加密标准,速度较快,适用于加密大量数据,但安全性较弱; 33 | - *Blowfish* ,使用变长密钥,运行速度很快,非专利算法,没有使用限制; 34 | - *etc* 35 | 36 | .. csv-table:: 表-1 对称加密算法安全级别 37 | :header: "安全级别 ( *Security Level* )", "工作因素 ( *Work Factor* )", "算法 ( *Algorithm* )" 38 | :widths: 36, 34, 30 39 | 40 | "薄弱 ( *Weak* )", ":math:`O(2^{40})`", "DES" 41 | "传统 ( *Legacy* )", ":math:`O(2^{64})`", "RC4" 42 | "基准 ( *Baseline* )", ":math:`O(2^{80})`", "3DES" 43 | "标准 ( *Standard* )", ":math:`O(2^{128})`", "AES-128" 44 | "较高 ( *High* )", ":math:`O(2^{192})`", "AES-192" 45 | "超高 ( *Ultra* )", ":math:`O(2^{256})`", "AES-256" 46 | 47 | 根据安全性,对称加密算法应该优先选择 *AES* ,位数尽可能大,例如 *AES-256* 。 48 | 49 | 由于所有参与者共享密钥,只要一人造成泄露便万劫不复,这是对称加密最大的弱点。 50 | 因此,对称加密密钥分发、保管必须严格控制,以免泄露。 51 | 52 | 非对称加密 53 | ========== 54 | 55 | 为解决对称加密共享密钥引发的问题,计算机科学家发明了一种更神奇的加密方式。 56 | 这种加密方式需要两个密钥,一个是 **公钥** ( *public key* )、一个是 **私钥** ( *private key* )。 57 | 私钥由自己保管,不能泄露;公钥分发给任何需要与自己通讯的参与者,无须保密。 58 | 59 | 数据加密者根据加密算法,用公钥对明文进行加密,得到不可读懂的密文。 60 | 数据解密者根据加密算法,用私钥对密文进行解密,得到原来的明文。 61 | 62 | .. figure:: /_images/security/symmetric-asymmetric/80ad9b50cce03bf499b54fc0456a33e3.jpg 63 | 64 | 由于加密环节和解密环节所用的密钥不同,因此这种加密方式也称为 **非对称加密** ( *asymmetric encryption* )。 65 | 由于公钥可以对外公开,也就不用刻意保护了。 66 | 67 | 此外,如果数据用私钥进行加密,那么只有用公钥才能解密。 68 | 由于公钥是公开的,这种机制一般不用于加密数据,而用于对数据进行 **签名** 。 69 | 70 | 那么,非对称加密有哪些典型的应用场景呢?接下来,我们以一个虚构故事展开讨论: 71 | 72 | *Alice* 是一位帮会大佬,手下有许多小弟, *Bob* 是其中一位。 73 | 小弟们在外行动,定期汇报成果,接受指令。 74 | 为保证通讯安全, *Alice* 通过非对称加密算法,打造了一对密钥: 75 | 76 | .. figure:: /_images/security/symmetric-asymmetric/6d1c5facbb0c313428c23e0ec173ac94.png 77 | :width: 300px 78 | 79 | *Alice* 小心翼翼地保管着私钥,并把公钥分发给 *Bob* 等小弟们。 80 | 81 | 数据加密 82 | -------- 83 | 84 | 小弟 *Bob* 需要向 *Alice* 汇报工作, *Alice* 不希望汇报内容被第三方获悉,包括其他小弟。 85 | 这时, *Bob* 用 *Alice* 给的公钥对汇报数据进行加密,再差人送给 *Alice* 。 86 | *Alice* 收到 *Bob* 送来的数据后,用自己手中的私钥一解,就知道 *Bob* 说啥了。 87 | 88 | .. figure:: /_images/security/symmetric-asymmetric/2b448b9c7af85c164f8124ba77e826bf.png 89 | 90 | 由于用公钥加密的数据只有私钥能解,而私钥只有 *Alice* 有,因此汇报内容不可能被第三方知晓。 91 | 换句话讲,只要私钥不泄露,加密数据便不会被其他人获悉。 92 | 93 | 数据签名 94 | -------- 95 | 96 | *Alice* 给 *Bob* 下达行动指令,内容虽然可以公开,但 *Alice* 必须防止不法之徒伪造指令。 97 | 98 | 为此, *Alice* 先借助类似 *MD5* 或 *SHA* 的哈希算法,为指令文本计算 **摘要** 。 99 | 同样的文本生成的摘要一定相同;不同的文本,哪怕只差一个字母,生成的摘要一定不同。 100 | 101 | 接着,*Alice* 用私钥对摘要进行加密,并将加密结果作为 **签名** 与指令一起发给 *Bob* 。 102 | 103 | .. figure:: /_images/security/symmetric-asymmetric/f944fcc9e487f4ded786d568ef2e6d86.png 104 | 105 | *Bob* 接到指令后,用公钥对签名进行解密,得到 *Alice* 生成的摘要。 106 | 然后,他用同样的算法,重新为指令文本计算摘要。 107 | 如果两个摘要吻合,便可确定指令是 *Alice* 下达的。 108 | 109 | 其他别有用心的第三方,或许已经掌握了摘要计算方法,但苦于缺少私钥,也就没有办法伪装成 *Alice* ,向 *Bob* 下达指令了。 110 | 111 | 这就是非对称加密的另一个典型使用场景—— **数据签名** ,可归纳为两步: 112 | 113 | #. 用私钥对数据进行签名; 114 | #. 用公钥对数据进行验证; 115 | 116 | 附录 117 | ==== 118 | 119 | .. include:: /_fragments/next-step-to-wechat-mp.rst 120 | 121 | .. include:: /_fragments/wechat-reward.rst 122 | 123 | .. include:: /_fragments/disqus.rst 124 | -------------------------------------------------------------------------------- /docs/zh_CN/services/consul/index.rst: -------------------------------------------------------------------------------- 1 | .. Consul 2 | FileName: index.rst 3 | Author: Fasion Chan 4 | Created: 2019-01-20 20:20:48 5 | @contact: fasionchan@gmail.com 6 | @version: $Id$ 7 | 8 | Description: 9 | 10 | Changelog: 11 | 12 | ====== 13 | Consul 14 | ====== 15 | 16 | .. toctree:: 17 | :titlesonly: 18 | 19 | 快速开始 20 | 21 | .. comments 22 | comment something out blow 23 | 24 | -------------------------------------------------------------------------------- /docs/zh_CN/services/consul/quick-start/checks.rst: -------------------------------------------------------------------------------- 1 | .. 健康检查 2 | FileName: checks.rst 3 | Author: Fasion Chan 4 | Created: 2019-01-22 20:22:18 5 | @contact: fasionchan@gmail.com 6 | @version: $Id$ 7 | 8 | Description: 9 | 10 | Changelog: 11 | 12 | .. meta:: 13 | :description lang=zh: 14 | 本节,我们进一步为节点和服务添加检查检查(healthcheck)。 15 | 健康检查是服务发现(servicediscovery)的重要组成部分,可避免访问不健康的服务实例。 16 | :keywords: consul, health check, 健康检查 17 | 18 | ======== 19 | 健康检查 20 | ======== 21 | 22 | 前面我们将 `Consul`_ 跑起来,添加 **节点** ( `node` )和 **服务** ( `service` ), 23 | 并通过接口 **查询** 服务信息,差不多都是小菜一碟。 24 | 25 | 本节,我们进一步为 **节点** 和 **服务** 添加 **检查检查** ( `health check` )。 26 | **健康检查** 是 **服务发现** ( `service discovery` )的重要组成部分,可避免访问不健康的服务实例。 27 | 28 | 我们在 :doc:`上节 ` 搭建的集群基础上进行试验,这是一个双节点集群。 29 | 30 | 定义检查 31 | ======== 32 | 33 | 与 :doc:`服务 ` 类似,健康检查可通过 **配置文件** 或 `HTTP` 接口调用进行注册。 34 | 35 | 这里我们还是采用配置文件的方式,因为跟服务配置一样,这种方式 **最常用** 。 36 | 37 | `Consul`_ *0.9.0* 以后, **代理** ( `agent` )需要将 ``enable_script_checks`` 配置设置为 ``true`` , 38 | 以开启脚本检查。 39 | 40 | 在第二个节点 `Consul`_ 配置目录下创建两个配置文件: 41 | 42 | .. code-block:: shell-session 43 | 44 | vagrant@n2:~$ echo '{"check": {"name": "ping", \ 45 | "args": ["ping", "-c1", "baidu.com"], "interval": "30s"}}' \ 46 | >/etc/consul.d/ping.json 47 | 48 | .. code-block:: shell-session 49 | 50 | vagrant@n2:~$ echo '{"service": {"name": "web", "tags": ["rails"], \ 51 | "port": 80, "check": {"args": ["curl", "localhost"], \ 52 | "interval": "10s"}}}' >/etc/consul.d/web.json 53 | 54 | 第一个配置 ``ping`` 是 **节点检查** ( `host-level check` ), 55 | 每隔 *30* 秒调用 ``ping -c1 baidu.com`` 一次。 56 | **脚本式** ( `script-based` )检查执行用户与启动 `Consul` 的用户一致。 57 | 如果命令返回值大于 **2** ,则认为检查 **失败** ,对应的服务也是 **不健康** 的。 58 | 如果返回值是 **1** ,则认为服务处于 **预警** ( `warning` )状态。 59 | 这个约定对于所有 **脚本式** 检查均适用。 60 | 61 | 第二个配置在 ``web`` 服务基础上,为其添加检查定义,每隔 *10* 秒钟调用 `curl` 判断服务是否可用。 62 | 与 **节点检测** 一样,如果命令返回值大于 **2** ,则认为检查 **失败** ,对应的服务将被标记为 **不健康** 。 63 | 64 | 65 | 现在,通过 ``consul reload`` 或者发送 ``SIGHUP`` 信号重启第二个 **代理** 。 66 | 接下来, **代理** 将出现以下日志: 67 | 68 | .. code-block:: text 69 | 70 | ==> Starting Consul agent... 71 | ... 72 | [INFO] agent: Synced service 'web' 73 | [INFO] agent: Synced check 'service:web' 74 | [INFO] agent: Synced check 'ping' 75 | [WARN] Check 'service:web' is now critical 76 | 77 | 前几行表明, **代理** 已经同步了新配置。 78 | 最后一行表明,我们为 ``web`` 服务添加的健康检查发现严重错误。 79 | 这是因为,我们并没有运行 `Web` 服务, `curl` 检查一定会失败。 80 | 81 | 检查健康状态 82 | ============ 83 | 84 | 我们已经添加了两个健康检查定义,现在可以通过 `HTTP` 查看结果。 85 | 首先,我们用以下命令查看所有 **不通过** 的检查(可以在任意节点运行): 86 | 87 | .. code-block:: shell-session 88 | 89 | vagrant@n1:~$ curl http://localhost:8500/v1/health/state/critical 90 | [{"Node":"agent-two","CheckID":"service:web","Name":"Service 'web' check","Status":"critical","Notes":"","ServiceID":"web","ServiceName":"web","ServiceTags":["rails"]}] 91 | 92 | 由此可见,只有一个检查处于严重错误状态,这就是我们的 ``web`` 服务。 93 | 94 | 此外,我们尝试通过 `DNS` 查询 ``web`` 服务, `Consul` 并不返回任何地址因为服务不健康。 95 | 96 | .. code-block:: shell-session 97 | 98 | vagrant@n1:~$ dig @127.0.0.1 -p 8600 web.service.consul 99 | 100 | ;; QUESTION SECTION: 101 | ;web.service.consul. IN A 102 | 103 | 总结 104 | ==== 105 | 106 | 本节,我们通过亲身试验发现,添加健康查也非常简单。 107 | 更新检查定义只需编辑配置文件,并向 **代理** 发送 `SIGHUP` 信号。 108 | 另外,也可以使用 `HTTP` 接口动态 **添加** 、 **删除** 、 以及 **修改** 检查定义。 109 | `API` 还支持 **失知制动** ( `dead man's switch` ),一种基于 `TTL`_ 的检查。 110 | `TTL` 检查让应用与 `Consul` 集成更紧密,业务逻辑判断可成为健康检查的一部分。 111 | 112 | 下一步 113 | ====== 114 | 115 | 下一节,我们介绍: :doc:`kv` 。 116 | 117 | .. include:: /_fragments/next-step-to-wechat-mp.rst 118 | 119 | 参考文献 120 | ======== 121 | 122 | #. `Registering Health Checks | Consul - HashiCorp Learn `_ 123 | 124 | .. include:: /_fragments/wechat-reward.rst 125 | 126 | .. include:: /_fragments/disqus.rst 127 | 128 | .. _Consul: https://www.consul.io/ 129 | .. _TTL: https://consul.io/docs/agent/checks.html#TTL 130 | 131 | .. comments 132 | comment something out below 133 | 134 | -------------------------------------------------------------------------------- /docs/zh_CN/services/consul/quick-start/index.rst: -------------------------------------------------------------------------------- 1 | .. 快速开始 2 | FileName: index.rst 3 | Author: Fasion Chan 4 | Created: 2019-01-21 19:38:30 5 | @contact: fasionchan@gmail.com 6 | @version: $Id$ 7 | 8 | Description: 9 | 10 | Changelog: 11 | 12 | .. meta:: 13 | :description lang=zh: 14 | :keywords: 15 | 16 | ======== 17 | 快速开始 18 | ======== 19 | 20 | `Consul`_ 是一个 **微服务管理** 解决方案,提供 **服务发现** 、 **配置管理** 、 以及 **服务划分** 等全特性功能。 21 | 通过本系列学习,你可在一天之内掌握 `Consul`_ ! 22 | 23 | .. toctree:: 24 | :titlesonly: 25 | 26 | 安装Consul 27 | 运行代理 28 | 注册服务 29 | 互连服务 30 | Consul集群 31 | 健康检查 32 | 键值数据 33 | Web UI 34 | 35 | 简要 36 | ==== 37 | 38 | #. :doc:`install` 。 39 | `Consul`_ 集群每个节点均需要安装 `Consul`_ `代理` ,本节介绍安装方法。 40 | #. :doc:`agent` 。 41 | `Consul`_ **代理** ( `agent` )可运行于 **服务器** ( `server` )模式或 **客户端** ( `client` )模式。 42 | 本节讨论这两种模式,并演示如何以 **开发** ( `development` )模式启动 **代理** 。 43 | #. :doc:`services` 。 44 | 往 `Consul`_ 注册服务,提供服务配置或者调用 `HTTP` 接口均可。 45 | 本节演示通过配置文件注册服务。 46 | #. :doc:`connect` 。 47 | `Consul`_ **互连** ( `Connect` )提供服务间连接 **鉴权** 及 **加密** ,基于 `TLS` 。 48 | #. :doc:`join` 。本节通过 `Vagrant` 虚拟机演示组件双节点集群。 49 | #. :doc:`checks` 。本节演示为 **节点** ( `node` )和 **服务** ( `service` )配置 **健康检查** 。 50 | #. :doc:`kv` 。本节演示使用 **命令行接口** ( `CLI` )添加、管理 **键值** ( `key-value` )数据。 51 | #. :doc:`ui` 。 `Consul`_ 自带 `Web` 界面,功能全面,操作友好,本节我们一起来探索。 52 | 53 | 54 | .. _Consul: https://www.consul.io/ 55 | 56 | .. comments 57 | comment something out below 58 | 59 | -------------------------------------------------------------------------------- /docs/zh_CN/services/consul/quick-start/install.rst: -------------------------------------------------------------------------------- 1 | .. 安装Consul 2 | FileName: installation.rst 3 | Author: Fasion Chan 4 | Created: 2019-01-22 19:29:41 5 | @contact: fasionchan@gmail.com 6 | @version: $Id$ 7 | 8 | Description: 9 | 10 | Changelog: 11 | 12 | .. meta:: 13 | :description lang=zh: 14 | 开始使用Consul前,必须先在机器上安装。 15 | 对于所有支持的系统和硬件平台,Consul均以二进制包的形式进行分发。 16 | 因此,用户可以选择直接使用二进制包,或者自行从源码编译构建。 17 | :keywords: consul, install, 安装, PATH环境变量, 二进制包 18 | 19 | ========== 20 | 安装Consul 21 | ========== 22 | 23 | 开始使用 `Consul`_ 前,必须先在机器上安装。 24 | 对于所有支持的系统和硬件平台, `Consul` 均以 **二进制包** 的形式进行分发。 25 | 因此,用户可以选择直接使用二进制包,或者自行从源码 **编译构建** 。 26 | 27 | 二进制包 28 | ======== 29 | 30 | 首先,在 `下载页面 `_ 选择并下载适用的二进制包, 31 | 二进制包为 `ZIP` 压缩包。 32 | 33 | 下载完毕后,解压二进制包。 34 | `Consul`_ 只包含一个二进制程序,名字为: `consul` 。 35 | 包中任何其他文件均可放心删除,完全不影响 `Consul` 功能。 36 | 37 | 最后一步,确保 `consul` 二进制程序可以被 `PATH` 环境变量找到。 38 | 用户可以将 `consul` 移到 `PATH` 目录中一个,或者将 `consul` 所在目录加到 `PATH` 中: 39 | 40 | .. code-block:: shell-session 41 | 42 | $ export PATH=/path/to/consul:$PATH 43 | 44 | 验证安装 45 | ======== 46 | 47 | `Consul`_ 安装完成后,需确保 `consul` 命令就绪,以验证安装效果。 48 | 新打开一个终端会话并运行以下命令: 49 | 50 | 51 | .. code-block:: shell-session 52 | 53 | $ consul -v 54 | Consul v1.4.0 55 | Protocol 2 spoken by default, understands 2 to 3 (agent will automatically use protocol >2 when speaking to compatible agents) 56 | 57 | 如果遇到找不到 `consul` 的错误,说明 `PATH` 环境变量设置有误。 58 | 需要重新检查 `PATH` 环境变量,是否包含安装 `Consul` 的目录(即 `consul` 程序所在目录)。 59 | 60 | 下一步 61 | ====== 62 | 63 | `Consul` 安装完毕后,便可 :doc:`agent` ,一睹为快。 64 | 65 | .. include:: /_fragments/next-step-to-wechat-mp.rst 66 | 67 | 参考文献 68 | ======== 69 | 70 | #. `Install Consul | Consul - HashiCorp Learn `_ 71 | 72 | .. include:: /_fragments/wechat-reward.rst 73 | 74 | .. include:: /_fragments/disqus.rst 75 | 76 | .. _Consul: https://www.consul.io/ 77 | 78 | .. comments 79 | comment something out below 80 | 81 | -------------------------------------------------------------------------------- /docs/zh_CN/services/consul/quick-start/kv.rst: -------------------------------------------------------------------------------- 1 | .. 键值数据 2 | FileName: kv.rst 3 | Author: Fasion Chan 4 | Created: 2019-01-24 18:15:19 5 | @contact: fasionchan@gmail.com 6 | @version: $Id$ 7 | 8 | Description: 9 | 10 | Changelog: 11 | 12 | .. meta:: 13 | :description lang=zh: 14 | 除了服务发现和健康检查,Consul还提供一个易于使用的KV存储。 15 | 这可以用来存储动态配置、辅助服务协调、构建领袖选举,几乎可以做任何开发人员能够想到的事情。 16 | :keywords: consul, kv store, dynamic configuration, KV存储, 键值存储, 动态配置 17 | 18 | ======== 19 | 键值数据 20 | ======== 21 | 22 | 除了 :doc:`服务发现 ` 和 :doc:`健康检查 ` ,`Consul`_ 还提供一个易于使用的 `KV` 存储。 23 | 这可以用来存储动态配置、辅助服务协调、构建领袖选举等,甚至做任何开发人员能够想到的事情。 24 | 25 | 简明用法 26 | ======== 27 | 28 | `KV` 存储更容易入门,接下来我们创建几个键值来演示一下。 29 | 与 `Consul`_ **键值存储** 打交道有两种不同方式: `HTTP` 接口或者 **命令行接口** ( `CLI` )。 30 | 下面的例子使用 **命令行接口** 进行,因为这样更为方便。 31 | 更高级的集成,可以参考 `Consul KV HTTP API文档 `_ 。 32 | 33 | 先 **查询** 给定 **键** ( `key` ) ``redis/config/minconns`` 对应的 **值** ( `value` ): 34 | 35 | .. code-block:: shell-session 36 | 37 | $ consul kv get redis/config/minconns 38 | Error! No key exists at: redis/config/minconns 39 | 40 | 可以看到,我们没有得到任何结果,因为该键根本没有存储任何值。 41 | 接着,我们往存储 **插入** 一些键值: 42 | 43 | .. code-block:: shell-session 44 | 45 | $ consul kv put redis/config/minconns 1 46 | Success! Data written to: redis/config/minconns 47 | 48 | .. code-block:: shell-session 49 | 50 | $ consul kv put redis/config/maxconns 25 51 | Success! Data written to: redis/config/maxconns 52 | 53 | .. code-block:: shell-session 54 | 55 | $ consul kv put -flags=42 redis/config/users/admin abcd1234 56 | Success! Data written to: redis/config/users/admin 57 | 58 | 现在存储已经有数据了,可以根据键将值 **查询** 出来: 59 | 60 | .. code-block:: shell-session 61 | 62 | $ consul kv get redis/config/minconns 63 | 1 64 | 65 | `Consul`_ 也可以返回额外的 **元数据** ,指定 ``-detailed`` 参数即可: 66 | 67 | .. code-block:: shell-session 68 | 69 | $ consul kv get -detailed redis/config/minconns 70 | CreateIndex 207 71 | Flags 0 72 | Key redis/config/minconns 73 | LockIndex 0 74 | ModifyIndex 207 75 | Session - 76 | Value 1 77 | 78 | 在 ``redis/config/users/admin`` 键上,我们存储了一个值为 `42` 的 **标识** ( `flag` )。 79 | `Consul`_ 支持 `64` 位的标识值。 80 | 标识值不是 `Consul` 内部使用的,而是客户端用来为 **键值** 添加带语义的元数据。 81 | 82 | 通过 ``-recurse`` 参数,可以 **列举** 存储内所有的键,返回结果以字母排序: 83 | 84 | .. code-block:: shell-session 85 | 86 | $ consul kv get -recurse 87 | redis/config/maxconns:25 88 | redis/config/minconns:1 89 | redis/config/users/admin:abcd1234 90 | 91 | 从存储中 **删除** 某个键,需要调用 ``delete`` 指令: 92 | 93 | .. code-block:: shell-session 94 | 95 | $ consul kv delete redis/config/minconns 96 | Success! Deleted key: redis/config/minconns 97 | 98 | **递归删除** 某个前缀下所有键也是支持的,同样是指定 ``-recurse`` 参数: 99 | 100 | .. code-block:: shell-session 101 | 102 | $ consul kv delete -recurse redis 103 | Success! Deleted keys with prefix: redis 104 | 105 | 在同样的键上再次执行 ``put`` 指令即可 **更新** 对应的值: 106 | 107 | .. code-block:: shell-session 108 | 109 | $ consul kv put foo bar 110 | 111 | $ consul kv get foo 112 | bar 113 | 114 | $ consul kv put foo zip 115 | 116 | $ consul kv get foo 117 | zip 118 | 119 | `Consul`_ 也支持原子的 **检查并设置** ( `Check-And-Set` )型更新操作,指定 ``-cas`` 参数即可: 120 | 121 | .. code-block:: shell-session 122 | 123 | $ consul kv put -cas -modify-index=123 foo bar 124 | Success! Data written to: foo 125 | 126 | $ consul kv put -cas -modify-index=123 foo bar 127 | Error! Did not write to foo: CAS failed 128 | 129 | 第一个更新操作成功因为记录索引刚好是 `123` ,第二次则失败因为索引不再是 `123` 了。 130 | 131 | 下一步 132 | ====== 133 | 134 | 由于篇幅关系,我们只介绍了若干个操作接口,完整接口可以查看文档: 135 | 136 | - `Consul KV HTTP API `_ 137 | - `Consul KV CLI `_ 138 | 139 | 下一节,我们介绍: :doc:`ui` 。 140 | 141 | .. include:: /_fragments/next-step-to-wechat-mp.rst 142 | 143 | 参考文献 144 | ======== 145 | 146 | #. `KV Data | Consul - HashiCorp Learn `_ 147 | 148 | .. include:: /_fragments/wechat-reward.rst 149 | 150 | .. include:: /_fragments/disqus.rst 151 | 152 | .. _Consul: https://www.consul.io/ 153 | 154 | .. comments 155 | comment something out below 156 | 157 | -------------------------------------------------------------------------------- /docs/zh_CN/services/consul/quick-start/ui.rst: -------------------------------------------------------------------------------- 1 | .. Web UI 2 | FileName: ui.rst 3 | Author: Fasion Chan 4 | Created: 2019-01-24 18:19:49 5 | @contact: fasionchan@gmail.com 6 | @version: $Id$ 7 | 8 | Description: 9 | 10 | Changelog: 11 | 12 | .. meta:: 13 | :description lang=zh: 14 | Consul还提供了一个功能全面的WebUI,界面也非常友好。 15 | UI可以查看服务、节点信息,查看健康检查配置和状态,查询或者设置键值数据。 16 | UI自动支持多数据中心(multi-datacenter)环境。 17 | :keywords: consul, ui, web, CONSUL_UI_LEGACY, 界面 18 | 19 | ====== 20 | Web UI 21 | ====== 22 | 23 | `Consul`_ 还提供了一个功能全面的 `Web UI` ,界面也非常友好。 24 | `UI` 可以查看 **服务** 、 **节点** 信息,查看 **健康检查** 配置和状态, 25 | 查询或者设置 **键值数据** 。 26 | `UI` 自动支持 **多数据中心** ( `multi-datacenter` )环境。 27 | 28 | **代理** 自带 `UI` 界面功能,指定 ``-ui`` 参数即可启用: 29 | 30 | .. code-block:: shell-session 31 | 32 | $ consul agent -dev -ui 33 | 34 | `UI` 服务端口与 `HTTP` 接口一样,路径为 ``/ui`` ,默认地址是 `http://localhost:8500/ui `_ 。 35 | 36 | `UI` 访问权限可以通过 `ACL` 进行控制,限制只对某些页面有 **读** 、 **写** 或 **更新** 权限。 37 | 38 | 另外,可以在 `这里 `_ 找到一个 `UI` 演示环境( `Demo` )。 39 | 40 | 历史版本 41 | ======== 42 | 43 | `Consul`_ `1.2.0` 版本之后,原来的 `UI` 界面废弃了。 44 | 但是,用户还是可以通过将环境变量 ``CONSUL_UI_LEGACY`` 设置为 ``true`` 来使用旧版 `UI` 。 45 | 如果未指定该环境变量,默认启用最新版 `UI` 。 46 | 想要使用最新版 `UI` ,将 ``CONSUL_UI_LEGACY`` 设置为 ``false`` 或者干脆就不提供该环境变量。 47 | 48 | 下一步 49 | ====== 50 | 51 | .. include:: /_fragments/next-step-to-wechat-mp.rst 52 | 53 | 参考文献 54 | ======== 55 | 56 | #. `Web UI | Consul - HashiCorp Learn `_ 57 | 58 | .. include:: /_fragments/wechat-reward.rst 59 | 60 | .. include:: /_fragments/disqus.rst 61 | 62 | .. _Consul: https://www.consul.io/ 63 | 64 | .. comments 65 | comment something out below 66 | 67 | -------------------------------------------------------------------------------- /docs/zh_CN/services/haproxy.rst: -------------------------------------------------------------------------------- 1 | .. HAProxy 2 | FileName: haproxy.rst 3 | Author: Fasion Chan 4 | Created: 2018-05-07 18:14:29 5 | @contact: fasionchan@gmail.com 6 | @version: $Id$ 7 | 8 | Description: 9 | 10 | Changelog: 11 | 12 | .. meta:: 13 | :keywords: haproxy, 负载均衡, load balancing 14 | 15 | ======= 16 | HAProxy 17 | ======= 18 | 19 | `HAProxy `_ 是一款开源负载均衡软件,同时提供4层(TCP)和7层(HTTP)代理。 20 | 21 | 负载均衡 22 | ======== 23 | 24 | 由于普通机器单机处理能力以及可靠性的限制,服务需要在多台机器进行部署,形成集群。 25 | 这里,主要有两方面的考虑: 26 | 27 | #. 提高可靠性; 28 | #. 提高处理能力; 29 | 30 | 那么,用户(或客户端)如何访问多实例服务呢? 31 | 32 | 最简单的方案是在客户端进行重试。 33 | 以 `DNS` 解析为例,可以配置多台 `DNS` 服务器,一台查询失败则尝试另外一台: 34 | 35 | .. figure:: /_images/services/haproxy/bb73a4fcd260578b645659c6dfd968f1.png 36 | :width: 512px 37 | 38 | *客户端重试* 39 | 40 | 这显然不是最佳的方案,客户端需要支持连接多台服务器,需要自带服务状态探测功能, 41 | 还需要具备切换能力。 42 | 43 | 一个更科学的架构是,提供一台服务器作为接入代理,为客户端访问实际服务器: 44 | 45 | .. figure:: /_images/services/haproxy/6a1276e4ac55c2597729ae0551084ffd.gif 46 | :width: 580px 47 | 48 | *负载均衡* 49 | 50 | 在这种模式下,客户端只是直接访问代理服务器,由代理服务器将请求转发到后面的处理服务器。 51 | 而且,转发对客户端来说是透明的,跟访问一台服务器没啥区别。 52 | 53 | 此外,技术人员还可以在代理服务器上实现更强大的架构功能: 54 | 55 | #. 代理服务器检查后端服务器状态,及时剔除故障服务器; 56 | #. 代理服务器控制转发流量,处理能力强的服务器可以多分配一些流量; 57 | 58 | 这种架构就是 **负载均衡** 架构,这里的代理服务器就是 **负载均衡服务器** 。 59 | 而 `HAProxy `_ 就是运行在负载均衡服务器之上,提供负载均衡能力的那个软件服务。 60 | 61 | 安装部署 62 | ======== 63 | 64 | 以 `Ubuntu` 为例,使用 `apt` 进行安装: 65 | 66 | .. code-block:: shell-session 67 | 68 | $ apt install haproxy 69 | 70 | 对于 `Linux` 系统, `Haproxy` 的配置一般存在 ``/etc`` 目录之下。 71 | 以 `Ubuntu` 为例,路径是 ``/etc/haproxy/haproxy.cfg`` 。 72 | 根据实际场景编辑配置文件,然后重启服务即可生效: 73 | 74 | .. code-block:: shell-session 75 | 76 | $ service haproxy restart 77 | 78 | .. _layer4-load-balancing: 79 | 80 | 4层负载均衡 81 | =========== 82 | 83 | 下面是以一个实际例子介绍4层负载均衡的配置方式。 84 | 这个故事是笔者为了科学上网,操碎心的故事。 85 | 86 | 最开始,在美国加州买了一台虚拟机,部署上 :doc:`shadowsocks` 服务端,在国内访问。 87 | 加州虽然挺遥远,延迟到部分时间在 200 毫秒不到,还是可以接受的。 88 | 但是,有时网络质量突然变差,丢包率急剧上升,几乎不可用。 89 | 虽然持续时间不会很长,但是在关键时刻确实很烦人。 90 | 91 | 为了解决这个问题,笔者又在香港买了另一台虚拟机,双保险科学上网。 92 | 平时哪台连不上就切到另一台,基本上没有不可用的情况。 93 | 顺便提一下,香港的服务器确实快,我从广州连过去延迟基本在 20 毫秒以下。 94 | 95 | 一台贵的香港服,一台便宜的加州服作为备胎,问题算是解决了。 96 | 然而,手工切来切去很不爽呀! 97 | 98 | 这时,我想起在广州还有一台服务器呢! 99 | 我在上面部一个 `HAProxy` 服务,将 `TCP` 连接分发到两台 :doc:`shadowsocks` 不就好了吗? 100 | 于是,下图横空出世: 101 | 102 | .. figure:: /_images/services/haproxy/bb0878dce5b5e85224e64c2f6208d69a.png 103 | :width: 480px 104 | 105 | *科学上网架构* 106 | 107 | 广州节点 `HAProxy` 的配置如下: 108 | 109 | .. code-block:: cfg 110 | 111 | global 112 | log /dev/log local0 113 | log /dev/log local1 notice 114 | chroot /var/lib/haproxy 115 | user haproxy 116 | group haproxy 117 | daemon 118 | 119 | defaults 120 | log global 121 | mode tcp 122 | option dontlognull 123 | contimeout 5000 124 | clitimeout 50000 125 | srvtimeout 50000 126 | 127 | listen ss-proxy 0.0.0.0:443 128 | mode tcp 129 | maxconn 1024 130 | balance roundrobin 131 | server hk xxx.xxx.xxx.xxx:443 check 132 | server ca xxx.xxx.xxx.xxx:443 check 133 | 134 | 这里采用 ``tcp`` 模式,也就是 **4层负载均衡** 模式。 135 | 我的配置分为 ``global`` 、 ``defaults`` 以及 ``listen`` 总共 ``3`` 节: 136 | 137 | ``global`` 节主要是一些全局配置,包括日志、运行用户、组以及运行模式等。 138 | 139 | ``defaults`` 节主要是一些默认配置,包括代理模式、连接超时时长等。 140 | 141 | ``listen`` 节是重点所在,定义了服务绑定的地址及端口、代理模式、后端服务器以及负载均衡算法等。 142 | 例子中,侦听端口是 ``443`` ,转发到两台后端服务器,分别是香港服( ``hk`` )以及加州服( ``ca`` )。 143 | 144 | 客户端连接到 `HAProxy` 之后,就不用动不动切换服务器了——爽! 145 | 146 | .. figure:: /_images/services/haproxy/fa48a31d52eaa2d04a30e8ddf1dcafe3.png 147 | :width: 252px 148 | 149 | *无须切换服务器* 150 | 151 | 权重调整 152 | ======== 153 | 154 | .. code-block:: cfg 155 | 156 | listen ss-proxy 0.0.0.0:443 157 | mode tcp 158 | maxconn 1024 159 | balance roundrobin 160 | server hk xxx.xxx.xxx.xxx:443 weight 256 161 | server ca xxx.xxx.xxx.xxx:443 weight 1 162 | 163 | 健康检查 164 | ======== 165 | 166 | .. code-block:: cfg 167 | 168 | listen ss-proxy 0.0.0.0:443 169 | mode tcp 170 | maxconn 1024 171 | balance roundrobin 172 | server hk xxx.xxx.xxx.xxx:443 check inter 2s fastinter 1s 173 | server ca xxx.xxx.xxx.xxx:443 check inter 2s fastinter 1s 174 | 175 | 下一步 176 | ====== 177 | 178 | 如果你想知道如何实现科学上网,可以看看 :doc:`shadowsocks` 。 179 | 180 | .. include:: /_fragments/next-step-to-wechat-mp.rst 181 | 182 | 参考文献 183 | ======== 184 | 185 | .. include:: /_fragments/wechat-reward.rst 186 | 187 | .. include:: /_fragments/disqus.rst 188 | 189 | .. comments 190 | comment something out below 191 | 192 | -------------------------------------------------------------------------------- /docs/zh_CN/services/index.rst: -------------------------------------------------------------------------------- 1 | .. 网络服务 2 | FileName: index.rst 3 | Author: Fasion Chan 4 | Created: 2018-02-24 20:20:48 5 | @contact: fasionchan@gmail.com 6 | @version: $Id$ 7 | 8 | Description: 9 | 10 | Changelog: 11 | 12 | ======== 13 | 网络服务 14 | ======== 15 | 16 | .. toctree:: 17 | :titlesonly: 18 | 19 | HAProxy 20 | Consul 21 | etcd 22 | gRPC 23 | Nginx 24 | SSH端口转发 25 | Tomcat 26 | 27 | .. comments 28 | comment something out blow 29 | Shadowsocks 30 | 梅林(Merlin)路由固件 31 | -------------------------------------------------------------------------------- /docs/zh_CN/services/nginx.rst: -------------------------------------------------------------------------------- 1 | .. Nginx 2 | FileName: nginx.rst 3 | Author: Fasion Chan 4 | Created: 2018-07-09 20:17:32 5 | @contact: fasionchan@gmail.com 6 | @version: $Id$ 7 | 8 | Description: 9 | 10 | Changelog: 11 | 12 | ===== 13 | Nginx 14 | ===== 15 | 16 | 配置片段 17 | ======== 18 | 19 | 静态资源缓存 20 | ------------ 21 | 22 | .. code-block:: nginx 23 | 24 | server { 25 | listen 80; 26 | server_name some-site.com; 27 | 28 | root /some/path/to/site; 29 | 30 | # 缓存图片 31 | location ~ \.(jpg|png|jpeg|bmp|gif|swf)$ { 32 | root /some/path/to/site/images; 33 | if (-f $request_filename) { 34 | expires 7d; 35 | break; 36 | } 37 | } 38 | 39 | # 缓存样式 40 | location ~ \.(css)$ { 41 | root /some/path/to/site/css; 42 | if (-f $request_filename) { 43 | expires 3d; 44 | break; 45 | } 46 | } 47 | 48 | # 缓存脚本 49 | location ~ \.(js)$ { 50 | root /some/path/to/site/js; 51 | if (-f $request_filename) { 52 | expires 1d; 53 | break; 54 | } 55 | } 56 | } 57 | 58 | 反向代理 59 | -------- 60 | 61 | .. code-block:: nginx 62 | 63 | server { 64 | # 监听端口 65 | listen 80; 66 | # 代理对外域名 67 | server_name proxy-site.com; 68 | 69 | location / { 70 | # 转向服务器 71 | proxy_pass http://dest-site.com; 72 | proxy_redirect default; 73 | } 74 | } 75 | 76 | # 服务器集群及权重(可选) 77 | upstream dest-site.com { 78 | server 10.0.0.1:80 weight=1; 79 | } 80 | 81 | Web Socket 转发 82 | --------------- 83 | 84 | .. code-block:: nginx 85 | 86 | location /wsapp/ { 87 | proxy_pass http://wsbackend; 88 | proxy_http_version 1.1; 89 | proxy_set_header Upgrade $http_upgrade; 90 | proxy_set_header Connection "Upgrade"; 91 | } 92 | 93 | 下一步 94 | ====== 95 | 96 | .. include:: /_fragments/next-step-to-wechat-mp.rst 97 | 98 | 参考文献 99 | ======== 100 | 101 | #. `Using NGINX as a WebSocket Proxy `_ 102 | 103 | .. include:: /_fragments/wechat-reward.rst 104 | 105 | .. include:: /_fragments/disqus.rst 106 | 107 | 108 | .. comments 109 | comment something out below 110 | 111 | .. meta:: 112 | :description lang=zh: 113 | :keywords: 114 | 115 | -------------------------------------------------------------------------------- /docs/zh_CN/services/ssh-port-forwarding.rst: -------------------------------------------------------------------------------- 1 | .. SSH端口转发 2 | FileName: port-forwarding.rst 3 | Author: Fasion Chan 4 | Created: 2018-03-28 18:42:03 5 | @contact: fasionchan@gmail.com 6 | @version: $Id$ 7 | 8 | Description: 9 | 10 | Changelog: 11 | 12 | .. meta:: 13 | :description lang=zh: 14 | 本文将介绍,如何利用 `ssh` 隧道进行端口转发。 15 | 端口转发可分为两种:本地端口转发以及远程端口转发。 16 | 在蓝服运行 ``ssh`` 命令,通过 ``-L`` 选项设置本地端口转发: 17 | ssh -L 8080:192.168.0.3:80 someuser@RedServer 18 | 在蓝服运行 ``ssh`` 命令,通过 ``-R`` 选项设置远程端口转发: 19 | ssh -R 2222:localhost:22 someuser@GreenServer 20 | :keywords: ssh端口转发, 远程端口转发, 本地端口转发, 端口转发, port-forwarding 21 | 22 | =========== 23 | SSH端口转发 24 | =========== 25 | 26 | `ssh` 命令除了登录服务器,还可以在两台机器之间建立隧道。 27 | 28 | 通过隧道,你可以打通一些本来不可访问的网络或者系统,让不可能成为可能。 29 | 因此,完全有必要花点时间,学习如何使用 `ssh` 命令打洞。 30 | 31 | 本文将介绍,如何利用 `ssh` 隧道进行端口转发。端口转发可分为两种: 32 | 33 | - :ref:`ssh-local-port-forwarding` 34 | - :ref:`ssh-remote-port-forwarding` 35 | 36 | .. note:: 37 | 38 | 下文图例用颜色区分不同的服务器,称蓝色服务器为蓝服,其他以此类推。 39 | 40 | .. _ssh-local-port-forwarding: 41 | 42 | 本地端口转发 43 | ============ 44 | 45 | .. figure:: /_images/services/port-forwarding/355c9c3d956d2b9aab7156a5caa8f76c.png 46 | 47 | 如上图,蓝服需要访问绿服 ``80`` 端口,但是直连不通。 48 | 蓝服可以通过 ``22`` 端口登录红服,而红服可以连接到绿服。 49 | 50 | 这种情况,可以在蓝服与红服之间建一个隧道,将蓝服一个本地端口(如 ``8080`` )代理到绿服 ``80`` 端口上。 51 | 蓝服访问本地 ``8080`` 端口,就像访问绿服 ``80`` 端口一样。 52 | 也就是说,蓝服 ``8080`` 端口被映射(转发)到绿服 ``80`` 端口。 53 | 54 | 似乎挺不错的,具体如何操作呢? 55 | 56 | 在蓝服运行 ``ssh`` 命令,通过 ``-L`` 选项设置端口转发: 57 | 58 | .. code-block:: shell-session 59 | 60 | fasion@BlueServer:~$ ssh -L 8080:192.168.0.3:80 someuser@RedServer 61 | 62 | 该命令将从蓝服登陆到红服(建立隧道),并在本地(即蓝服)监听 ``8080`` 端口。 63 | 访问 ``8080`` 端口的请求将通过隧道到达红服,最终由红服负责转发到绿服 ``80`` 端口。 64 | 这种端口转发模式称为 **本地端口转发** ( `Local Port Forwarding` )。 65 | 66 | 选项 ``-L`` 参数有不同的指定方式: 67 | 68 | - [bind_address:]bind_port:host:hostport 69 | - [bind_address:]bind_port:remote_socket 70 | - local_socket:host:hostport 71 | - local_socket:remote_socket 72 | 73 | ``bind_address`` 和 ``bind_port`` 是指蓝服监听的地址端口对; ``host`` 和 ``hostport`` 指定被代理的端口,即红服 ``80`` 端口。 74 | 75 | ``bind_address`` 可以指定不同的值: 76 | 77 | #. ``localhost`` 或者 ``127.0.0.1`` ,只有本地可以访问; 78 | #. 特定 `IP` ,只能通过该 `IP` 访问; 79 | #. ``*`` 或者 ``0.0.0.0`` ,没有任何限制; 80 | #. 不填,默认行为同 3 ; 81 | 82 | ``host`` 和 ``hostport`` 可以是任何红服可到达的服务,包括红服本身: 83 | 84 | .. figure:: /_images/services/port-forwarding/9fe45fe01680a9bc1a724b97694ffcb7.png 85 | 86 | 在上面这个例子中,红服的 ``80`` 端口被防火墙屏蔽了,而 ``22`` 端口访问正常。 87 | 88 | 这时也可以通过端口转发解决问题,``host`` 应该填 ``localhost`` 或者 ``127.0.0.1`` , ``hostport`` 应该填 ``80`` : 89 | 90 | .. code-block:: shell-session 91 | 92 | fasion@BlueServer:~ $ ssh -L 8080:localhost:80 someuser@RedServer 93 | 94 | 注意到 Unix套接字 也是支持的,这里就不展开了。 95 | 96 | .. _ssh-remote-port-forwarding: 97 | 98 | 远程端口转发 99 | ============ 100 | 101 | .. figure:: /_images/services/port-forwarding/16bcc9128d1c522ad386d584d1bbb63d.png 102 | 103 | 如上图,由于防火墙的存在,外部无法直接访问蓝服 ``22`` 端口。 104 | 蓝服可以登录绿服,而外部也可以正常访问绿服。 105 | 这种情况下,也可以通过端口转发打通网络。 106 | 107 | 在蓝服运行 ``ssh`` 命令,通过 ``-R`` 选项设置端口转发: 108 | 109 | .. code-block:: shell-session 110 | 111 | fasion@BlueServer:~$ ssh -R 2222:localhost:22 someuser@GreenServer 112 | 113 | 该命令将从蓝服登陆绿服,并在绿服监听 ``2222`` 端口。 114 | 之后,访问绿服 ``2222`` 端口的请求,将通过隧道到达蓝服,由蓝服负责转发到其本地的 ``22`` 端口。 115 | 116 | 这种端口转发模式称为 **远程端口转发** ( `Remote Port Forwarding` ),与 **本地端口转发** 类似,但方向刚好相反。 117 | 118 | 选项 ``-R`` 参数与 ``-L`` 类似,不再赘述: 119 | 120 | - [bind_address:]port:host:hostport 121 | - [bind_address:]port:local_socket 122 | - remote_socket:host:hostport 123 | - remote_socket:local_socket 124 | - [bind_address:]port 125 | 126 | 总结 127 | ==== 128 | 129 | `ssh` 端口转发就是通过 `ssh` 命令在两台机器之间建立隧道,一端负责 **监听** ,另一端负责 **转发** 。 130 | 由于方向不同,可分为两种不同的模式: 131 | 132 | .. csv-table:: 端口转发模式 133 | :header: "模式", "监听端", "转发端" 134 | 135 | "本地端口转发", "本地", "远程" 136 | "远程端口转发", "远程", "本地" 137 | 138 | 很显然, **端口转发模式** 是由 **监听端** 命名的。 139 | 140 | 下一步 141 | ====== 142 | 143 | .. include:: /_fragments/next-step-to-wechat-mp.rst 144 | 145 | 参考文献 146 | ======== 147 | 148 | #. `How to Create SSH Tunnels `_ 149 | 150 | .. include:: /_fragments/wechat-reward.rst 151 | 152 | .. include:: /_fragments/disqus.rst 153 | 154 | .. comments 155 | comment something out below 156 | 157 | .. meta:: 158 | :description lang=zh: 159 | :keywords: 160 | 161 | 162 | .. raw:: html 163 | 164 | 165 | -------------------------------------------------------------------------------- /docs/zh_CN/services/tomcat.rst: -------------------------------------------------------------------------------- 1 | .. Tomcat 2 | FileName: tomcat.rst 3 | Author: Fasion Chan 4 | Created: 2018-06-27 08:49:54 5 | @contact: fasionchan@gmail.com 6 | @version: $Id$ 7 | 8 | Description: 9 | 10 | Changelog: 11 | 12 | .. meta:: 13 | :keywords: tomcat, 安装 14 | 15 | ====== 16 | Tomcat 17 | ====== 18 | 19 | 安装 20 | ==== 21 | 22 | 先准备好 `JDK` 包以及 `Tomcat` 二进制包,下载链接如下: 23 | 24 | - `Oracle JDK 下载 `_ 25 | - `Apache Tomcat 下载 `_ 26 | 27 | 接下来,我们将 `JDK` 部署在 ``/data/jdk`` 目录下; 28 | 将 `Tomcat` 部署在 ``/data/tomcat/clusters/default`` 目录下。 29 | 30 | .. note:: 31 | 32 | `Tomcat` 部署目录选择主要出于多实例考虑, `clusters` 目录下可以部署多个实例, `default` 是其中一个。 33 | 34 | 接下来,我们将 `JDK` 包解压至选定目录: 35 | 36 | .. code-block:: shell-session 37 | 38 | $ mkdir /data/jdk 39 | $ tar -C /data/jdk -xf /media/home/Downloads/jdk-10.0.1_linux-x64_bin.tar.gz 40 | $ ls /data/jdk/ 41 | jdk-10.0.1 42 | 43 | 跑一下 `java` 命令,确认安装正常无误: 44 | 45 | .. code-block:: shell-session 46 | 47 | $ /data/jdk/jdk-10.0.1/bin/java --version 48 | java 10.0.1 2018-04-17 49 | Java(TM) SE Runtime Environment 18.3 (build 10.0.1+10) 50 | Java HotSpot(TM) 64-Bit Server VM 18.3 (build 10.0.1+10, mixed mode) 51 | 52 | 继续解压 `Tomcat` 二进制包至选定目录: 53 | 54 | .. code-block:: shell-session 55 | 56 | $ mkdir -p /data/tomcat/clusters/default 57 | $ tar -C /data/tomcat/clusters/default -xf apache-tomcat-9.0.8.tar.gz 58 | $ ls /data/tomcat/clusters/default 59 | apache-tomcat-9.0.8 60 | 61 | 进入 `Tomcat` 目录,编辑 ``bin/catalina.sh`` 文件: 62 | 63 | .. code-block:: shell-session 64 | 65 | $ cd /data/tomcat/clusters/default/apache-tomcat-9.0.8 66 | $ vi bin/catalina.sh 67 | 68 | 在代码逻辑开始之前(一条非注释语句之前),定义以下环境变量: 69 | 70 | .. code-block:: shell 71 | 72 | export TOMCAT_HOME="/data/tomcat/clusters/default/apache-tomcat-9.0.8" 73 | export CATALINA_HOME="/data/tomcat/clusters/default/apache-tomcat-9.0.8" 74 | export JRE_HOME="/data/jdk/jdk-10.0.1" 75 | export JAVA_HOME="/data/jdk/jdk-10.0.1" 76 | 77 | 运行 `bin/startup.sh` 启动服务: 78 | 79 | .. code-block:: shell-session 80 | 81 | $ bin/startup.sh 82 | Using CATALINA_BASE: /data/tomcat/clusters/default/apache-tomcat-9.0.8 83 | Using CATALINA_HOME: /data/tomcat/clusters/default/apache-tomcat-9.0.8 84 | Using CATALINA_TMPDIR: /data/tomcat/clusters/default/apache-tomcat-9.0.8/temp 85 | Using JRE_HOME: /data/jdk/jdk-10.0.1 86 | Using CLASSPATH: /data/tomcat/clusters/default/apache-tomcat-9.0.8/bin/bootstrap.jar:/data/tomcat/clusters/default/apache-tomcat-9.0.8/bin/tomcat-juli.jar 87 | Tomcat started. 88 | 89 | 确认 `Tomcat` 进程已经启动运行: 90 | 91 | .. code-block:: shell-session 92 | 93 | $ ps aux | grep -v grep | grep tomcat 94 | fasion 24646 9.2 10.0 2395260 101156 pts/0 Sl 01:36 0:16 /data/jdk/jdk-10.0.1/bin/java -Djava.util.logging.config.file=/data/tomcat/clusters/default/apache-tomcat-9.0.8/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djdk.tls.ephemeralDHKeySize=2048 -Djava.protocol.handler.pkgs=org.apache.catalina.webresources -Dorg.apache.catalina.security.SecurityListener.UMASK=0027 -Dignore.endorsed.dirs= -classpath /data/tomcat/clusters/default/apache-tomcat-9.0.8/bin/bootstrap.jar:/data/tomcat/clusters/default/apache-tomcat-9.0.8/bin/tomcat-juli.jar -Dcatalina.base=/data/tomcat/clusters/default/apache-tomcat-9.0.8 -Dcatalina.home=/data/tomcat/clusters/default/apache-tomcat-9.0.8 -Djava.io.tmpdir=/data/tomcat/clusters/default/apache-tomcat-9.0.8/temp org.apache.catalina.startup.Bootstrap start 95 | 96 | 最后,使用浏览器访问 `8080` 端口即可看到 `Tomcat` 默认页面: 97 | 98 | .. figure:: /_images/services/tomcat/357b06b730ccb543ff3220f6fdae39a4.png 99 | :width: 508px 100 | 101 | *Tomcat 默认页面* 102 | 103 | 如果 `Tomcat` 部署在本地,则访问 ``_ 。 104 | 105 | 下一步 106 | ====== 107 | 108 | .. include:: /_fragments/next-step-to-wechat-mp.rst 109 | 110 | 参考文献 111 | ======== 112 | 113 | #. `Apache Tomcat 9 (9.0.8) - Documentation Index `_ 114 | 115 | .. include:: /_fragments/wechat-reward.rst 116 | 117 | .. include:: /_fragments/disqus.rst 118 | 119 | .. comments 120 | comment something out below 121 | 122 | :description lang=zh: 123 | 124 | -------------------------------------------------------------------------------- /docs/zh_CN/toolkit/index.rst: -------------------------------------------------------------------------------- 1 | .. 工具箱 2 | FileName: index.rst 3 | Author: Fasion Chan 4 | Created: 2018-01-27 11:25:09 5 | @contact: fasionchan@gmail.com 6 | @version: $Id$ 7 | 8 | Description: 9 | 10 | Changelog: 11 | 12 | 13 | ====== 14 | 工具箱 15 | ====== 16 | 17 | .. toctree:: 18 | :maxdepth: 1 19 | 20 | curl 21 | ifconfig 22 | ip 23 | iperf 24 | man 25 | nc 26 | rinetd 27 | route 28 | socat 29 | tcpdump 30 | 31 | .. comments 32 | comment something out here 33 | -------------------------------------------------------------------------------- /docs/zh_CN/toolkit/ip.rst: -------------------------------------------------------------------------------- 1 | .. ip 2 | FileName: ip.rst 3 | Author: Fasion Chan 4 | Created: 2018-01-28 10:16:41 5 | @contact: fasionchan@gmail.com 6 | @version: $Id$ 7 | 8 | Description: 9 | 10 | Changelog: 11 | 12 | .. meta:: 13 | :description lang=zh: 14 | ip 是一个用来查询或者维护、网络设备、策略路由以及隧道的网络工具。 15 | 本文通过详实例子,演示如何使用该命令进行网络管理。 16 | :keywords: ip命令, ip command, 网卡混杂模式 17 | 18 | == 19 | ip 20 | == 21 | 22 | `ip `_ 是一个用来查询或者维护 **路由** (``Routing`` )、 23 | **网络设备** ( ``Device`` )、 **策略路由** ( ``Policy Routing`` )以及 **隧道** ( ``Tunnel`` )的网络工具。 24 | 25 | 本文提供一些用法实例,详细文档请查看手册: `ip(8) - Linux manual page `_ ,或者命令行下运行 :doc:`man` 命令: 26 | 27 | .. code-block:: shell-session 28 | 29 | fasion@ubuntu:~/lnp$ man ip 30 | 31 | 网络设备 32 | ======== 33 | 34 | ``ip link`` 命令用于查询或者设置网络设备。 35 | 36 | 查看网卡信息 37 | ------------ 38 | 39 | .. code-block:: console 40 | 41 | fasion@ubuntu:~$ ip link show enp0s8 42 | 3: enp0s8: mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000 43 | link/ether 08:00:27:0e:18:e5 brd ff:ff:ff:ff:ff:ff 44 | 45 | 启用禁用 46 | -------- 47 | 48 | .. code-block:: console 49 | 50 | $ ip link set enp0s8 up 51 | 52 | .. code-block:: console 53 | 54 | $ ip link set enp0s8 down 55 | 56 | 网卡混杂模式 57 | ------------ 58 | 59 | 正常模式下,网卡将过滤目的 :ref:`mac-address` 不是自己的数据包。 60 | 在某些场景,比如网络嗅探,我们需要抓取并分析其他网络数据包。 61 | 这时,可以为网卡开启 :ref:`promisc-mode` 。 62 | 该模式开启后后,网卡将接受到达接口的所有数据包,不管 :ref:`mac-address` 是啥。 63 | 64 | 运行以下命令,为网卡 ``enp0s8`` 开启混杂模式: 65 | 66 | .. code-block:: console 67 | 68 | fasion@ubuntu:~$ sudo ip link set enp0s8 promisc on 69 | 70 | 操作完毕后,再次查询网卡状态,将看到 ``PROMISC`` 标识: 71 | 72 | .. code-block:: shell-session 73 | 74 | fasion@ubuntu:~$ ip link show enp0s8 75 | 3: enp0s8: mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000 76 | link/ether 08:00:27:0e:18:e5 brd ff:ff:ff:ff:ff:ff 77 | 78 | 地址 79 | ==== 80 | 81 | .. code-block:: shell-session 82 | 83 | fasion@ubuntu:~/lnp$ ip addr 84 | 1: lo: mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1 85 | link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 86 | inet 127.0.0.1/8 scope host lo 87 | valid_lft forever preferred_lft forever 88 | inet6 ::1/128 scope host 89 | valid_lft forever preferred_lft forever 90 | 2: enp0s3: mtu 1500 qdisc pfifo_fast state UP group default qlen 1000 91 | link/ether 08:00:27:4a:14:df brd ff:ff:ff:ff:ff:ff 92 | inet 10.0.2.15/24 brd 10.0.2.255 scope global enp0s3 93 | valid_lft forever preferred_lft forever 94 | inet6 fe80::a00:27ff:fe4a:14df/64 scope link 95 | valid_lft forever preferred_lft forever 96 | 3: enp0s8: mtu 1500 qdisc pfifo_fast state UP group default qlen 1000 97 | link/ether 08:00:27:c8:04:83 brd ff:ff:ff:ff:ff:ff 98 | inet 192.168.56.10/24 brd 192.168.56.255 scope global enp0s8 99 | valid_lft forever preferred_lft forever 100 | inet6 fe80::a00:27ff:fec8:483/64 scope link 101 | valid_lft forever preferred_lft forever 102 | 103 | .. code-block:: shell-session 104 | 105 | $ ip addr add 192.168.56.2/24 dev enp0s8 106 | 107 | 下一步 108 | ====== 109 | 110 | .. include:: /_fragments/next-step-to-wechat-mp.rst 111 | 112 | 参考文献 113 | ======== 114 | 115 | #. `ip(8) - Linux manual page `_ 116 | 117 | .. include:: /_fragments/wechat-reward.rst 118 | 119 | .. comments 120 | comment something out blow 121 | 122 | -------------------------------------------------------------------------------- /docs/zh_CN/toolkit/iperf.rst: -------------------------------------------------------------------------------- 1 | .. iperf 2 | FileName: iperf.rst 3 | Author: Fasion Chan 4 | Created: 2018-04-08 08:52:23 5 | @contact: fasionchan@gmail.com 6 | @version: $Id$ 7 | 8 | Description: 9 | 10 | Changelog: 11 | 12 | .. meta:: 13 | :description lang=zh: 14 | iperf是一个用来测量网络吞吐的工具。 15 | 它既可以测量TCP吞吐,也可以测量UDP吞吐。 16 | 使用iperf测量网络吞吐,用户需要一个接收并忽略流量的服务端以及一个生成测试流量的客户端。 17 | :keywords: iperf, 网络带宽测量, 网络吞吐测量 18 | 19 | ===== 20 | iperf 21 | ===== 22 | 23 | `iperf` 是一个用来 **测量网络吞吐** 的工具。 24 | 它既可以测量 `TCP` 吞吐,也可以测量 `UDP` 吞吐。 25 | 使用 `iperf` 测量网络吞吐,用户需要一个接收并忽略流量的服务端以及一个生成测试流量的客户端。 26 | 27 | 下文以 `TCP` 为例,演示使用 `iperf` 测量从 ``BlueServer`` 到 ``RedServer`` 的网络带宽: 28 | 29 | .. _iperf-server: 30 | 31 | 服务端 32 | ====== 33 | 34 | 在 ``RedServer`` 服务器上,运行 `iperf` 命令启动服务端: 35 | 36 | .. code-block:: shell-session 37 | 38 | fasion@RedServer:~$ iperf -s 39 | ------------------------------------------------------------ 40 | Server listening on TCP port 5001 41 | TCP window size: 85.3 KByte (default) 42 | ------------------------------------------------------------ 43 | 44 | 注意到, `iperf` 服务端默认监听 ``5001`` 端口, `TCP` 窗口大小为 `85.3 KB` 。 45 | 用户可根据需要调整,详情请查看 :ref:`iperf-references` 。 46 | 47 | .. _iperf-client: 48 | 49 | 客户端 50 | ====== 51 | 52 | 在 ``BlueServer`` 服务器上,运行 `iperf` 命令启动客户端: 53 | 54 | .. code-block:: shell-session 55 | 56 | fasionBlueServer:~$ iperf -c RedServer 57 | ------------------------------------------------------------ 58 | Client connecting to RedServer, TCP port 5001 59 | TCP window size: 85.0 KByte (default) 60 | ------------------------------------------------------------ 61 | [ 3 ] local 192.168.56.2 port 38517 connected with 192.168.1.3 port 5001 62 | 63 | 客户端连上服务端之后,便开始生产并发送测试流量了。 64 | 除了使用机器名,还可以直接指定 ``RedServer`` 的 `IP` 地址。 65 | 66 | .. _iperf-report: 67 | 68 | 测试报告 69 | ======== 70 | 71 | 测试完成后, `iperf` 向屏幕输出测试报告: 72 | 73 | .. code-block:: shell-session 74 | 75 | fasionBlueServer:~$ iperf -c RedServer 76 | ------------------------------------------------------------ 77 | Client connecting to RedServer, TCP port 5001 78 | TCP window size: 85.0 KByte (default) 79 | ------------------------------------------------------------ 80 | [ 3 ] local 192.168.56.2 port 38517 connected with 192.168.1.3 port 5001 81 | [ ID ] Interval Transfer Bandwidth 82 | [ 3 ] 0.0-11.4 sec 2.38 MBytes 1.75 Mbits/sec 83 | 84 | 从报告中可以得知,客户端在大约 ``12`` 秒的时间内,发送了 `2.38 MB` 数据,平均带宽是 `1.75 Mb/s` 。 85 | 服务端也会输出测试报告,格式是一样的,不再赘述。 86 | 87 | 下一步 88 | ====== 89 | 90 | .. include:: /_fragments/next-step-to-wechat-mp.rst 91 | 92 | .. _iperf-references: 93 | 94 | 参考文献 95 | ======== 96 | 97 | #. `iperf(1) - Linux manual page `_ 98 | 99 | .. include:: /_fragments/wechat-reward.rst 100 | 101 | .. include:: /_fragments/disqus.rst 102 | 103 | .. comments 104 | comment something out below 105 | 106 | .. meta:: 107 | :description lang=zh: 108 | :keywords: 109 | 110 | -------------------------------------------------------------------------------- /docs/zh_CN/toolkit/man.rst: -------------------------------------------------------------------------------- 1 | .. man 2 | FileName: man.rst 3 | Author: Fasion Chan 4 | Created: 2018-01-28 14:35:22 5 | @contact: fasionchan@gmail.com 6 | @version: $Id$ 7 | 8 | Description: 9 | 10 | Changelog: 11 | 12 | === 13 | man 14 | === 15 | 16 | 需要使用某个命令,却忘记了用法? 17 | 代码写了一半,想不起某个系统调用的用法? 18 | 很不幸,这种囧事几乎每天都有…… 19 | 20 | 没事,`Google `_ 一下呗。 21 | 22 | 除此之外,还有更便捷的方式:运行 ``man`` 命令查看 `手册页 `_ ( ``Manual pages`` )。 23 | 手册页是 ``Linux/Unix`` 软件文档的一种常用形式,涵盖:命令、系统调用、库函数等方方面面。 24 | 25 | 以查看 ``socket`` 系统调用手册为例,命令行下运行: 26 | 27 | .. code-block:: shell-session 28 | :linenos: 29 | 30 | fasion@ubuntu:~/lnp$ man socket 31 | 32 | 回车按下后,手册来了: 33 | 34 | .. figure:: /_images/toolkit/man/5dfc3c544562c605f94c8949f87ff6b6.png 35 | 36 | 如上图,系统调用需要引入的 **头文件** , **参数** 类似及含义, **返回值** 等等一目了然。 37 | 38 | 注意到, ``man`` 提供了 ``less`` 终端分页器,在文档较长时非常有用。 39 | 按 ``j`` 往下滚动,按 ``k`` 往上滚动; 40 | 按 ``-f`` 向下翻页,按 ``-b`` 向上翻页; 41 | 按 ``gg`` 回到开头,按 ``G`` 跳到结尾处。 42 | ``vim`` 用户应该非常熟悉! 43 | 44 | 如果忘记了 ``man`` 命令的用法,还可以用 ``man`` 查自己的手册: 45 | 46 | .. code-block:: shell-session 47 | :linenos: 48 | 49 | fasion@ubuntu:~/lnp$ man man 50 | 51 | 章节 52 | ==== 53 | 54 | ``Linux`` 下,手册通常分为 ``8`` 个章节( ``Section`` ),见表格-1: 55 | 56 | .. csv-table:: 表格-1 手册页章节 57 | :header: "章节", "说明" 58 | :widths: 10 40 59 | 60 | "1", "一般命令" 61 | "2", "系统调用" 62 | "3", "库函数,涵盖C标准函数库" 63 | "4", "特殊文件(通常是/dev中的设备文件)和驱动程序" 64 | "5", "文件格式和约定" 65 | "6", "游戏和屏保" 66 | "7", "杂项" 67 | "8", "系统管理命令和守护进程" 68 | "9", "内核例程" 69 | 70 | 不同的章节,可能有同名的手册。 71 | ``printf`` 就是一例,章节 ``1`` 提供 ``printf`` 命令的手册;章节 ``3`` 提供 ``printf`` 库函数的手册。 72 | 这种情况下,如果直接运行 ``man printf`` ,显示的是命令 ``printf`` 的手册。 73 | 对于 ``C`` 库函数,需要指定章节: 74 | 75 | .. code-block:: shell-session 76 | :linenos: 77 | 78 | fasion@ubuntu:~/lnp$ man 3 printf 79 | 80 | .. comments 81 | comment something out blow 82 | 83 | -------------------------------------------------------------------------------- /docs/zh_CN/toolkit/rinetd.rst: -------------------------------------------------------------------------------- 1 | .. rinetd 2 | FileName: rinetd.rst 3 | Author: Fasion Chan 4 | Created: 2018-09-27 19:27:58 5 | @contact: fasionchan@gmail.com 6 | @version: $Id$ 7 | 8 | Description: 9 | 10 | Changelog: 11 | 12 | .. meta:: 13 | :description lang=zh: 14 | :keywords: 15 | 16 | ====== 17 | rinetd 18 | ====== 19 | 20 | 进行网络编程、服务部署时,经常需要临时对一些端口进行转发。 21 | 22 | 举个例子,笔者开发过一个 `Agent` 软件—— 23 | 它部署于集群每台服务器上,对其上的某个服务进行管理,需要连接服务端口。 24 | 我在本地进行开发,需要部署一套相同的服务,这多少有些麻烦。 25 | 如果可以在本地部署端口转发服务,监听服务端口,将请求转发至部署有该服务的测试机,便可完美解决问题。 26 | 27 | 端口转发方案很多,:doc:`/services/ssh-port-forwarding` , `NAT` 端口转发,甚至 :doc:`/services/haproxy` 之类的工具都可以排上用场。 28 | 然而,应对开发调试这种 **临时需求** , `rinetd`_ 就能胜任,它足够简单轻量级,依赖也少。 29 | 30 | .. warning:: 31 | 32 | 请不要将 `rinetd`_ 应用到生产服务! 33 | 34 | `rinetd`_ 底层采用 `select` 而不是 `epoll` 实现。 35 | 众所周知, `select` 有致命缺陷,一次能处理的 `文件描述符`_ (套接字)非常有限,效率也比较低下。 36 | 37 | 因此,**在高并发环境采用rinetd无异于自杀** 。 38 | 39 | 更多细节可参考文章:`rinetd 在生产环境要谨慎使用 `_ 。 40 | 41 | 安装 42 | ==== 43 | 44 | `rinetd`_ 可以运行在任何 `Unix` 系统中,但系统一般没有预装,需要用户自己动手。 45 | 46 | 安装也简单,只需视系统运行包管理工具。以 `Debian` 为例: 47 | 48 | .. code-block:: shell-session 49 | 50 | $ apt install rinetd 51 | 52 | 笔者在 `OSX` 系统开发,则可以使用 `brew` 来安装: 53 | 54 | .. code-block:: shell-session 55 | 56 | $ brew install rinetd 57 | 58 | .. note:: 59 | 60 | 顺便提一下,笔者使用 `brew` 安装 `rinetd`_ 时,出现一些错误——提示不能写入 `/usr/local/sbin` 目录。 61 | 62 | 看了一眼该目录,根本就不存在!这种情况可以自己建好 `/usr/local/sbin` 再试,所属用户、所属组以及权限可以参考 `/usr/local/bin` 。 63 | 64 | 配置 65 | ==== 66 | 67 | 运行 `rinetd`_ 前,需要先准备一个配置文件。 68 | 配置文件非常简单,主要包含 :ref:`rinetd-forwarding-rules` 、 :ref:`rinetd-access-rules` 以及 :ref:`rinetd-logging-rules` 。 69 | 70 | .. _rinetd-forwarding-rules: 71 | 72 | 转发规则 73 | -------- 74 | 75 | 转发规则定义了监听什么端口,以及转发到哪个目标地址上的哪个端口。形式如下: 76 | 77 | .. code-block:: text 78 | 79 | bindaddress bindport connectaddress connectport 80 | 81 | 其中, `bindaddress` 是 **绑定地址** ; `bindport` 是 **绑定端口** (监听端口);`connectaddress` 是 **目标地址** ; `connectport` 是 **目标端口** 。 82 | 83 | 举个例子: 84 | 85 | .. code-block:: text 86 | 87 | 206.125.69.81 80 10.1.1.2 80 88 | 89 | 这个配置告诉 `rinetd`_ 监听本地端口 `206.125.69.81:80` ,然后将请求转发到内网机器 `10.1.1.2` 的 `80` 端口。 90 | 91 | .. _rinetd-access-rules: 92 | 93 | 访问控制规则 94 | ------------ 95 | 96 | 访问控制规则规定了哪些来源 `IP` 可以连接。 97 | 98 | 访问控制规则可以分成两种: **放行规则** ( `allow rules` )以及 **禁止规则** ( `allow rules` )。 99 | 只要定义了放行规则,任何不匹配的来源 `IP` 将被拒绝连接; 100 | 只要定义了禁止规则,任何匹配的来源 `IP` 将被拒绝连接。 101 | 102 | 此外,访问控制规则还定义了两种不同的 **作用范围** : 103 | 104 | #. 写在 :ref:`rinetd-forwarding-rules` 之前的是 **全局规则** ,对所有转发规则均有效; 105 | #. 写在某条转发规则后的,则只对当前转发规则有效。 106 | 107 | 回过头来看看访问控制规则怎么写: 108 | 109 | .. code-block:: text 110 | 111 | allow pattern 112 | deny pattern 113 | 114 | 其中, `pattern` 为来源 `IP` 模式。例如: 115 | 116 | .. code-block:: text 117 | 118 | allow 206.125.69.* 119 | 120 | 这条规则指示对来源 `IP` 在 `206.125.69.0/24` 这个段内的所有连接放行。 121 | 122 | .. _rinetd-logging-rules: 123 | 124 | 日志输出规则 125 | ------------ 126 | 127 | 日志输出规则定义日志输出文件以及格式: 128 | 129 | .. code-block:: text 130 | 131 | logfile /var/log/rinetd.log 132 | logcommon 133 | 134 | 完整示例 135 | -------- 136 | 137 | .. code-block:: text 138 | 139 | logfile /var/log/rinetd.log 140 | logcommon 141 | 142 | allow 10.*.*.* 143 | 144 | 206.125.69.81 80 10.1.1.2 80 145 | allow 206.125.69.* 146 | 147 | 10.101.1.2 3306 10.1.1.10 3306 148 | 149 | 部署 150 | ==== 151 | 152 | 准备好配置文件后,通过 `-c` 选项启动 `rinetd` 命令即可: 153 | 154 | .. code-block:: shell-session 155 | 156 | $ rinetd -c /etc/rinetd.conf 157 | 158 | .. note:: 159 | 160 | 注意到,程序启动后便退出了。 161 | 这是因为, `rinetd`_ 以后台进程( `守护进程`_ )的形式运行服务。 162 | 执行 `ps aux | grep rinetd` 命令,可以找到该进程。 163 | 164 | .. warning:: 165 | 166 | 再次强调,请不要将 `rinetd`_ 应用到生产服务! 167 | 168 | `rinetd`_ 底层采用 `select` 而不是 `epoll` 实现。 169 | 众所周知, `select` 有致命缺陷,一次能处理的 `文件描述符`_ (套接字)非常有限,效率也比较低下。 170 | 171 | 因此,**在高并发环境采用rinetd无异于自杀** 。 172 | 173 | 更多细节可参考文章:`rinetd 在生产环境要谨慎使用 `_ 。 174 | 175 | 下一步 176 | ====== 177 | 178 | .. include:: /_fragments/next-step-to-wechat-mp.rst 179 | 180 | 参考文献 181 | ======== 182 | 183 | #. `RINETD(8) `_ 184 | 185 | .. include:: /_fragments/wechat-reward.rst 186 | 187 | .. include:: /_fragments/disqus.rst 188 | 189 | 190 | .. _守护进程: https://learn-linux.readthedocs.io/zh_CN/latest/system-programming/daemon/index.html 191 | .. _文件描述符: https://learn-linux.readthedocs.io/zh_CN/latest/system-programming/file-io/file-descriptor.html 192 | .. _rinetd: https://www.boutell.com/rinetd/ 193 | 194 | .. comments 195 | comment something out below 196 | 197 | -------------------------------------------------------------------------------- /docs/zh_CN/toolkit/socat.rst: -------------------------------------------------------------------------------- 1 | .. socat 2 | FileName: socat.rst 3 | Author: Fasion Chan 4 | Created: 2019-02-20 18:55:14 5 | @contact: fasionchan@gmail.com 6 | @version: $Id$ 7 | 8 | Description: 9 | 10 | Changelog: 11 | 12 | .. meta:: 13 | :description lang=zh: 14 | socat(SOcketCAT)是一个多用途双向数据转接工具。 15 | socat功能跟NetCat一样,但更安全(支持chroot),兼容多种协议, 16 | 支持操作文件(file)、管道(pipe)、设备(device)、TCP套接字、Unix套接字、 17 | SOCKS客户端、CONNECT代理以及SSL等等。 18 | :keywords: socat, 端口转发, tcp, udp, port forward 19 | 20 | ===== 21 | socat 22 | ===== 23 | 24 | `socat`_ ( `SOcket CAT` )是一个多用途双向数据转接工具。 25 | 26 | `socat`_ 功能跟 :doc:`NetCat ` 一样,但更安全(支持 `chroot` ),兼容多种协议, 27 | 支持操作 **文件** ( `file` )、 **管道** ( `pipe` )、 **设备** ( `device` )、 28 | `TCP` 套接字、 `Unix` 套接字、 `SOCKS` 客户端、 `CONNECT` 代理以及 `SSL` 等等。 29 | 30 | 安装 31 | ==== 32 | 33 | Linux 34 | ----- 35 | 36 | 在 `Linux` 系统,使用包管理器进行安装,以 `Debian/Ubuntu` 为例: 37 | 38 | .. code-block:: shell-session 39 | 40 | # apt update && apt install socat 41 | 42 | OSX 43 | --- 44 | 45 | 在 `OSX` 系统,使用装包神奇 `brew` 进行安装: 46 | 47 | .. code-block:: shell-session 48 | 49 | $ brew update && brew install socat 50 | 51 | 典型用法 52 | ======== 53 | 54 | 端口转发 55 | -------- 56 | 57 | TCP 58 | +++ 59 | 60 | 监听本地 *80* 端口,并将请求转发(代理)到 *10.0.0.1:8080* 上: 61 | 62 | .. code-block:: shell-session 63 | 64 | # socat TCP-LISTEN:80,reuseaddr,fork TCP:10.0.0.1:8080 65 | 66 | UDP 67 | +++ 68 | 69 | 监听本地 *53* 端口,并将请求转发(代理)到 *10.0.0.1:5353* 上: 70 | 71 | .. code-block:: shell-session 72 | 73 | # socat UDP-LISTEN:53,reuseaddr,fork UDP:10.0.0.1:5353 74 | 75 | .. comments 76 | comment something out below 77 | 78 | -------------------------------------------------------------------------------- /docs/zh_CN/toolkit/tcpdump.rst: -------------------------------------------------------------------------------- 1 | .. tcpdump 2 | FileName: tcpdump.rst 3 | Author: Fasion Chan 4 | Created: 2018-01-28 20:20:59 5 | @contact: fasionchan@gmail.com 6 | @version: $Id$ 7 | 8 | Description: 9 | 10 | Changelog: 11 | 12 | .. meta:: 13 | :description lang=zh: 14 | tcpdump是一个网络抓包工具,用于嗅探经过主机的网络报文,排查问题时非常有用。 15 | 本文介绍tcpdump的基本用法,并提供大量典型示例。 16 | :keywords: tcpdump, 抓包工具, 17 | 18 | ======= 19 | tcpdump 20 | ======= 21 | 22 | `tcpdump`_ 是一个 **网络抓包** 工具,用于嗅探经过主机的网络报文,排查问题时非常有用。 23 | 本文介绍 `tcpdump` 的 **基本用法** ,并提供大量 **典型示例** 。 24 | 25 | 基本用法 26 | ======== 27 | 28 | 抓取经过 `enp0s3` :ref:`nic` *80* 端口的报文: 29 | 30 | .. code-block:: shell-session 31 | 32 | $ tcpdump -ni enp0s3 port 80 33 | 34 | 其中, *-n* 表示不将地址转化成名字,这个选项在网络工具中很常见, :doc:`ip` 、 `ping` 、 `ss` 等命令也有。 35 | *-i* 选项指定所嗅探的 **网络设备** ; 36 | *port 80* 是一个 **表达式** ( `expression` ),用于过滤报文,表示只输出端口为 *80* 的报文。 37 | 38 | .. note:: 39 | 40 | 网络工具命令一般通过 `DNS` 反解将 `IP` 地址转化成域名输出展示。 41 | `DNS` 查询有一定耗时,特别是记录查询失败时,因此命令输出可能会有明显延迟。 42 | 43 | 例如,运行 `ping` 命令时, `ICMP` 回显答复报文已经收到,而命令却还没输出。 44 | 这种卡顿现象只需指定 *-n* 选项即可解决。 45 | 46 | 典型示例 47 | ======== 48 | 49 | 嗅探环回流量, *-i* 指定环回设备 `lo` : 50 | 51 | .. code-block:: shell-session 52 | 53 | $ tcpdump -ni lo 54 | 55 | 嗅探所有网络流量, *-i* 指定任意网络设备,为特殊关键字 *any* : 56 | 57 | .. code-block:: shell-session 58 | 59 | $ tcpdump -ni any 60 | 61 | 通过表达式过滤 `ICMP` 协议流量: 62 | 63 | .. code-block:: shell-session 64 | 65 | $ tcpdump -ni any icmp 66 | 67 | 通过表达式过滤给定主机( `IP` 地址)的流量: 68 | 69 | .. code-block:: shell-session 70 | 71 | $ tcpdump -ni any host 10.0.1.2 72 | 73 | 过滤给定主机 *80* 端口的流量: 74 | 75 | .. code-block:: shell-session 76 | 77 | $ tcpdump -ni any host 10.0.1.2 and port 80 78 | 79 | 匹配 `TCP` 分组标志位,以 `SYN` 为例: 80 | 81 | .. code-block:: shell-session 82 | 83 | $ tcpdump -ni any port 443 and "tcp[tcpflags] & tcp-syn != 0" 84 | 85 | 下一步 86 | ====== 87 | 88 | .. include:: /_fragments/next-step-to-wechat-mp.rst 89 | 90 | 参考文献 91 | ======== 92 | 93 | #. `tcpdump(1) - Linux manual page `_ 94 | 95 | .. _tcpdump: http://man7.org/linux/man-pages/man1/tcpdump.1.html 96 | 97 | .. include:: /_fragments/wechat-reward.rst 98 | 99 | .. include:: /_fragments/comment-system.rst 100 | 101 | .. comments 102 | comment something out blow 103 | 104 | -------------------------------------------------------------------------------- /docs/zh_CN/translations/cap-theorem-and-distributed-database-management-systems.rst: -------------------------------------------------------------------------------- 1 | .. 2 | Author: fasion 3 | Created time: 2019-09-25 09:10:52 4 | Last Modified by: fasion 5 | Last Modified time: 2019-09-25 15:32:10 6 | 7 | .. meta:: 8 | :description lang=zh: 9 | 为了选择最优数据处理工具,需要对CAP定理有一个基本认识。 10 | CAP定理指出,对于一个分布式系统,无法同时满足一致性、可用性以及分区容错性。 11 | :keywords: CAP theorem, CAP理论, 一致性, 可用性, 分区容错性, 数据库管理系统, DBMS 12 | 13 | ============================= 14 | CAP定理与分布式数据库管理系统 15 | ============================= 16 | 17 | .. note:: 18 | 19 | 本文译自:`CAP Theorem and Distributed Database Management Systems `_ 20 | 21 | 早年间提升 **数据存储规模** 以及 **系统处理能力** 的手段多为 **垂直扩容** ( `scale vertically` ), 22 | 即采用性能更高的服务器,或者优化现有代码。 23 | 24 | 然而,随着 **并行处理** ( `parallel processing` )以及 **分布式系统** ( `distributed system` )优势日益显现, 25 | **水平扩容** ( `scale horizontally` )更加流行,即用更多服务器并行地处理任务。 26 | 27 | .. figure:: /_images/translations/cap-theorem-and-distributed-database-management-systems/41ac78eba143a642a487a7e11092c2fb.jpeg 28 | :width: 480px 29 | 30 | `Apache` 项目涌现了大量数据处理工具,包括 `Spark`_ 、 `Hadoop`_ 、 `Kafka`_ 、 `Zookeeper`_ 以及 `Storm`_ 等等。 31 | 为了选择最优数据处理工具,需要对 :doc:`/distributed/cap-theorem` 有一个基本认识。 32 | CAP定理指出,对于一个 **分布式系统** ,无法同时满足 **一致性** ( `Consistency` )、 **可用性** ( `Availability` )以及 **分区容错性** ( `Partition tolerance` )。 33 | 34 | .. figure:: /_images/translations/cap-theorem-and-distributed-database-management-systems/2b4954e5f88028a22c36dd62f4850832.png 35 | :width: 333px 36 | 37 | :doc:`/distributed/cap-theorem` 38 | 在大数据领域非常重要,特别是需要根据使用场景对三点进行权衡时。 39 | 这篇博客,我将重点阐述 *CAP* 这三个概念以及抉择考量。 40 | 由于 **数据库管理系统** ( `DBMS` )发展迅猛,我避免将讨论局限在某个特定系统。 41 | 42 | 分区容错性 43 | ========== 44 | 45 | .. figure:: /_images/translations/cap-theorem-and-distributed-database-management-systems/4b8685b22f8665a961ac6a87da8595c5.png 46 | 47 | 这个条件要求,不管多少消息被节点间网络延迟,系统必须持续运作。 48 | 一个分区容错的系统,可以容忍任意数量的网络故障,只要不是整个网络都挂掉。 49 | 数据记录需要充分复制,覆盖各种节点、网络组合,保证系统在网络短暂中断时能够正常服务。 50 | 设计现代分布式系统时,分区容错性不是一个选择,而是一个必选项。 51 | 因此,我们需要在一致性和可用性间做选择。 52 | 53 | 一致性 54 | ====== 55 | 56 | .. figure:: /_images/translations/cap-theorem-and-distributed-database-management-systems/bd690aa7a6d02942ed9b66ec2e0cd329.png 57 | 58 | 这个条件要求,同一时间所有节点都看到相同的数据。 59 | 简而言之,一个读操作必须返回最近写操作写入的值,所有节点都返回相同的数据。 60 | 如果系统在一致状态下开始事务,事务保证其结束后系统状态也是一致的,系统便满足一致性。 61 | 在这个模型中,系统可能在事务中进入不一致状态,但是不管事务在哪个执行阶段出错,均可回滚。 62 | 63 | 如上图,在不同的时间写入两个不同的数据记录( `Bulbasaur` `Pikachu` )。 64 | 一致性要求任意节点可以读到 `Pikachu` ,也就是最后写入的值。 65 | 然而,其他节点更新数据需要时间,网络中将经常有节点不可用。 66 | 67 | 可用性 68 | ====== 69 | 70 | .. figure:: /_images/translations/cap-theorem-and-distributed-database-management-systems/202900b8dd5509bfc006cc006a62ccd7.png 71 | 72 | 这个条件要求,每个请求都得到相应,不过成功还是失败。 73 | 想达到可用性要求,分布式系统必须在服务时间内 *100%* 可用。 74 | 每个客户端请求都能得到响应,不管集群内节点状态如何。 75 | 评价指标很直观:你是否可以提交读、写操作命令。 76 | 77 | 这意味着,与上一例子不同,我们无法得知 `Pikachu` 还是 `Bulbasaur` 先写,结果可以是二者之一。 78 | 因此,在高频率流式数据分析场景,可用性不太可行。 79 | 80 | 结论 81 | ==== 82 | 83 | **分布式系统** 让我们可以达到过去无法想象的 **计算能力** 和 **可用性水平** 。 84 | 现在我们有很多 **高性能** 、 **低延迟** 、接近 **百分百可用** 的系统,跑在全球范围内不同的数据中心。 85 | 最重要的是,现在的系统可以跑在商用硬件上,容易获得、可配置,而且价格也不高。 86 | 87 | 然而,代价也是有的。分布式系统比单机系统更加复杂。 88 | 因此,想更好掌握 **水平扩容** 技巧,你需要理解分布式系统带来的 **复杂性** , 89 | 根据开发任务在 `CAP` 中取舍,并为其选择正确的工具。 90 | 91 | 下一步 92 | ====== 93 | 94 | .. include:: /_fragments/next-step-to-wechat-mp.rst 95 | 96 | .. include:: /_fragments/wechat-reward.rst 97 | 98 | .. include:: /_fragments/disqus.rst 99 | 100 | .. _Spark: https://spark.apache.org/ 101 | .. _Hadoop: https://hadoop.apache.org/ 102 | .. _Kafka: https://kafka.apache.org/ 103 | .. _Zookeeper: https://zookeeper.apache.org/ 104 | .. _Storm: https://storm.apache.org/ 105 | 106 | .. comments 107 | comment something out below 108 | 109 | -------------------------------------------------------------------------------- /docs/zh_CN/translations/index.rst: -------------------------------------------------------------------------------- 1 | .. 译文 2 | FileName: index.rst 3 | Author: Fasion Chan 4 | Created: 2018-10-09 20:53:04 5 | @contact: fasionchan@gmail.com 6 | @version: $Id$ 7 | 8 | Description: 9 | 10 | Changelog: 11 | 12 | 译文 13 | ==== 14 | 15 | .. toctree:: 16 | :titlesonly: 17 | 18 | CAP定理与分布式数据管理系统 19 | 深入理解Linux TCP backlog 20 | Raft算法论文 21 | socat - Linux/Unix TCP 端口转发 22 | 23 | .. comments 24 | comment something out below 25 | 26 | -------------------------------------------------------------------------------- /docs/zh_CN/translations/socat-linux-unix-tcp-port-forwarding.rst: -------------------------------------------------------------------------------- 1 | .. socat - Linux/Unix TCP 端口转发 2 | FileName: socat-linux-unix-tcp-port-forwarding.rst 3 | Author: Fasion Chan 4 | Created: 2019-02-20 18:59:10 5 | @contact: fasionchan@gmail.com 6 | @version: $Id$ 7 | 8 | Description: 9 | 10 | Changelog: 11 | 12 | .. meta:: 13 | :description lang=zh: 14 | socat功能跟NetCat一样,但更安全(支持chroot),兼容多种协议,支持操作文件(file)、管道(pipe)、设备(device)、TCP套接字、Unix套接字、SOCKS客户端、CONNECT代理以及SSL等等。 15 | :keywords: socat, port forwarding, tcp, linux, unix, 端口转发 16 | 17 | =============================== 18 | socat - Linux/Unix TCP 端口转发 19 | =============================== 20 | 21 | 不用 **防火墙** ( `firewall` )软件, `Linux/Unix` 系统能否实现 **端口转发** ( `port-forwarding` )呢? 22 | `socat`_ ( `SOcket CAT` )是一个多用途双向数据转接工具,在 `Linux`_ 系统中如何安装? 23 | 24 | `socat`_ 功能跟 :doc:`NetCat ` 一样,但更安全(支持 `chroot` ),兼容多种协议, 25 | 支持操作 **文件** ( `file` )、 **管道** ( `pipe` )、 **设备** ( `device` )、 26 | `TCP` 套接字、 `Unix` 套接字、 `SOCKS` 客户端、 `CONNECT` 代理以及 `SSL` 等等。 27 | 28 | .. note:: 29 | 30 | 本文译自:`socat: Linux / UNIX TCP Port Forwarder `_ 31 | 32 | 典型用途 33 | ======== 34 | 35 | #. `TCP` **端口转发** ( `port forwarding` ); 36 | #. 外网留痕; 37 | #. 攻击弱防火墙(安全测试); 38 | #. `Unix` 套接字的 `shell` 操作接口; 39 | #. `IPv6` 转接; 40 | #. 安全测试和研究; 41 | 42 | 安装 43 | ==== 44 | 45 | `Debian/Ubuntu` 下,只需执行 `apt` 命令: 46 | 47 | .. code-block:: shell-session 48 | 49 | $ sudo apt update && sudo apt install socat 50 | 51 | .. warning:: 52 | 53 | 以下示例命令可能在你的电脑上 **开端口** 或者通过 **套接字** 连接其他互联网用户。 54 | 使用这个工具必须有 `TCP/IP` 以及 `Unix` 网络方面的知识。 55 | 56 | 端口转发 57 | ======== 58 | 59 | 将 *80* 端口转发到 *202.54.1.5* : 60 | 61 | .. code-block:: shell-session 62 | 63 | # socat TCP-LISTEN:80,fork TCP:202.54.1.5:80 64 | 65 | *TCP-LISTEN:80* 表示监听本地 *80* 端口; `fork` 表示创建子进程处理新连接; 66 | *TCP:202.54.1.5:80* 表示将新连接转发到 *202.54.1.5:80* 。 67 | 68 | 经过以上命令,所有到 *80* 端口的 `TCP` 连接将被转发到 *202.54.1.5* ,与 :doc:`netcat ` 一样。 69 | 70 | 连接SSH服务器 71 | ============= 72 | 73 | 你可以连到远程 `SSH` 服务器( `server1` ),使用 `pty` 作为 `socat`_ 和 `ssh` 的通讯方式, 74 | 并将其作为 `ssh` 的控制 `tty` ( `ctty` ),并将 `pty` 作为新进程组所有者( `setsid` ), 75 | 这样 `ssh` 可以从 `socat` 获取密码。 76 | 77 | 78 | .. code-block:: shell-session 79 | 80 | $ (sleep 5; echo YOURSSHPASSWORDHERE; sleep 5; echo date; sleep 1) | \ 81 | socat - EXEC:'ssh -l userName server1.nixcraft.net.in',pty,setsid,ctty 82 | 83 | 操作Unix套接字 84 | ============== 85 | 86 | `Unix` 套接字是非常常见的本地通讯方式,但是能够操作这类套接字的工具命令不多, 87 | :doc:`/toolkit/socat` 是其中一个。 88 | 下面这个例子,通过 `HAProxy` 的 `Unix` 套接字,获取其运行信息,包含 `PID` 、启动时间等: 89 | 90 | .. code-block:: shell-session 91 | 92 | # echo "show info" | socat unix-connect:/var/tmp/haproxy stdio 93 | 94 | 高级端口转发 95 | ============ 96 | 97 | .. code-block:: shell-session 98 | 99 | # socat -d -d -lmlocal2 \ 100 | TCP4-LISTEN:80,bind=myaddr1,su=nobody,fork,range=10.0.0.0/8,reuseaddr \ 101 | TCP4:www.nixcraft.net.in:80,bind=myaddr2 102 | 103 | 这个例子在 `accept()` `系统调用`_ 后 `fork` 子进程进行处理,因此可同时处理多个并发连接。 104 | 安全性方面也有所提高: `fork` 后 `su` 到 `nobody` 用户,避免权限泄露; 105 | 只允许来自 *10.0.0.0/8* 网段的连接。 106 | 由于设置了 `reuseaddr` ,就算子进程套接字还没有完全关闭,主进程退出即可重启。 107 | 由于指定 *-lmlocal2* 选项, `accept` 循环前日志将输出到 `stderr` 。 108 | 后续的日志以 *local2* 为标识转发到 *syslog* 。 109 | 110 | 下一步 111 | ====== 112 | 113 | .. include:: /_fragments/next-step-to-wechat-mp.rst 114 | 115 | 参考文献 116 | ======== 117 | 118 | #. `socat(1): Multipurpose relay - Linux man page `_ 119 | #. `socat 项目 `_ 120 | 121 | .. include:: /_fragments/wechat-reward.rst 122 | 123 | .. include:: /_fragments/disqus.rst 124 | 125 | .. _linux: https://learn-linux.readthedocs.io/zh_CN/latest/ 126 | .. _socat: https://linux.die.net/man/1/socat 127 | .. _系统调用: https://learn-linux.readthedocs.io/zh_CN/latest/system-programming/syscall/principle.html 128 | 129 | .. comments 130 | comment something out below 131 | 132 | -------------------------------------------------------------------------------- /readthedocs.yml: -------------------------------------------------------------------------------- 1 | formats: [] 2 | requirements_file: requirements/docs.txt 3 | -------------------------------------------------------------------------------- /requirements/docs-dev.txt: -------------------------------------------------------------------------------- 1 | sphinx-autobuild==0.7.1 2 | -------------------------------------------------------------------------------- /requirements/docs.txt: -------------------------------------------------------------------------------- 1 | sphinx-sitemap==0.3.1 2 | -------------------------------------------------------------------------------- /src/c/.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Object files 5 | *.o 6 | *.ko 7 | *.obj 8 | *.elf 9 | 10 | # Linker output 11 | *.ilk 12 | *.map 13 | *.exp 14 | 15 | # Precompiled Headers 16 | *.gch 17 | *.pch 18 | 19 | # Libraries 20 | *.lib 21 | *.a 22 | *.la 23 | *.lo 24 | 25 | # Shared objects (inc. Windows DLLs) 26 | *.dll 27 | *.so 28 | *.so.* 29 | *.dylib 30 | 31 | # Executables 32 | *.exe 33 | *.out 34 | *.app 35 | *.i*86 36 | *.x86_64 37 | *.hex 38 | 39 | # Debug files 40 | *.dSYM/ 41 | *.su 42 | *.idb 43 | *.pdb 44 | 45 | # Kernel Module Compile Results 46 | *.mod* 47 | *.cmd 48 | .tmp_versions/ 49 | modules.order 50 | Module.symvers 51 | Mkfile.old 52 | dkms.conf 53 | -------------------------------------------------------------------------------- /src/c/endianness/endianness.c: -------------------------------------------------------------------------------- 1 | /** 2 | * FileName: endianness.c 3 | * Author: Fasion Chan 4 | * @contact: fasionchan@gmail.com 5 | * @version: $Id$ 6 | * 7 | * Description: 8 | * 9 | * Changelog: 10 | * 11 | **/ 12 | 13 | #include 14 | 15 | int main() 16 | { 17 | int value = 1; 18 | if (((char*)&value)[0]) { 19 | printf("Little endian\n"); 20 | } 21 | else { 22 | printf("Big endian\n"); 23 | } 24 | 25 | return value; 26 | } 27 | -------------------------------------------------------------------------------- /src/c/endianness/show.c: -------------------------------------------------------------------------------- 1 | /** 2 | * FileName: show.c 3 | * Author: Fasion Chan 4 | * @contact: fasionchan@gmail.com 5 | * @version: $Id$ 6 | * 7 | * Description: 8 | * 9 | * Changelog: 10 | * 11 | **/ 12 | 13 | #include 14 | 15 | void show_mem_rep(unsigned char* start, int n) 16 | { 17 | // show bytes one by one from start to start+n 18 | int i; 19 | for (i=0; i 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | 20 | /** 21 | * Convert binary MAC address to readable format. 22 | * 23 | * Arguments 24 | * n: binary format, must be 6 bytes. 25 | * 26 | * a: buffer for readable format, 18 bytes at least(`\0` included). 27 | **/ 28 | void mac_ntoa(unsigned char *n, char *a) { 29 | // traverse 6 bytes one by one 30 | for (int i=0; i<6; i++) { 31 | // format string 32 | char *format = ":%02x"; 33 | 34 | // first byte without leading `:` 35 | if(0 == i) { 36 | format = "%02x"; 37 | } 38 | 39 | // format current byte 40 | a += sprintf(a, format, n[i]); 41 | } 42 | } 43 | 44 | 45 | int main(int argc, char *argv[]) { 46 | // create a socket, any type is ok 47 | int s = socket(AF_INET, SOCK_STREAM, 0); 48 | if (-1 == s) { 49 | perror("Fail to create socket"); 50 | return 1; 51 | } 52 | 53 | // fill iface name to struct ifreq 54 | struct ifreq ifr; 55 | strncpy(ifr.ifr_name, argv[1], 15); 56 | 57 | // call ioctl to get hardware address 58 | int ret = ioctl(s, SIOCGIFHWADDR, &ifr); 59 | if (-1 == ret) { 60 | perror("Fail to get mac address"); 61 | return 2; 62 | } 63 | 64 | // convert to readable format 65 | char mac[18]; 66 | mac_ntoa((unsigned char *)ifr.ifr_hwaddr.sa_data, mac); 67 | 68 | // output result 69 | printf("IFace: %s\n", ifr.ifr_name); 70 | printf("MAC: %s\n", mac); 71 | 72 | return 0; 73 | } 74 | -------------------------------------------------------------------------------- /src/c/tcp/clock/Makefile: -------------------------------------------------------------------------------- 1 | # FileName: Makefile 2 | # Author: Fasion Chan 3 | # @contact: fasionchan@gmail.com 4 | # @version: $Id$ 5 | # 6 | # Description: 7 | # 8 | # Changelog: 9 | # 10 | 11 | server: server.c 12 | gcc -o $@ $^ 13 | -------------------------------------------------------------------------------- /src/c/udp/echo/Makefile: -------------------------------------------------------------------------------- 1 | # FileName: Makefile 2 | # Author: Fasion Chan 3 | # @contact: fasionchan@gmail.com 4 | # @version: $Id$ 5 | # 6 | # Description: 7 | # 8 | # Changelog: 9 | # 10 | 11 | server: server.c 12 | gcc -o $@ $^ 13 | -------------------------------------------------------------------------------- /src/c/udp/echo/client.c: -------------------------------------------------------------------------------- 1 | /** 2 | * FileName: client.c 3 | * Author: Fasion Chan 4 | * @contact: fasionchan@gmail.com 5 | * @version: $Id$ 6 | * 7 | * Description: 8 | * 9 | * Changelog: 10 | * 11 | **/ 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #define DEFAULT_DATA "Hello, world!" 22 | #define DEFAULT_LISTEN_PORT "55555" 23 | #define BUFFER_SIZE 256 24 | 25 | #define MAX(a, b) ((a)>(b)?(a):(b)) 26 | 27 | /** 28 | * struct for storing command line arguments. 29 | **/ 30 | struct arguments { 31 | // address of the udp echo server 32 | char const *server_addr; 33 | 34 | // port of the udp echo server 35 | char const *server_port; 36 | 37 | // data to send 38 | char const *data; 39 | }; 40 | 41 | /** 42 | * opt_handler function for GNU argp. 43 | **/ 44 | static error_t opt_handler(int key, char *arg, struct argp_state *state) { 45 | struct arguments *arguments = state->input; 46 | 47 | switch(key) { 48 | case 'a': 49 | arguments->server_addr = arg; 50 | break; 51 | case 'd': 52 | arguments->data = arg; 53 | break; 54 | case 'p': 55 | arguments->server_port = arg; 56 | break; 57 | default: 58 | return ARGP_ERR_UNKNOWN; 59 | } 60 | 61 | return 0; 62 | } 63 | 64 | /** 65 | * Parse command line arguments given by argc, argv. 66 | * 67 | * Arguments 68 | * argc: the same with main function. 69 | * 70 | * argv: the same with main function. 71 | * 72 | * Returns 73 | * Pointer to struct arguments if success, NULL if error. 74 | **/ 75 | static struct arguments const *parse_arguments(int argc, char *argv[]) 76 | { 77 | // docs for program and options 78 | static char const doc[] = "client: talk to the udp server"; 79 | static char const args_doc[] = ""; 80 | 81 | // command line options 82 | static struct argp_option const options[] = { 83 | // Option -a --server-address: address of the udp server 84 | {"server-address", 'a', "SERVER_ADDR", 0, "address of the udp server"}, 85 | 86 | // Option -p --server-port: port of the udp server 87 | {"server-port", 'p', "SERVER_PORT", 0, "port of the udp server"}, 88 | 89 | // Option -d --data: data to send 90 | {"data", 'd', "DATA", 0, "data to send"}, 91 | 92 | { 0 }, 93 | }; 94 | 95 | static struct argp const argp = { 96 | options, 97 | opt_handler, 98 | args_doc, 99 | doc, 100 | 0, 101 | 0, 102 | 0, 103 | }; 104 | 105 | // for storing results 106 | static struct arguments arguments = { 107 | .server_port = DEFAULT_LISTEN_PORT, 108 | .data = DEFAULT_DATA, 109 | }; 110 | 111 | argp_parse(&argp, argc, argv, 0, 0, &arguments); 112 | 113 | return &arguments; 114 | } 115 | 116 | int main(int argc, char *argv[]) 117 | { 118 | // parse command line options to struct arguments 119 | struct arguments const *arguments = parse_arguments(argc, argv); 120 | if (arguments == NULL) { 121 | fprintf(stderr, "Bad command line options given\n"); 122 | return 1; 123 | } 124 | 125 | // fill address struct 126 | struct sockaddr_in server_addr; 127 | bzero(&server_addr, sizeof(server_addr)); 128 | server_addr.sin_family = AF_INET; 129 | inet_aton(arguments->server_addr, &server_addr.sin_addr); 130 | server_addr.sin_port = htons(atoi(arguments->server_port)); 131 | 132 | // create udp socket 133 | int s = socket(AF_INET, SOCK_DGRAM, 0); 134 | if (s == -1) { 135 | perror("fail to create socket"); 136 | return 1; 137 | } 138 | 139 | char buffer[BUFFER_SIZE]; 140 | strncpy(buffer, arguments->data, BUFFER_SIZE); 141 | buffer[BUFFER_SIZE-1] = '\0'; 142 | 143 | int bytes_sent = sendto(s, buffer, strlen(buffer)+1, 0, 144 | (struct sockaddr *)&server_addr, sizeof(server_addr)); 145 | if (bytes_sent == -1) { 146 | perror("fail to send data"); 147 | return 1; 148 | } 149 | 150 | struct sockaddr_in peer_addr; 151 | int peer_addr_len = sizeof(peer_addr); 152 | int bytes_recieved = recvfrom(s, buffer, BUFFER_SIZE, 0, 153 | (struct sockaddr *)&peer_addr, &peer_addr_len); 154 | if (bytes_recieved == -1) { 155 | perror("fail to recieve data from server"); 156 | return 1; 157 | } 158 | 159 | buffer[MAX(bytes_recieved-1, 0)] = '\0'; 160 | printf("%s\n", buffer); 161 | 162 | // close socket 163 | int rv = close(s); 164 | if (rv == -1) { 165 | perror("fail to close socket"); 166 | return 1; 167 | } 168 | 169 | return 0; 170 | } 171 | -------------------------------------------------------------------------------- /src/c/udp/multicast/clock/Makefile: -------------------------------------------------------------------------------- 1 | # FileName: Makefile 2 | # Author: Fasion Chan 3 | # @contact: fasionchan@gmail.com 4 | # @version: $Id$ 5 | # 6 | # Description: 7 | # 8 | # Changelog: 9 | # 10 | 11 | .DEFAULT_GOAL := all 12 | 13 | server: server.c 14 | gcc -o $@ $^ 15 | 16 | client: client.c 17 | gcc -o $@ $^ 18 | 19 | all: server client 20 | 21 | clean: 22 | rm -rf server client 23 | -------------------------------------------------------------------------------- /src/c/udp/multicast/clock/client.c: -------------------------------------------------------------------------------- 1 | /** 2 | * FileName: client.c 3 | * Author: Fasion Chan 4 | * @contact: fasionchan@gmail.com 5 | * @version: $Id$ 6 | * 7 | * Description: 8 | * 9 | * Changelog: 10 | * 11 | **/ 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #define MCAST_ADDR "224.0.0.88" 21 | #define MCAST_PORT 8888 22 | #define BUFFER_SIZE 20 23 | 24 | int main() 25 | { 26 | // create udp socket 27 | int s = socket(AF_INET, SOCK_DGRAM, 0); 28 | if (s == -1) { 29 | perror("create socket"); 30 | exit(1); 31 | } 32 | 33 | // fill bind address with multicast port 34 | struct sockaddr_in bind_addr; 35 | bzero(&bind_addr, sizeof(bind_addr)); 36 | bind_addr.sin_family = AF_INET; 37 | bind_addr.sin_addr.s_addr = htonl(INADDR_ANY); 38 | bind_addr.sin_port = htons(MCAST_PORT); 39 | 40 | // bind address 41 | int rv = bind(s, (struct sockaddr *)&bind_addr, sizeof(bind_addr)); 42 | if (rv == -1) { 43 | perror("bind address"); 44 | exit(2); 45 | } 46 | 47 | // allow loop so that localhost can receive 48 | int loop = 1; 49 | rv = setsockopt(s, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop)); 50 | if (rv == -1) { 51 | perror("setsockopt loop"); 52 | exit(3); 53 | } 54 | 55 | // add self to multicast group 56 | struct ip_mreq mreq; 57 | mreq.imr_multiaddr.s_addr = inet_addr(MCAST_ADDR); 58 | mreq.imr_interface.s_addr = htonl(INADDR_ANY); 59 | rv = setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)); 60 | if (rv == -1) { 61 | perror("setsockopt add membership"); 62 | exit(3); 63 | } 64 | 65 | // receive message from multicast server 66 | char buffer[BUFFER_SIZE]; 67 | int bytes = recvfrom(s, buffer, BUFFER_SIZE, 0, NULL, NULL); 68 | if (bytes == -1) { 69 | perror("receive datetime"); 70 | exit(2); 71 | } 72 | 73 | // output datetime string 74 | printf("%s\n", buffer); 75 | 76 | return 0; 77 | } 78 | -------------------------------------------------------------------------------- /src/c/udp/multicast/clock/server.c: -------------------------------------------------------------------------------- 1 | /** 2 | * FileName: server.c 3 | * Author: Fasion Chan 4 | * @contact: fasionchan@gmail.com 5 | * @version: $Id$ 6 | * 7 | * Description: 8 | * 9 | * Changelog: 10 | * 11 | **/ 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #define MCAST_ADDR "224.0.0.88" 24 | #define MCAST_PORT 8888 25 | #define MCAST_INTERVAL 1 26 | #define BUFFER_SIZE 20 27 | 28 | /** 29 | * fetch current time and format it into string with format: xxxx-xx-xx xx:xx:xx 30 | * 31 | * WARN: 32 | * This function is non-reentrant, and thus not thread-safe, since static 33 | * buffer is used. 34 | * 35 | **/ 36 | const char *fetch_datetime() { 37 | // static buffer for storing result 38 | static char buffer[BUFFER_SIZE]; 39 | 40 | // get current time 41 | struct timeval tv; 42 | gettimeofday(&tv, NULL); 43 | 44 | // convert to datetime 45 | struct tm *tm = localtime(&tv.tv_sec); 46 | 47 | // format datetime 48 | strftime(buffer, BUFFER_SIZE, "%Y-%m-%d %H:%M:%S", tm); 49 | 50 | return buffer; 51 | } 52 | 53 | int main() 54 | { 55 | // create udp socket 56 | int s = socket(AF_INET, SOCK_DGRAM, 0); 57 | if (s == -1) { 58 | perror("create socket"); 59 | exit(1); 60 | } 61 | 62 | // fill multicast address and port 63 | struct sockaddr_in mcast_addr; 64 | bzero(&mcast_addr, sizeof(mcast_addr)); 65 | mcast_addr.sin_family = AF_INET; 66 | mcast_addr.sin_addr.s_addr = inet_addr(MCAST_ADDR); 67 | mcast_addr.sin_port = htons(MCAST_PORT); 68 | 69 | for (;;) { 70 | // fetch current datetime string 71 | const char *datetime = fetch_datetime(); 72 | 73 | // send datetime to multicast address 74 | int bytes = sendto(s, datetime, BUFFER_SIZE, 0, (struct sockaddr *)&mcast_addr, sizeof(mcast_addr)); 75 | if (bytes == -1) { 76 | perror("send datetime"); 77 | exit(2); 78 | } 79 | 80 | // wait for a while 81 | sleep(MCAST_INTERVAL); 82 | } 83 | 84 | return 0; 85 | } 86 | -------------------------------------------------------------------------------- /src/go/grpc/server-streaming/ticker/.gitignore: -------------------------------------------------------------------------------- 1 | client 2 | server 3 | -------------------------------------------------------------------------------- /src/go/grpc/server-streaming/ticker/Makefile: -------------------------------------------------------------------------------- 1 | # Author: fasion 2 | # Created time: 2019-05-10 09:35:28 3 | # Last Modified by: fasion 4 | # Last Modified time: 2019-05-10 10:29:42 5 | 6 | default: clean all 7 | 8 | tick.pb.go: tick.proto 9 | protoc --go_out=plugins=grpc:. $^ 10 | 11 | server: server.go tick.pb.go 12 | go build $^ 13 | 14 | client: client.go tick.pb.go 15 | go build $^ 16 | 17 | all: server client 18 | 19 | clean: 20 | rm -f tick.pb.go server client -------------------------------------------------------------------------------- /src/go/grpc/server-streaming/ticker/client.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: fasion 3 | * Created time: 2019-05-10 08:51:45 4 | * Last Modified by: fasion 5 | * Last Modified time: 2019-05-10 10:24:27 6 | */ 7 | 8 | package main 9 | 10 | import ( 11 | "context" 12 | "fmt" 13 | "io" 14 | "log" 15 | 16 | empty "github.com/golang/protobuf/ptypes/empty" 17 | 18 | "google.golang.org/grpc" 19 | ) 20 | 21 | const ( 22 | address = "locals.fasionchan.com:55555" 23 | ) 24 | 25 | func main() { 26 | conn, err := grpc.Dial(address, grpc.WithInsecure()) 27 | if err != nil { 28 | log.Fatalf("failed to connect: %v\n", err) 29 | } 30 | defer conn.Close() 31 | 32 | c := NewTickServiceClient(conn) 33 | 34 | handler, err := c.Listen(context.Background(), &empty.Empty{}) 35 | if err != nil { 36 | log.Fatalf("failed to call listen :%s\n", err) 37 | } 38 | 39 | for { 40 | tick, err := handler.Recv() 41 | if err != nil { 42 | if err != io.EOF { 43 | log.Fatalf("failed to Recv: %v\n", err) 44 | } 45 | break 46 | } 47 | 48 | fmt.Println(tick.GetTimestamp()) 49 | } 50 | } -------------------------------------------------------------------------------- /src/go/grpc/server-streaming/ticker/server.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: fasion 3 | * Created time: 2019-05-10 09:13:27 4 | * Last Modified by: fasion 5 | * Last Modified time: 2019-05-10 10:26:31 6 | */ 7 | 8 | package main 9 | 10 | import ( 11 | "log" 12 | "net" 13 | "time" 14 | 15 | "google.golang.org/grpc" 16 | 17 | "github.com/golang/protobuf/ptypes" 18 | empty "github.com/golang/protobuf/ptypes/empty" 19 | ) 20 | 21 | const ( 22 | address = ":55555" 23 | ) 24 | 25 | type TickService struct{} 26 | 27 | func (self *TickService) Listen(_ *empty.Empty, handler TickService_ListenServer) (error) { 28 | for { 29 | tick := Tick{ 30 | Timestamp: ptypes.TimestampNow(), 31 | } 32 | 33 | if err := handler.Send(&tick); err != nil { 34 | log.Printf("fail to send: %v\n", err) 35 | } 36 | 37 | time.Sleep(time.Second) 38 | } 39 | 40 | return nil 41 | } 42 | 43 | func main() { 44 | lstn, err := net.Listen("tcp", address) 45 | if err != nil { 46 | log.Fatalf("failed to listen: %v", err) 47 | } 48 | 49 | service := TickService{} 50 | 51 | s := grpc.NewServer() 52 | RegisterTickServiceServer(s, &service) 53 | 54 | if err := s.Serve(lstn); err != nil { 55 | log.Fatalf("failed to serve: %s", err) 56 | } 57 | } -------------------------------------------------------------------------------- /src/go/grpc/server-streaming/ticker/tick.proto: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: fasion 3 | * Created time: 2019-05-10 08:37:45 4 | * Last Modified by: fasion 5 | * Last Modified time: 2019-05-10 08:51:05 6 | */ 7 | 8 | syntax = "proto3"; 9 | 10 | package main; 11 | 12 | import "google/protobuf/timestamp.proto"; 13 | import "google/protobuf/empty.proto"; 14 | 15 | service TickService { 16 | rpc Listen(google.protobuf.Empty) returns (stream Tick) {}; 17 | } 18 | 19 | message Tick { 20 | google.protobuf.Timestamp timestamp = 1; 21 | } -------------------------------------------------------------------------------- /src/nodejs/websocket/client.js: -------------------------------------------------------------------------------- 1 | const WebSocket = require('ws'); 2 | const iconv = require('iconv-lite'); 3 | 4 | const ws = new WebSocket('ws://localhost:18888/'); 5 | 6 | ws.on('open', function () { 7 | const s = JSON.stringify({name: '小菜'}); 8 | const b = iconv.encode(s, 'gbk'); 9 | ws.send(b); 10 | }); 11 | -------------------------------------------------------------------------------- /src/nodejs/websocket/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "iconv": "^2.3.5", 4 | "iconv-lite": "^0.5.0", 5 | "ws": "^7.2.0" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/nodejs/websocket/server.js: -------------------------------------------------------------------------------- 1 | const WebSocket = require('ws'); 2 | 3 | const server = new WebSocket.Server({port: 18888}); 4 | 5 | server.on('connection', function (ws) { 6 | ws.on('messge', function (msg) { 7 | console.log('received', msg) 8 | }); 9 | }); 10 | -------------------------------------------------------------------------------- /src/python/.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | MANIFEST 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | 49 | # Translations 50 | *.mo 51 | *.pot 52 | 53 | # Django stuff: 54 | *.log 55 | .static_storage/ 56 | .media/ 57 | local_settings.py 58 | 59 | # Flask stuff: 60 | instance/ 61 | .webassets-cache 62 | 63 | # Scrapy stuff: 64 | .scrapy 65 | 66 | # Sphinx documentation 67 | docs/_build/ 68 | 69 | # PyBuilder 70 | target/ 71 | 72 | # Jupyter Notebook 73 | .ipynb_checkpoints 74 | 75 | # pyenv 76 | .python-version 77 | 78 | # celery beat schedule file 79 | celerybeat-schedule 80 | 81 | # SageMath parsed files 82 | *.sage.py 83 | 84 | # Environments 85 | .env 86 | .venv 87 | env/ 88 | venv/ 89 | ENV/ 90 | env.bak/ 91 | venv.bak/ 92 | 93 | # Spyder project settings 94 | .spyderproject 95 | .spyproject 96 | 97 | # Rope project settings 98 | .ropeproject 99 | 100 | # mkdocs documentation 101 | /site 102 | 103 | # mypy 104 | .mypy_cache/ 105 | -------------------------------------------------------------------------------- /src/python/ethernet/send_ether.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding=utf8 -*- 3 | 4 | ''' 5 | FileName: send_ether.py 6 | Author: Chen Yanfei 7 | @contact: fasionchan@gmail.com 8 | @version: $Id$ 9 | 10 | Description: 11 | 12 | Changelog: 13 | 14 | ''' 15 | 16 | import base64 17 | import struct 18 | 19 | from argparse import ( 20 | ArgumentParser, 21 | ) 22 | from fcntl import ( 23 | ioctl, 24 | ) 25 | from socket import ( 26 | AF_PACKET, 27 | AF_INET, 28 | SOCK_DGRAM, 29 | SOCK_RAW, 30 | IPPROTO_RAW, 31 | socket, 32 | ) 33 | 34 | 35 | def mac_aton(a): 36 | ''' 37 | Convert readable MAC address to binary format. 38 | 39 | Arguments 40 | a: readable format, str type of Colon-Separated Hexadecimal. 41 | 42 | Returns 43 | A bytes type of size 6, which is the binary format. 44 | ''' 45 | 46 | return base64.b16decode(a.upper().replace(':', '')) 47 | 48 | 49 | def fetch_iface_mac(iface, s=None): 50 | ''' 51 | Fetch MAC address of given iface. 52 | 53 | Arguments 54 | iface: iface name, str type. 55 | 56 | Returns 57 | A bytes type of size 6, which is the MAC address in binary format. 58 | ''' 59 | 60 | # create socket if given, any type is ok 61 | if not s: 62 | s = socket(AF_INET, SOCK_DGRAM) 63 | 64 | # pack iface name to struct ifreq 65 | iface_buf = struct.pack('64s', iface.encode('utf8')) 66 | 67 | # call ioctl to get hardware address 68 | # according to C header file, SIOCGIFHWADDR is 0x8927 69 | mac = ioctl(s.fileno(), 0x8927, iface_buf)[18:24] 70 | 71 | return mac 72 | 73 | 74 | def send_ether(iface, to, _type, data, s=None): 75 | ''' 76 | Send data through ethernet protocol, using raw socket. 77 | 78 | Arguments 79 | iface: name of iface for sending, str type. 80 | 81 | to: destination MAC addres, str type for readable or 82 | bytes type for binary. 83 | 84 | _type: protocol type, int type. 85 | 86 | data: data to send, str type or bytes type. 87 | ''' 88 | 89 | # if destination address is readable format, convert first 90 | if isinstance(to, str): 91 | to = mac_aton(to) 92 | 93 | # if data is str type, encode it first 94 | if isinstance(data, str): 95 | data = data.encode('utf8') 96 | 97 | # create raw socket if not given 98 | if s is None: 99 | s = socket(AF_PACKET, SOCK_RAW) 100 | 101 | # bind to the sending iface 102 | s.bind((iface, 0)) 103 | 104 | # get MAC address of sending iface, which is the source address 105 | fr = fetch_iface_mac(iface, s) 106 | 107 | # pack ethernet header 108 | header = struct.pack('!6s6sH', to, fr, _type) 109 | # pack ethernet frame 110 | frame = header + data 111 | 112 | # send the ethernet frame 113 | s.send(frame) 114 | 115 | 116 | def parse_arguments(): 117 | ''' 118 | Parse command line arguments. 119 | 120 | Arguments 121 | 122 | Returns 123 | An argparse.Namespace is return, in which command options and 124 | arguments are stored. 125 | ''' 126 | 127 | # parser for command line arguments 128 | parser = ArgumentParser(description='Send ethernet frame.') 129 | 130 | # Argument: name of iface for sending 131 | parser.add_argument( 132 | '-i', 133 | '--iface', 134 | dest='iface', 135 | required=True, 136 | ) 137 | # Argument: destination MAC address 138 | parser.add_argument( 139 | '-t', 140 | '--to', 141 | dest='to', 142 | required=True, 143 | ) 144 | # Argument: data to send 145 | parser.add_argument( 146 | '-d', 147 | '--data', 148 | dest='data', 149 | default='a' * 46, 150 | required=False, 151 | ) 152 | # Argument: protocol type 153 | parser.add_argument( 154 | '-T', 155 | '--type', 156 | dest='_type', 157 | default='0x0900', 158 | required=False, 159 | ) 160 | 161 | # parse arguments 162 | args = parser.parse_args() 163 | 164 | return args 165 | 166 | 167 | def main(): 168 | ''' 169 | Entrance for the program. 170 | ''' 171 | 172 | # parse command line arguments 173 | args = parse_arguments() 174 | 175 | # send ethernet frame according to given arguments 176 | send_ether( 177 | iface=args.iface, 178 | to=args.to, 179 | _type=eval(args._type), 180 | data=args.data, 181 | ) 182 | 183 | if __name__ == '__main__': 184 | main() 185 | -------------------------------------------------------------------------------- /src/python/ethernet/show_mac.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding=utf8 -*- 3 | 4 | ''' 5 | FileName: show_mac.py 6 | Author: Fasion Chan 7 | @contact: fasionchan@gmail.com 8 | @version: $Id$ 9 | 10 | Description: 11 | 12 | Changelog: 13 | 14 | ''' 15 | 16 | import base64 17 | import struct 18 | import sys 19 | 20 | from fcntl import ( 21 | ioctl, 22 | ) 23 | from socket import ( 24 | AF_INET, 25 | SOCK_DGRAM, 26 | socket, 27 | ) 28 | 29 | 30 | def mac_ntoa(n): 31 | ''' 32 | Convert binary MAC address to readable format. 33 | 34 | Arguments 35 | n: binary format, must be bytes type of size 6. 36 | 37 | Returns 38 | A str type which is the readable format, like '08:00:27:c8:04:83'. 39 | ''' 40 | 41 | return '%02x:%02x:%02x:%02x:%02x:%02x' % tuple(n) 42 | 43 | 44 | def fetch_iface_mac(iface, s=None): 45 | ''' 46 | Fetch MAC address of given iface. 47 | 48 | Arguments 49 | iface: iface name, str type. 50 | 51 | Returns 52 | A bytes type of size 6, which is the MAC address in binary format. 53 | ''' 54 | 55 | # create socket if not given, any type is ok 56 | if not s: 57 | s = socket(AF_INET, SOCK_DGRAM) 58 | 59 | # pack iface name to struct ifreq 60 | iface_buf = struct.pack('64s', iface.encode('utf8')) 61 | 62 | # call ioctl to get hardware address 63 | # according to C header file, SIOCGIFHWADDR is 0x8927 64 | mac = ioctl(s.fileno(), 0x8927, iface_buf)[18:24] 65 | 66 | return mac 67 | 68 | 69 | def main(): 70 | # name of iface 71 | iface = sys.argv[1] 72 | 73 | # Fetch mac address 74 | mac = fetch_iface_mac(iface) 75 | 76 | # output result 77 | print('iFace: {iface}'.format(iface=iface)) 78 | print('MAC: {mac}'.format(mac=mac_ntoa(mac))) 79 | 80 | 81 | if __name__ == '__main__': 82 | main() 83 | -------------------------------------------------------------------------------- /src/python/icmp/ping/ping.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding=utf8 -*- 3 | 4 | ''' 5 | FileName: ping.py 6 | Author: Fasion Chan 7 | @contact: fasionchan@gmail.com 8 | @version: $Id$ 9 | 10 | Description: 11 | 12 | Changelog: 13 | 14 | ''' 15 | 16 | import os 17 | import socket 18 | import struct 19 | import sys 20 | import threading 21 | import time 22 | 23 | def calculate_checksum(icmp): 24 | if len(icmp) % 2: 25 | icmp += b'\00' 26 | 27 | checksum = 0 28 | for i in range(len(icmp)//2): 29 | word, = struct.unpack('!H', icmp[2*i:2*i+2]) 30 | checksum += word 31 | 32 | while True: 33 | carry = checksum >> 16 34 | if carry: 35 | checksum = (checksum & 0xffff) + carry 36 | else: 37 | break 38 | 39 | checksum = ~checksum & 0xffff 40 | 41 | return struct.pack('!H', checksum) 42 | 43 | def calculate_checksum(icmp): 44 | highs = icmp[0::2] 45 | lows = icmp[1::2] 46 | 47 | checksum = ((sum(highs) << 8) + sum(lows)) 48 | 49 | while True: 50 | carry = checksum >> 16 51 | if carry: 52 | checksum = (checksum & 0xffff) + carry 53 | else: 54 | break 55 | 56 | checksum = ~checksum & 0xffff 57 | 58 | return struct.pack('!H', checksum) 59 | 60 | def pack_icmp_echo_request(ident, seq, payload): 61 | pseudo = struct.pack( 62 | '!BBHHH', 63 | 8, 64 | 0, 65 | 0, 66 | ident, 67 | seq, 68 | ) + payload 69 | checksum = calculate_checksum(pseudo) 70 | return pseudo[:2] + checksum + pseudo[4:] 71 | 72 | def unpack_icmp_echo_reply(icmp): 73 | _type, code, _, ident, seq, = struct.unpack( 74 | '!BBHHH', 75 | icmp[:8] 76 | ) 77 | if _type != 0: 78 | return 79 | if code != 0: 80 | return 81 | 82 | payload = icmp[8:] 83 | 84 | return ident, seq, payload 85 | 86 | def send_routine(sock, addr, ident, magic, stop): 87 | # first sequence no 88 | seq = 1 89 | 90 | while not stop: 91 | # currrent time 92 | sending_ts = time.time() 93 | 94 | # packet current time to payload 95 | # in order to calculate round trip time from reply 96 | payload = struct.pack('!d', sending_ts) + magic 97 | 98 | # pack icmp packet 99 | icmp = pack_icmp_echo_request(ident, seq, payload) 100 | 101 | # send it 102 | sock.sendto(icmp, 0, (addr, 0)) 103 | 104 | seq += 1 105 | time.sleep(1) 106 | 107 | def recv_routine(sock, ident, magic): 108 | while True: 109 | # wait for another icmp packet 110 | ip, (src_addr, _) = sock.recvfrom(1500) 111 | 112 | # unpack it 113 | result = unpack_icmp_echo_reply(ip[20:]) 114 | if not result: 115 | continue 116 | 117 | # print info 118 | _ident, seq, payload = result 119 | if _ident != ident: 120 | continue 121 | 122 | sending_ts, = struct.unpack('!d', payload[:8]) 123 | print('%s seq=%d %5.2fms' % ( 124 | src_addr, 125 | seq, 126 | (time.time()-sending_ts) * 1000, 127 | )) 128 | 129 | def ping(addr): 130 | # create socket for sending and receiving icmp packet 131 | sock = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_ICMP) 132 | 133 | # id field 134 | ident = os.getpid() 135 | # magic string to pad 136 | magic = b'1234567890' 137 | 138 | # sender thread stop flag 139 | # append anything to stop 140 | sender_stop = [] 141 | 142 | # start sender thread 143 | # call send_routine function to send icmp forever 144 | args = (sock, addr, ident, magic, sender_stop,) 145 | sender = threading.Thread(target=send_routine, args=args) 146 | sender.start() 147 | 148 | try: 149 | # receive icmp reply forever 150 | recv_routine(sock, ident, magic) 151 | except KeyboardInterrupt: 152 | pass 153 | 154 | # tell sender thread to stop 155 | sender_stop.append(True) 156 | 157 | # clean sender thread 158 | sender.join() 159 | 160 | print() 161 | 162 | if __name__ == '__main__': 163 | ping(sys.argv[1]) 164 | -------------------------------------------------------------------------------- /src/python/restful/flask/kvs/kvs.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding=utf8 -*- 3 | 4 | ''' 5 | FileName: kvs.py 6 | Author: Fasion Chan 7 | @contact: fasionchan@gmail.com 8 | @version: $Id$ 9 | 10 | Description: 11 | 12 | Changelog: 13 | 14 | ''' 15 | 16 | import json 17 | 18 | from collections import ( 19 | OrderedDict, 20 | ) 21 | from flask import ( 22 | Flask, 23 | jsonify, 24 | request, 25 | ) 26 | 27 | SIZE_LIMIT = 100 28 | KVS = OrderedDict() 29 | 30 | app = Flask(__name__) 31 | app.config['JSON_AS_ASCII'] = False 32 | 33 | 34 | def get_request_data(): 35 | ''' 36 | 获取请求数据 37 | 38 | 根据请求数据类型反序列化 39 | ''' 40 | 41 | data = None 42 | 43 | # 类型 44 | content_type = request.headers['Content-Type'] 45 | 46 | try: 47 | # json 48 | if content_type == 'application/json': 49 | data = json.loads(request.data) 50 | except Exception as exc: 51 | print(exc) 52 | 53 | return isinstance(data, dict), data 54 | 55 | 56 | @app.route('/kvs', methods=['POST']) 57 | def create(): 58 | ''' 59 | 增 60 | ''' 61 | 62 | # 资源不足,返回错误 63 | if len(KVS) >= SIZE_LIMIT: 64 | return jsonify({ 65 | 'result': False, 66 | 'message': 'out of resources', 67 | }) 68 | 69 | # 获取请求数据 70 | result, data = get_request_data() 71 | 72 | # 请求数据错误 73 | if not result: 74 | return jsonify({ 75 | 'result': False, 76 | 'message': 'bad request data', 77 | }) 78 | 79 | # 取出数据键 80 | key = data.get('key') 81 | if not key: 82 | return jsonify({ 83 | 'result': False, 84 | 'message': 'data key missing', 85 | }) 86 | 87 | # 插入资源池并判断状态 88 | result = KVS.setdefault(key, data) is data 89 | 90 | # 资源已存在 91 | if not result: 92 | return jsonify({ 93 | 'result': False, 94 | 'message': 'resource exists', 95 | }) 96 | 97 | return jsonify({ 98 | 'result': result, 99 | 'data': data, 100 | }) 101 | 102 | 103 | @app.route('/kvs/', methods=['DELETE']) 104 | def delete(key): 105 | ''' 106 | 删 107 | ''' 108 | 109 | # 删除资源 110 | data = KVS.pop(key, None) 111 | 112 | # 资源不存在 113 | if data is None: 114 | return jsonify({ 115 | 'result': False, 116 | 'message': 'resource not exists', 117 | }) 118 | 119 | return jsonify({ 120 | 'result': True, 121 | 'data': data, 122 | }) 123 | 124 | 125 | @app.route('/kvs/', methods=['PUT']) 126 | def update(key): 127 | ''' 128 | 改 129 | ''' 130 | 131 | # 获取请求数据 132 | result, changes = get_request_data() 133 | 134 | # 请求数据错误 135 | if not result: 136 | return jsonify({ 137 | 'result': False, 138 | 'message': 'bad request data', 139 | }) 140 | 141 | # 获取资源 142 | data = KVS.get(key) 143 | 144 | # 资源不存在 145 | if data is None: 146 | return jsonify({ 147 | 'result': False, 148 | 'message': 'resource not exists', 149 | }) 150 | 151 | # 更新资源 152 | data.update(changes) 153 | 154 | return jsonify({ 155 | 'result': True, 156 | 'data': data, 157 | }) 158 | 159 | 160 | @app.route('/kvs/') 161 | def retrieve(key): 162 | ''' 163 | 查 164 | ''' 165 | 166 | # 获取资源 167 | data = KVS.get(key) 168 | 169 | # 资源不存在 170 | if data is None: 171 | return jsonify({ 172 | 'result': False, 173 | 'message': 'resource not exists', 174 | }) 175 | 176 | return jsonify({ 177 | 'result': True, 178 | 'data': data, 179 | }) 180 | 181 | 182 | @app.route('/kvs') 183 | def search(): 184 | ''' 185 | 列 186 | ''' 187 | 188 | skip = int(request.args.get('skip', 0)) 189 | limit = int(request.args.get('limit', 10)) 190 | data = list(KVS.values())[skip:skip+limit] 191 | 192 | return jsonify({ 193 | 'result': True, 194 | 'data': data, 195 | 'meta': { 196 | 'total': len(KVS), 197 | 'skip': skip, 198 | 'count': len(data), 199 | }, 200 | }) 201 | -------------------------------------------------------------------------------- /src/python/restful/flask/kvs/requirements.txt: -------------------------------------------------------------------------------- 1 | Flask==1.0.2 2 | -------------------------------------------------------------------------------- /src/python/smtp/send_email.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding=utf8 -*- 3 | 4 | ''' 5 | FileName: send_email.py 6 | Author: Fasion Chan 7 | @contact: fasionchan@gmail.com 8 | @version: $Id$ 9 | 10 | Description: 11 | 12 | Changelog: 13 | 14 | ''' 15 | 16 | import argparse 17 | import smtplib 18 | import datetime 19 | 20 | 21 | def send_email(host, port, user, password, fr, to, subject, body, 22 | smtp_cls=smtplib.SMTP_SSL): 23 | 24 | ''' 25 | Send an email by smtp protocol 26 | 27 | Arguments 28 | host: email server host 29 | port: email server port 30 | user: user to login 31 | password: password 32 | fr: sender email address, the same as login user usually 33 | to: receiver email address 34 | subject: email title 35 | body: email content 36 | 37 | Returns 38 | None 39 | ''' 40 | 41 | smtp = smtp_cls() 42 | 43 | # connect and login 44 | smtp.connect(host, port) 45 | smtp.login(user, password) 46 | 47 | # format message 48 | msg = u'''From: {fr} 49 | To: {to} 50 | Subject: {subject} 51 | Date: {date} 52 | 53 | {body} 54 | '''.format( 55 | fr=fr, 56 | to=to, 57 | subject=subject, 58 | date=datetime.datetime.now().strftime('%d/%m/%Y %H:%M'), 59 | body=body, 60 | ) 61 | 62 | # do send 63 | smtp.sendmail(fr, to, msg.encode('utf8')) 64 | smtp.quit() 65 | 66 | 67 | def main(): 68 | parser = argparse.ArgumentParser(prog='sender') 69 | 70 | parser.add_argument( 71 | '-H', 72 | '--host', 73 | dest='host', 74 | metavar='host', 75 | default='', 76 | required=True, 77 | help='email server host', 78 | ) 79 | 80 | parser.add_argument( 81 | '-p', 82 | '--port', 83 | dest='port', 84 | metavar='port', 85 | default='', 86 | required=True, 87 | help='email server port', 88 | ) 89 | 90 | parser.add_argument( 91 | '-u', 92 | '--user', 93 | dest='user', 94 | metavar='user', 95 | default='', 96 | required=True, 97 | help='user', 98 | ) 99 | 100 | parser.add_argument( 101 | '-P', 102 | '--password', 103 | dest='password', 104 | metavar='password', 105 | default='', 106 | required=True, 107 | help='password', 108 | ) 109 | 110 | parser.add_argument( 111 | '-r', 112 | '--receiver', 113 | dest='receiver', 114 | metavar='receiver', 115 | default='', 116 | required=True, 117 | help='email receiver', 118 | ) 119 | 120 | parser.add_argument( 121 | '-s', 122 | '--subject', 123 | dest='subject', 124 | metavar='subject', 125 | default='', 126 | required=True, 127 | help='email subject', 128 | ) 129 | 130 | parser.add_argument( 131 | '-b', 132 | '--body', 133 | dest='body', 134 | metavar='body', 135 | default='', 136 | required=True, 137 | help='email body', 138 | ) 139 | 140 | args = parser.parse_args() 141 | 142 | send_email( 143 | host=args.host, 144 | port=int(args.port), 145 | user=args.user, 146 | password=args.password, 147 | fr=args.user, 148 | to=args.receiver, 149 | subject=args.subject, 150 | body=args.body, 151 | smtp_cls=smtplib.SMTP_SSL, 152 | ) 153 | 154 | 155 | if __name__ == '__main__': 156 | main() 157 | -------------------------------------------------------------------------------- /src/python/udp/echo/client.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding=utf8 -*- 3 | 4 | ''' 5 | FileName: client.py 6 | Author: Fasion Chan 7 | @contact: fasionchan@gmail.com 8 | @version: $Id$ 9 | 10 | Description: 11 | 12 | Changelog: 13 | 14 | ''' 15 | 16 | from argparse import ( 17 | ArgumentParser, 18 | ) 19 | from socket import ( 20 | socket, 21 | AF_INET, 22 | SOCK_DGRAM, 23 | ) 24 | 25 | BUFFER_SIZE = 1024 26 | 27 | 28 | def parse_arguments(): 29 | parser = ArgumentParser(description='client.py: talk with udp echo server') 30 | 31 | parser.add_argument( 32 | '-a', 33 | '--server-address', 34 | dest='server_addr', 35 | required=False, 36 | default='127.0.0.1', 37 | ) 38 | 39 | parser.add_argument( 40 | '-p', 41 | '--server-port', 42 | dest='server_port', 43 | required=False, 44 | default=55555, 45 | ) 46 | 47 | parser.add_argument( 48 | '-d', 49 | '--data', 50 | dest='data', 51 | required=False, 52 | default='Hello, world!', 53 | ) 54 | 55 | args = parser.parse_args() 56 | 57 | return args 58 | 59 | 60 | def main(): 61 | args = parse_arguments() 62 | s = socket(AF_INET, SOCK_DGRAM) 63 | s.sendto(args.data.encode('utf8'), (args.server_addr, args.server_port)) 64 | msg, peer = s.recvfrom(BUFFER_SIZE) 65 | print(msg.decode('utf8')) 66 | 67 | if __name__ == '__main__': 68 | main() 69 | -------------------------------------------------------------------------------- /src/python/udp/echo/server.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding=utf8 -*- 3 | 4 | ''' 5 | FileName: server.py 6 | Author: Fasion Chan 7 | @contact: fasionchan@gmail.com 8 | @version: $Id$ 9 | 10 | Description: 11 | 12 | Changelog: 13 | 14 | ''' 15 | 16 | from argparse import ( 17 | ArgumentParser, 18 | ) 19 | from socket import ( 20 | socket, 21 | AF_INET, 22 | SOCK_DGRAM, 23 | ) 24 | 25 | BUFFER_SIZE = 1024 26 | 27 | 28 | def parse_arguments(): 29 | parser = ArgumentParser(description='server.py: udp echo server') 30 | 31 | parser.add_argument( 32 | '-a', 33 | '--bind-address', 34 | dest='bind_addr', 35 | required=False, 36 | default='0.0.0.0', 37 | ) 38 | 39 | parser.add_argument( 40 | '-p', 41 | '--bind-port', 42 | dest='bind_port', 43 | required=False, 44 | default=55555, 45 | ) 46 | 47 | args = parser.parse_args() 48 | 49 | return args 50 | 51 | def main(): 52 | args = parse_arguments() 53 | s = socket(AF_INET, SOCK_DGRAM) 54 | s.bind((args.bind_addr, args.bind_port)) 55 | while True: 56 | msg, peer = s.recvfrom(BUFFER_SIZE) 57 | print('Recieved %4d bytes from %s' % (len(msg), peer)) 58 | s.sendto(msg, peer) 59 | 60 | if __name__ == '__main__': 61 | main() 62 | --------------------------------------------------------------------------------