search.xml 172 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <search>
  3. <entry>
  4. <title>斐讯N1刷机后操作</title>
  5. <url>/posts/b9577586.html</url>
  6. <content><![CDATA[<p>N1刷机成功后,为了方便使用,免不了要执行一些常见的配置操作或软件安装,例:更换国内软件源、安装docker、设置WIFI、安装Java环境等。</p>
  7. <span id="more"></span>
  8. <h1 id="阅读须知"><a href="#阅读须知" class="headerlink" title="阅读须知"></a>阅读须知</h1><p>本示例系统使用的是armbian 5.67 stretch 4.19</p>
  9. <h1 id="设置WiFi"><a href="#设置WiFi" class="headerlink" title="设置WiFi"></a>设置WiFi</h1><p>要设置WiFi可以使用系统自带的网络设置图形界面</p>
  10. <figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">nmtui</span><br></pre></td></tr></table></figure>
  11. <p>执行命令后,通过方向键和回车键选中其中的<em>Activate a connection</em>选项,将会弹出一个列表(<em>Wired</em>代表的是有线连接,<em>WiFi</em>代表的是无线连接),按提示输入WiFi账号密码即可。</p>
  12. <p>如果图形界面中没有WiFi列表则说明系统的WiFi模块有问题,可按如下方法解决:</p>
  13. <p>方法一: 执行如下命令重新加载模块</p>
  14. <figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">modprobe dhd &amp;&amp; echo dhd &gt;&gt; &#x2F;etc&#x2F;modules</span><br><span class="line">modprobe wifi_dummy &amp;&amp; echo wifi_dummy &gt;&gt; &#x2F;etc&#x2F;modules</span><br></pre></td></tr></table></figure>
  15. <p>方法二:使用armbian-config命令设置wifi</p>
  16. <figure class="highlight plain"><table><tr><td class="code"><pre><span class="line"># 执行命令</span><br><span class="line">armbian-config</span><br></pre></td></tr></table></figure>
  17. <p>依据提示选中Network中的WIFI</p>
  18. <p>方法三:重新安装系统。</p>
  19. <h1 id="更换国内源"><a href="#更换国内源" class="headerlink" title="更换国内源"></a>更换国内源</h1><p>重要的事情说三遍</p>
  20. <p>如果默认源的安装速度不是特别慢的话,无需特意跟换源!!!</p>
  21. <p>如果默认源的安装速度不是特别慢的话,无需特意跟换源!!!</p>
  22. <p>如果默认源的安装速度不是特别慢的话,无需特意跟换源!!!</p>
  23. <p>/etc/apt/sources.list文件记录的是系统所使用的软件源,而默认安装的系统使用的是国外源</p>
  24. <p>首先对/etc/apt/sources.list文件进行备份,以备不时之需</p>
  25. <figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">cp &#x2F;etc&#x2F;apt&#x2F;sources.list &#x2F;etc&#x2F;apt&#x2F;sources.list.bak</span><br></pre></td></tr></table></figure>
  26. <p>然后编辑/etc/apt/sources.list文件,把原有的源删除,并加入新的国内源(这里使用的是科大的源,如果需要的可以自行更换为其它源,如:163、清华等),并保存。</p>
  27. <figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">vi &#x2F;etc&#x2F;apt&#x2F;sources.list</span><br><span class="line"></span><br><span class="line"># 科大软件源</span><br><span class="line">deb http:&#x2F;&#x2F;mirrors.ustc.edu.cn&#x2F;debian&#x2F; stretch main non-free contrib</span><br><span class="line">deb http:&#x2F;&#x2F;mirrors.ustc.edu.cn&#x2F;debian&#x2F; stretch-updates main non-free contrib</span><br><span class="line">deb http:&#x2F;&#x2F;mirrors.ustc.edu.cn&#x2F;debian&#x2F; stretch-backports main non-free contrib</span><br><span class="line">deb-src http:&#x2F;&#x2F;mirrors.ustc.edu.cn&#x2F;debian&#x2F; stretch main non-free contrib</span><br><span class="line">deb-src http:&#x2F;&#x2F;mirrors.ustc.edu.cn&#x2F;debian&#x2F; stretch-updates main non-free contrib</span><br><span class="line">deb-src http:&#x2F;&#x2F;mirrors.ustc.edu.cn&#x2F;debian&#x2F; stretch-backports main non-free contrib</span><br><span class="line">deb http:&#x2F;&#x2F;mirrors.ustc.edu.cn&#x2F;debian-security&#x2F; stretch&#x2F;updates main non-free contrib</span><br><span class="line">deb-src http:&#x2F;&#x2F;mirrors.ustc.edu.cn&#x2F;debian-security&#x2F; stretch&#x2F;updates main non-free contrib</span><br></pre></td></tr></table></figure>
  28. <p>最后执行更新命令,使软件列表生效</p>
  29. <figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">apt update</span><br></pre></td></tr></table></figure>
  30. <p>等待命令执行完,至此新的软件源就生效了。</p>
  31. <h1 id="安装docker"><a href="#安装docker" class="headerlink" title="安装docker"></a>安装docker</h1><p>安装docker有一个非常便捷的方法就是使用阿里提供的一键安装脚本</p>
  32. <figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">curl -fsSL https:&#x2F;&#x2F;get.docker.com | bash -s docker --mirror Aliyun</span><br></pre></td></tr></table></figure>
  33. <p>通过脚本直接安装docker及其所需的依赖,可以说是非常方便了。</p>
  34. <p>注意:该脚本会直接安装最新的docker脚本</p>
  35. <h1 id="安装JRE"><a href="#安装JRE" class="headerlink" title="安装JRE"></a>安装JRE</h1><p>有时候需要运行Java程序,因此JRE(Java运行时环境)是必不可少的。</p>
  36. <p>执行如下命令</p>
  37. <figure class="highlight plain"><table><tr><td class="code"><pre><span class="line"># 安装java8的jre</span><br><span class="line">apt-get install openjdk-8-jre</span><br></pre></td></tr></table></figure>
  38. <p>注意点一:如果安装过程中遇到所需依赖无法下载的问题,可能是由apt源造成的。博主之前使用的是科大软件源,结果提示部分依赖缺少无法下载,然后跟换回默认源就可以了。</p>
  39. <p>注意点二:博主一开始是从Oracle官网下载的解压包:server-jre-8u212-linux-x64.tar.gz,并用其配置环境,但是在尝试执行命令的时候却报错:<em>cannot execute binary file: Exec format error</em>,这是因为该解压包的文件目标运行系统和本系统(参考:阅读须知)有差异而导致的,需要指定的版本才能在本系统运行。</p>
  40. <h1 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h1><p><a href="https://luotianyi.vc/1389.html">Armbian系统重新加载WiFi模块</a></p>
  41. <p><a href="https://www.hostloc.com/thread-527652-1-1.html">N1求教连接wifi问题,实在不知道咋回事了</a></p>
  42. ]]></content>
  43. <categories>
  44. <category>有趣</category>
  45. <category>刷机</category>
  46. </categories>
  47. <tags>
  48. <tag>有趣</tag>
  49. </tags>
  50. </entry>
  51. <entry>
  52. <title>架构师的思考层次</title>
  53. <url>/posts/b1bd9b76.html</url>
  54. <content><![CDATA[<p>作为一个架构师,在面对一个产品的时候应该怎么进行思考呢?</p>
  55. <span id="more"></span>
  56. <h1 id="关注产品本身"><a href="#关注产品本身" class="headerlink" title="关注产品本身"></a>关注产品本身</h1><p>第一个层次是<strong>关注产品本身</strong>,即只会考虑产品本身系统的事情,不会考虑系统外的事情,例:后期与第三方系统对接的问题等。</p>
  57. <h1 id="关注整个系统"><a href="#关注整个系统" class="headerlink" title="关注整个系统"></a>关注整个系统</h1><p>第二个层次是<strong>关注整个系统</strong>,在上了规模的产品中,大多是多个系统之间的配合,因此除了要关注自己的系统之外,还要考虑到与其它系统之间的协作。</p>
  58. <h1 id="关注产品背后的价值"><a href="#关注产品背后的价值" class="headerlink" title="关注产品背后的价值"></a>关注产品背后的价值</h1><p>第三个层次是<strong>关注产品可能潜在的价值</strong>,除了技术的要素,重点关注的是价值,即该产品可能带来的价值。</p>
  59. <h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><p>以上内容是阅读别人文章后的心得,并计划在后续的工作中进行尝试,记录于2019-06-24 22:30。</p>
  60. <h1 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h1><p><a href="https://blog.51cto.com/frankfan/1248401">架构设计师—你在哪层楼?</a></p>
  61. ]]></content>
  62. <categories>
  63. <category>架构师</category>
  64. </categories>
  65. <tags>
  66. <tag>架构师</tag>
  67. </tags>
  68. </entry>
  69. <entry>
  70. <title>科学的重复</title>
  71. <url>/posts/ab6871d9.html</url>
  72. <content><![CDATA[<p>想要学习效果好,记忆是个绕不开的话题,通过科学的重复记忆,就能显著的提高记忆效果。</p>
  73. <span id="more"></span>
  74. <h1 id="遗忘曲线"><a href="#遗忘曲线" class="headerlink" title="遗忘曲线"></a>遗忘曲线</h1><blockquote>
  75. <p>遗忘曲线(又名:艾宾浩斯遗忘曲线)揭示了人类大脑对于新事物的记忆规律:遗忘是先快后慢,最有趋于稳定。</p>
  76. </blockquote>
  77. <h1 id="启示"><a href="#启示" class="headerlink" title="启示"></a>启示</h1><p>根据遗忘曲线的特性,在关键时间点上进行重复复习,即可事半功倍的进行记忆。</p>
  78. <p>关键时间点:一般记住后,在5分钟后重复一遍,30分钟后再重复一遍,12小时后,1天后,2天后,4天后,7天后,15天后就会记得很牢。</p>
  79. <h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><p>并不需要一定要严格按照上述的时间点进行复习,只需要在大概的时间重复记忆一下内容即可,其本质是:重复记忆。</p>
  80. <p>计划在后续中进行尝试,并记录下心得。</p>
  81. <p>记录于2019-06-24 23:04,开始尝试。</p>
  82. <h1 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h1><p><a href="https://baike.baidu.com/item/%E9%81%97%E5%BF%98%E6%9B%B2%E7%BA%BF/7278665?fromtitle=%E8%89%BE%E5%AE%BE%E6%B5%A9%E6%96%AF%E9%81%97%E5%BF%98%E6%9B%B2%E7%BA%BF&fromid=3905802">艾宾浩斯遗忘曲线</a></p>
  83. <p><a href="https://www.zhihu.com/question/31136262">如何利用遗忘曲线来有效记忆?</a></p>
  84. ]]></content>
  85. <categories>
  86. <category>学习</category>
  87. <category>记忆</category>
  88. </categories>
  89. <tags>
  90. <tag>学习</tag>
  91. <tag>记忆</tag>
  92. </tags>
  93. </entry>
  94. <entry>
  95. <title>Linux操作指南:01-新建用户</title>
  96. <url>/posts/1eb05570.html</url>
  97. <content><![CDATA[<p>在Linux上root用户拥有最高的权限,但是多人共享root账户或者直接使用root账户都是一件危险的事情,因此新建普通用户给其它操作员是一件顺理成章的事情。</p>
  98. <span id="more"></span>
  99. <p><strong>注:演示使用的Linux操作系统是Centos 7</strong></p>
  100. <h1 id="用户操作"><a href="#用户操作" class="headerlink" title="用户操作"></a>用户操作</h1><h2 id="新增用户"><a href="#新增用户" class="headerlink" title="新增用户"></a>新增用户</h2><p>全新的Linux系统默认都是只有root账户,因此通过root用户来创建用户,当然也可以使用具备新建用户的权限的用户来创建用户</p>
  101. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">useradd test</span><br></pre></td></tr></table></figure>
  102. <p>此时通过查看命令即可看到home目录下多了个test目录,即代表用户test已经成功创建</p>
  103. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> ls -l 查看命令</span></span><br><span class="line">ls -l /home</span><br><span class="line">drwx------ 2 test test 4096 Jan 10 21:32 test</span><br></pre></td></tr></table></figure>
  104. <h1 id="修改用户密码"><a href="#修改用户密码" class="headerlink" title="修改用户密码"></a>修改用户密码</h1><p>使用<em>useradd</em>命令创建用户后,此时由于没有设置密码,该新建的账户是无法登陆使用的,因此需要给该新账户添加密码(注:修改密码使用的是同一个命令)</p>
  105. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> passwd 修改密码命令</span></span><br><span class="line">passwd test</span><br><span class="line">New password: </span><br></pre></td></tr></table></figure>
  106. <p>此时即可输入新密码了,但是会发现好像一直按键盘都是空的,这就是Linux的安全策略,光给密码打码还不够安全,连长度都不知道才是真的安全,输入完密码按回车键即可</p>
  107. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">passwd test</span><br><span class="line">New password: </span><br><span class="line">Retype new password: </span><br></pre></td></tr></table></figure>
  108. <p>输入完第一次后还会要求你再重复输入一次,以防你输入错误的密码</p>
  109. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">passwd test</span><br><span class="line">New password: </span><br><span class="line">Retype new password: </span><br><span class="line">passwd: all authentication tokens updated successfully.</span><br></pre></td></tr></table></figure>
  110. <p>两次输入密码成功后会出现成功的提示信息,此时新建账户已经可以使用了。</p>
  111. <p>但是有时候可不是这么顺利,比如说输入的密码太短:</p>
  112. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">passwd test</span><br><span class="line">New password: </span><br><span class="line">BAD PASSWORD: The password is shorter than 8 characters</span><br></pre></td></tr></table></figure>
  113. <p>或者输入的密码中包含用户名</p>
  114. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">passwd test</span><br><span class="line">New password:</span><br><span class="line">BAD PASSWORD: The password contains the user name in some form</span><br></pre></td></tr></table></figure>
  115. <p>又或者输入的密码太简单</p>
  116. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">passwd test</span><br><span class="line">New password:</span><br><span class="line">BAD PASSWORD: The password fails the dictionary check - it is too simplistic/systematic</span><br></pre></td></tr></table></figure>
  117. <p>以上的几种情况都会导致输入的密码无效,要重新输入新的密码。</p>
  118. <h2 id="删除用户"><a href="#删除用户" class="headerlink" title="删除用户"></a>删除用户</h2><p>新建的用户在使用一段时间后可能会面临删账户的情况,使用如下命令:</p>
  119. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">userdel test</span><br></pre></td></tr></table></figure>
  120. <p>但是这样只是仅仅删除了账户,而home目录下的账户目录是没有被删除的,因此可以选择加入参数*-R*在删除账户的同时删除对应的用户目录。</p>
  121. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">userdel -R test</span><br></pre></td></tr></table></figure>
  122. <h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><p>以上就是在Linux中关于账户的一些常用操作。</p>
  123. ]]></content>
  124. <categories>
  125. <category>Linux</category>
  126. </categories>
  127. <tags>
  128. <tag>Linux</tag>
  129. </tags>
  130. </entry>
  131. <entry>
  132. <title>Linux操作指南:02-配置防火墙端口</title>
  133. <url>/posts/c62f803c.html</url>
  134. <content><![CDATA[<p>新装的Linux系统,ssh、nginx、tomcat等各种服务都安装好了,可是在外网却访问不了??这十有八九是防火墙的端口没有打开了。</p>
  135. <span id="more"></span>
  136. <h1 id="环境"><a href="#环境" class="headerlink" title="环境"></a>环境</h1><p>系统:CentOS 7</p>
  137. <h1 id="firewall-cmd与iptables"><a href="#firewall-cmd与iptables" class="headerlink" title="firewall-cmd与iptables"></a>firewall-cmd与iptables</h1><p>到了CentOS 7,防火墙的操作命令由<em>iptables</em>改为了<em>firewall-cmd</em>了。以下是摘抄自<a href="https://wangchujiang.com/linux-command/c/firewall-cmd.html">他人</a>的解释:</p>
  138. <blockquote>
  139. <p>firewall-cmd 是 firewalld的字符界面管理工具,firewalld是centos7的一大特性,最大的好处有两个:支持动态更新,不用重启服务;第二个就是加入了防火墙的“zone”概念。</p>
  140. <p>firewalld跟iptables比起来至少有两大好处:</p>
  141. <ol>
  142. <li>firewalld可以动态修改单条规则,而不需要像iptables那样,在修改了规则后必须得全部刷新才可以生效。</li>
  143. <li>firewalld在使用上要比iptables人性化很多,即使不明白“五张表五条链”而且对TCP/IP协议也不理解也可以实现大部分功能。</li>
  144. </ol>
  145. <p>firewalld自身并不具备防火墙的功能,而是和iptables一样需要通过内核的netfilter来实现,也就是说firewalld和 iptables一样,他们的作用都是用于维护规则,而真正使用规则干活的是内核的netfilter,只不过firewalld和iptables的结 构以及使用方法不一样罢了。</p>
  146. </blockquote>
  147. <p>总的来说这次变更带来的直观好处就是变的更方便更好用了。</p>
  148. <h1 id="端口开发的两种方式"><a href="#端口开发的两种方式" class="headerlink" title="端口开发的两种方式"></a>端口开发的两种方式</h1><p>开放端口有两种方式:指定端口和指定服务。</p>
  149. <p>指定端口很好理解,就是写上那个端口号就开放那个端口。</p>
  150. <p>指定服务可以理解为内置的一个端口映射,默认情况下:ssh服务端口是22、http服务端口是80、MySQL服务端口是3306、tomcat服务端口是8080,因此用服务名来代替直接指定端口,方便记忆和使用。</p>
  151. <p><strong>要注意的是:通过指定服务名开放的就要通过指定服务名关闭;通过指定端口号开放的就要通过指定端口号关闭,且指定端口的时候一定要指定是什么协议,tcp 还是 udp。</strong></p>
  152. <h1 id="permanent参数和zone参数"><a href="#permanent参数和zone参数" class="headerlink" title="permanent参数和zone参数"></a>permanent参数和zone参数</h1><p>配置端口的时候这两个参数是会经常使用到的。</p>
  153. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">firewall-cmd --permanent</span><br></pre></td></tr></table></figure>
  154. <p>这个很好理解,就是让配置永久生效的意思。</p>
  155. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">firewall-cmd --zone=public</span><br></pre></td></tr></table></figure>
  156. <p><strong>zone</strong>参数就难以理解一点,这个参数的作用是指定一套规则集合,依靠这些规则来判断是否放行数据。这里使用的规则集是<strong>public</strong>,即只放行已配置的服务(端口)。</p>
  157. <p>更详细的可以参考:<a href="http://www.excelib.com/article/287/show/#g5vTC3">Firewalld的结构</a>,<a href="https://www.cnblogs.com/excelib/p/5155951.html">用活Firewalld防火墙中的zone</a></p>
  158. <h1 id="firewall-cmd常用命令"><a href="#firewall-cmd常用命令" class="headerlink" title="firewall-cmd常用命令"></a>firewall-cmd常用命令</h1><p>增加端口</p>
  159. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 指定端口</span></span><br><span class="line">firewall-cmd --zone=public --add-port=80/tcp --permanent</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 指定服务</span></span><br><span class="line">firewall-cmd --add-service=http --permanent</span><br></pre></td></tr></table></figure>
  160. <p>移除端口</p>
  161. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 指定端口</span></span><br><span class="line">firewall-cmd --permanent --remove-port=80/tcp</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 指定服务</span></span><br><span class="line">firewall-cmd --permanent --remove-service=http</span><br></pre></td></tr></table></figure>
  162. <p>显示防火墙运行状态</p>
  163. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">firewall-cmd --state</span><br></pre></td></tr></table></figure>
  164. <p>仅显示打开的端口信息</p>
  165. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">firewall-cmd --list-ports</span><br></pre></td></tr></table></figure>
  166. <p>仅显示增加的服务信息</p>
  167. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">firewall-cmd --list-service</span><br></pre></td></tr></table></figure>
  168. <p>显示所有信息</p>
  169. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">firewall-cmd --list-all</span><br></pre></td></tr></table></figure>
  170. <p>配置完之后,必须要重启防火墙让配置生效,如下命令的意思是不中断连接重新加载防火墙配置</p>
  171. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">firewall-cmd --reload</span><br></pre></td></tr></table></figure>
  172. <h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><p>这里只是列举了自己常用的一些命令,更具体的可以参考以下文章</p>
  173. <ul>
  174. <li><p><a href="https://wangchujiang.com/linux-command/c/firewall-cmd.html">firewall-cmd详解</a></p>
  175. </li>
  176. <li><p><a href="http://www.excelib.com/article/287/show/#g5vTC3">Firewalld的结构</a></p>
  177. </li>
  178. <li><p><a href="https://www.cnblogs.com/excelib/p/5155951.html">用活Firewalld防火墙中的zone</a></p>
  179. </li>
  180. </ul>
  181. ]]></content>
  182. <categories>
  183. <category>Linux</category>
  184. </categories>
  185. <tags>
  186. <tag>Linux</tag>
  187. </tags>
  188. </entry>
  189. <entry>
  190. <title>Linux设置时区</title>
  191. <url>/posts/35e905e4.html</url>
  192. <content><![CDATA[<p>如果服务器在国外且所在时区不一致,那么使用<code>date</code>命令查看时间的话,会看到另外一个时区的时间,为了符合生活习惯需要设置新的时区。</p>
  193. <p>假设一个场景:凌晨3点人少的时候重启服务器。这样写crontab定时任务就有点麻烦了,因为要以自己的时间计算服务器所在时区的时间,因此把服务器时区设置为自己生活所在的时区还是挺有必要的。</p>
  194. <span id="more"></span>
  195. <p>设置方法如下</p>
  196. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 选择时区,在这里选了中国时区Asia/Shanghai</span></span><br><span class="line">cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 会提示</span></span><br><span class="line">cp: overwrite ‘/etc/localtime’?</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 输入确认y</span></span><br><span class="line">cp: overwrite ‘/etc/localtime’? y</span><br></pre></td></tr></table></figure>
  197. <p>PS1:这里只是使用了其中一种方法,其它设置方法可以参考<a href="https://blog.csdn.net/gezilan/article/details/79422864">Linux如何设置时区、时间</a>。</p>
  198. <p>PS2:如果时区对上了,但是具体的时间对不上,可能是没有使用ntp同步互联网时间。</p>
  199. ]]></content>
  200. <categories>
  201. <category>Linux</category>
  202. </categories>
  203. <tags>
  204. <tag>Linux</tag>
  205. </tags>
  206. </entry>
  207. <entry>
  208. <title>Linux配置IPV6地址</title>
  209. <url>/posts/ef0b8374.html</url>
  210. <content><![CDATA[<p>一般的服务器都是没有提供IPV6地址的,但是有时候我们又会需要使用到,例如访问谷歌经常会弹出人机验证非常讨厌,这时候使用IPV6进行访问就不需要再验证了。</p>
  211. <span id="more"></span>
  212. <h1 id="环境"><a href="#环境" class="headerlink" title="环境"></a>环境</h1><p>系统:CentOS 7</p>
  213. <h1 id="免费IPV6"><a href="#免费IPV6" class="headerlink" title="免费IPV6"></a>免费IPV6</h1><p>这是一个免费资源,是由HE(HURRICANE ELECTRIC)提供的,通过技术手段连上HE提供的服务器,实现IPV4转IPV6,我们就间接有了IPV6访问的能力了。</p>
  214. <p>具体的获取教程请参考<a href="https://zhuanlan.zhihu.com/p/344450513">HE的IPV6注册</a>,目的是在HE中获取如下的配置内容:</p>
  215. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">modprobe ipv6</span><br><span class="line">ip tunnel add he-ipv6 mode sit remote 216.218.200.58 local 替换你的ipv4地址 ttl 255</span><br><span class="line">ip link set he-ipv6 up</span><br><span class="line">ip addr add 替换获得的ipv6地址 dev he-ipv6</span><br><span class="line">ip route add ::/0 dev he-ipv6</span><br><span class="line">ip -f inet6 addr</span><br></pre></td></tr></table></figure>
  216. <h1 id="自动配置IPV6"><a href="#自动配置IPV6" class="headerlink" title="自动配置IPV6"></a>自动配置IPV6</h1><p>如果直接执行上述的命令,由于这些命令都是临时生效的,每次重启服务器都需要重新执行一次。因此我们要设置为自动执行。操作过程如下</p>
  217. <ol>
  218. <li>首先新建一个脚本ipv6.sh,脚本示例如下</li>
  219. </ol>
  220. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 当前目录是:/home/demo 文件具体路径:/home/demo/ipv6.sh</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> 创建脚本ipv6.sh</span></span><br><span class="line">vi ipv6.sh</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 脚本内容如下</span></span><br><span class="line"><span class="meta">#</span><span class="bash">!/bin/bash</span></span><br><span class="line"></span><br><span class="line">modprobe ipv6</span><br><span class="line">ip tunnel add he-ipv6 mode sit remote 216.218.200.58 local 替换你的ipv4地址 ttl 255</span><br><span class="line">ip link set he-ipv6 up</span><br><span class="line">ip addr add 替换获得的ipv6地址 dev he-ipv6</span><br><span class="line">ip route add ::/0 dev he-ipv6</span><br><span class="line">ip -f inet6 addr</span><br></pre></td></tr></table></figure>
  221. <ol start="2">
  222. <li>保存退出后,赋予执行权限</li>
  223. </ol>
  224. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 授予执行权限</span></span><br><span class="line">chmod +x ipv6.sh</span><br></pre></td></tr></table></figure>
  225. <ol start="3">
  226. <li>在rc.local文件中加入执行ipv6.sh的命令,最后保存退出,等到下次重启服务器就能看到效果了。</li>
  227. </ol>
  228. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 编辑rc.local脚本</span></span><br><span class="line">vi /etc/rc.local</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 加入如下内容,记得替换成自己的路径</span></span><br><span class="line">/home/demo/ipv6.sh</span><br></pre></td></tr></table></figure>
  229. <p>rc.local脚本,是Linux系统自带的脚本,每次系统启动时都会执行一遍脚本中的命令,我们就是通过这个机制来自动执行ipv6设置。</p>
  230. <h1 id="检查配置是否生效"><a href="#检查配置是否生效" class="headerlink" title="检查配置是否生效"></a>检查配置是否生效</h1><p>想要立刻重启服务器,可以使用命令<em>reboot</em>,重启后输入网络查看命令<em>ifconfig</em>,找到<em>he-ipv6</em>这个网络接口,如果能找到就代表配置成功了。</p>
  231. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 重启服务器</span></span><br><span class="line">reboot</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 查看网络信息</span></span><br><span class="line">ifconfig</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 找到he-ipv6这个名字,这个名字是在上面的配置中名命的,不是自动生成的</span></span><br><span class="line">he-ipv6: flags=209&lt;UP,POINTOPOINT,RUNNING,NOARP&gt; mtu 1480</span><br><span class="line"> inet6 ipv6地址 prefixlen 64 scopeid 0x0&lt;global&gt;</span><br><span class="line"> inet6 ipv6地址 prefixlen 64 scopeid 0x20&lt;link&gt;</span><br><span class="line"> sit txqueuelen 1000 (IPv6-in-IPv4)</span><br><span class="line"> RX packets 1575 bytes 555832 (542.8 KiB)</span><br><span class="line"> RX errors 0 dropped 0 overruns 0 frame 0</span><br><span class="line"> TX packets 1654 bytes 407621 (398.0 KiB)</span><br><span class="line"> TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0</span><br><span class="line"></span><br></pre></td></tr></table></figure>
  232. <h1 id="使用IPV6访问"><a href="#使用IPV6访问" class="headerlink" title="使用IPV6访问"></a>使用IPV6访问</h1><p>尝试使用IPV6访问一下谷歌</p>
  233. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> ping6 就是用ipv6进行访问</span></span><br><span class="line">ping6 google.com</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 提示错误</span></span><br><span class="line">connect: Network is unreachable</span><br></pre></td></tr></table></figure>
  234. <p>(这是我猜的)应该是由于缺少IPV6域名地址的解析能力,无法正确获得IPV6地址,因此访问失败。因此通过在hosts文件中加入谷歌的IPV6地址,尝试绕过解析这一步骤</p>
  235. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 修改host文件</span></span><br><span class="line">vi /etc/hosts</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 加入谷歌的IPV6地址</span></span><br><span class="line">2404:6800:4008:c00::71 google.com</span><br><span class="line">2404:6800:4008:c02::63 www.google.com</span><br></pre></td></tr></table></figure>
  236. <p>修改完hosts文件后要重新加载网络信息才能生效</p>
  237. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 重启网络</span></span><br><span class="line">systemctl restart network</span><br></pre></td></tr></table></figure>
  238. <p>由于上一步重启了网络,因此要重新配置IPV6,执行一下ipv6.sh脚本即可</p>
  239. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">/home/demo/ipv6.sh</span><br></pre></td></tr></table></figure>
  240. <p>再次访问</p>
  241. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">ping6 google.com</span><br><span class="line"></span><br><span class="line">PING google.com(google.com (2404:6800:4008:c00::71)) 56 data bytes</span><br><span class="line">64 bytes from google.com (2404:6800:4008:c00::71): icmp_seq=1 ttl=107 time=224 ms</span><br><span class="line">64 bytes from google.com (2404:6800:4008:c00::71): icmp_seq=2 ttl=107 time=224 ms</span><br><span class="line">64 bytes from google.com (2404:6800:4008:c00::71): icmp_seq=3 ttl=107 time=223 ms</span><br></pre></td></tr></table></figure>
  242. <p>这次就成功了,其中的IPV6地址就是我们在hosts文件中填的那个。</p>
  243. <h1 id="shadowsocks使用IPV6"><a href="#shadowsocks使用IPV6" class="headerlink" title="shadowsocks使用IPV6"></a>shadowsocks使用IPV6</h1><p>使用shadowsocks有个重要用途就是使用谷歌搜索,但是如果IP或者IP段被谷歌标记了的话,经常会弹出人机验证非常讨厌,通过使用IPV6的话就可以避开这个验证。</p>
  244. <p>shadowsocks使用IPV6非常简单,简单的加入如下配置即可</p>
  245. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 编辑配置文件</span></span><br><span class="line">vi /etc/shadowsocks-libev/config.json</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 加入配置项</span></span><br><span class="line">&quot;ipv6_first&quot;:true</span><br></pre></td></tr></table></figure>
  246. <p>然后重启shadowsocks服务即可。</p>
  247. ]]></content>
  248. <categories>
  249. <category>Linux</category>
  250. </categories>
  251. <tags>
  252. <tag>Linux</tag>
  253. </tags>
  254. </entry>
  255. <entry>
  256. <title>Nginx开启Gzip压缩</title>
  257. <url>/posts/84bf135c.html</url>
  258. <content><![CDATA[<p>有些资源文件的体积比较大,开启nginx的gzip压缩,能够极大的提升传输的效率。</p>
  259. <span id="more"></span>
  260. <h1 id="环境"><a href="#环境" class="headerlink" title="环境"></a>环境</h1><p>系统:CentOS 7</p>
  261. <p>Nginx版本:1.16.1</p>
  262. <h1 id="配置方式"><a href="#配置方式" class="headerlink" title="配置方式"></a>配置方式</h1><p>nginx配置为文件服务器的方式非常简单,打开nginx的配置文件,一般在这个路径下</p>
  263. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">vi /etc/nginx/nginx.conf</span><br></pre></td></tr></table></figure>
  264. <p>然后在http、server、location这三个任一代码块(只是影响了生效的范围)中加入如下关键指令即可</p>
  265. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash">开启gzip压缩 默认关闭off</span></span><br><span class="line">gzip on;</span><br><span class="line"><span class="meta">#</span><span class="bash">IE版本1-6不支持gzip压缩,关闭</span></span><br><span class="line">gzip_disable &#x27;MSIE[1-6].&#x27;;</span><br><span class="line"><span class="meta">#</span><span class="bash">需要压缩的文件格式 text/html默认会压缩,不用添加</span></span><br><span class="line">gzip_types text/css text/javascript application/javascript image/jpeg image/png image/gif; </span><br><span class="line"><span class="meta">#</span><span class="bash">给响应头加个vary,告知客户端能否缓存</span></span><br><span class="line">gzip_vary on; </span><br><span class="line"><span class="meta">#</span><span class="bash"> 默认值是 4 4k/8k,设置系统获取几个单位的缓存用于存储gzip的压缩结果数据流。 例如 4 4k 代表以4k为单位,按照原始数据大小以4k为单位的4倍申请内存。 4 8k 代表以8k为单位,按照原始数据大小以8k为单位的4倍申请内存。</span></span><br><span class="line">gzip_buffers 4 8k;</span><br><span class="line"><span class="meta">#</span><span class="bash"> 压缩等级1~9,默认值1,1级别最低压缩速度最快但是压缩比最小,9级别最高压缩速度最慢但压缩比最大,建议根据自己情况测试一下那个级别适合自己,偷懒的话网上看的大多数都是设成1或者4</span></span><br><span class="line">gzip_comp_level 1; </span><br><span class="line"><span class="meta">#</span><span class="bash"> 默认值0 文件大小大于该值时才进行压缩,单位为Byte,写1k即1024B,当值为0时所有页面都进行压缩,建议设置成大于1k的字节数</span></span><br><span class="line">gzip_min_length 1k; </span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 这个不熟悉</span></span><br><span class="line">gzip_proxied # 默认关闭off 用于反向代理的时候是否开启压缩,具体参数建议看下文的参考文章</span><br></pre></td></tr></table></figure>
  266. <p>具体示例</p>
  267. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">http &#123;</span><br><span class="line"> ......</span><br><span class="line"> server &#123;</span><br><span class="line"> ......</span><br><span class="line"> location / &#123;</span><br><span class="line"> gzip on;</span><br><span class="line"> gzip_disable &#x27;MSIE[1-6].&#x27;;</span><br><span class="line"> gzip_types text/css text/javascript application/javascript image/jpeg image/png image/gif; </span><br><span class="line"> gzip_buffers 4 4k;</span><br><span class="line"> gzip_comp_level 1;</span><br><span class="line"> gzip_min_length 20;</span><br><span class="line"> gzip_vary on; </span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
  268. <p>写完配置文件后检查一下有没有写错(可省略)</p>
  269. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">nginx -t</span><br></pre></td></tr></table></figure>
  270. <p>最后就是让nginx重新加载让配置生效</p>
  271. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">nginx -s reload</span><br></pre></td></tr></table></figure>
  272. <h1 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h1><p><a href="https://www.nginx.cn/doc/standard/httpgzip.html">Nginx Gzip模块中文参考</a></p>
  273. ]]></content>
  274. <categories>
  275. <category>Nginx</category>
  276. </categories>
  277. <tags>
  278. <tag>服务器</tag>
  279. <tag>Nginx</tag>
  280. </tags>
  281. </entry>
  282. <entry>
  283. <title>Nginx配置SSL证书</title>
  284. <url>/posts/ecc40a95.html</url>
  285. <content><![CDATA[<p>HTTP连接是不安全的,数据是明文传输的,如果有敏感数据这就直接暴露在互联网环境下是很危险的行为,因此为Nginx配置SSL证书,使用安全的HTTPS进行访问是非常有必要的。</p>
  286. <span id="more"></span>
  287. <h1 id="环境"><a href="#环境" class="headerlink" title="环境"></a>环境</h1><p>系统:CentOS 7</p>
  288. <p>Nginx版本:1.16.1</p>
  289. <h1 id="SSL证书"><a href="#SSL证书" class="headerlink" title="SSL证书"></a>SSL证书</h1><p>Nginx需要使用到的SSL证书分为了两部分:key和pem,这个证书是唯一的。</p>
  290. <p>具体的获得方式要自己去域名服务提供商里找了,至于SSL是啥,我自己也很难说清楚,请自行百度吧。</p>
  291. <h1 id="SSL配置方式"><a href="#SSL配置方式" class="headerlink" title="SSL配置方式"></a>SSL配置方式</h1><p>nginx配置启用SSL的方式非常简单,打开nginx的配置文件,一般在这个路径下</p>
  292. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">vi /etc/nginx/nginx.conf</span><br></pre></td></tr></table></figure>
  293. <p>然后在server块中加入如下关键指令即可</p>
  294. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">listen 443 ssl; # 443是默认的HTTPS端口 ssl指的启用SSL安全配置的意思,在较旧的版本中是单独写成ssl on形式</span><br><span class="line"><span class="meta">#</span><span class="bash"> 证书放在了/etc/nginx/cert目录下,由于cert目录与nginx.conf配置文件处于同级目录下,因此可以写成cert/,</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> 如果是其它地方建议直接写成绝对路径 例如:/home/nginx/cert/cert-file-name.pem</span></span><br><span class="line">ssl_certificate cert/cert-file-name.pem; # ssl证书 需要将cert-file-name.pem替换成已上传的证书文件的名称。</span><br><span class="line">ssl_certificate_key cert/cert-file-name.key; # ssl证书需要将cert-file-name.key替换成已上传的证书密钥文件的名称。</span><br><span class="line"></span><br><span class="line">ssl_session_timeout 5m; # 会话的超时时间,m指分钟</span><br><span class="line">ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4; # 加密算法</span><br><span class="line"><span class="meta">#</span><span class="bash">表示使用的加密套件的类型。</span></span><br><span class="line">ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # 表示使用的TLS协议的类型。</span><br><span class="line">ssl_prefer_server_ciphers on; # 设置协商加密算法时,优先使用我们服务端的加密套件,而不是客户端浏览器的加密套件</span><br><span class="line"></span><br></pre></td></tr></table></figure>
  295. <p>具体示例</p>
  296. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">http &#123;</span><br><span class="line"> ......</span><br><span class="line"> server &#123;</span><br><span class="line"> listen 443 ssl;</span><br><span class="line"> ssl_certificate cert/cert-file-name.pem; </span><br><span class="line"> ssl_certificate_key cert/cert-file-name.key;</span><br><span class="line"> ssl_session_timeout 5m;</span><br><span class="line"> ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;</span><br><span class="line"> ssl_protocols TLSv1 TLSv1.1 TLSv1.2;</span><br><span class="line"> ssl_prefer_server_ciphers on;</span><br><span class="line"> </span><br><span class="line"> ......</span><br><span class="line"> </span><br><span class="line"> location / &#123;</span><br><span class="line"> ......</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
  297. <h1 id="重定向"><a href="#重定向" class="headerlink" title="重定向"></a>重定向</h1><p>既然已经开启了SSL实现了HTTPS,那么普通的HTTP传输就不再需要了,但是每次输入网址都要刻意输入<em>https</em>还是很繁琐的,因此加入重定向配置</p>
  298. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">http &#123;</span><br><span class="line"> ......</span><br><span class="line"> server &#123;</span><br><span class="line"> listen 80; # http访问的端口</span><br><span class="line"> ......</span><br><span class="line"> rewrite ^(.*)$ https://$host$1; #将所有HTTP请求通过rewrite指令重定向到HTTPS。</span><br><span class="line"> ......</span><br><span class="line"> &#125;</span><br><span class="line"> </span><br><span class="line"><span class="meta"> #</span><span class="bash"> 无效了。已经重定向永远到不了了</span></span><br><span class="line"> server &#123;</span><br><span class="line"> listen 80;</span><br><span class="line"> ......</span><br><span class="line"> &#125;</span><br><span class="line"> </span><br><span class="line"><span class="meta"> #</span><span class="bash"> 有效</span></span><br><span class="line"> server &#123;</span><br><span class="line"> listen 443 ssl;</span><br><span class="line"> ......</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
  299. <p>这样写后,所有的HTTP访问最终都会重定向到HTTPS,需要注意:这样配置后其它的监听80端口的配置就都失效了,因为都重定向了,需要更新相应的配置了。</p>
  300. <p>写完配置文件后检查一下有没有写错(可省略)</p>
  301. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">nginx -t</span><br></pre></td></tr></table></figure>
  302. <p>最后就是让nginx重新加载让配置生效</p>
  303. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">nginx -s reload</span><br></pre></td></tr></table></figure>
  304. ]]></content>
  305. <categories>
  306. <category>Nginx</category>
  307. </categories>
  308. <tags>
  309. <tag>服务器</tag>
  310. <tag>Nginx</tag>
  311. </tags>
  312. </entry>
  313. <entry>
  314. <title>Nginx配置为代理服务器</title>
  315. <url>/posts/55e0da5c.html</url>
  316. <content><![CDATA[<p>Nginx作为代理服务器是一个很常见的用途,例如内部有一个tomcat服务但是又不想开放8080端口,通过配置代理可以在只开放80端口的情况下访问到内部的tomcat服务了。</p>
  317. <span id="more"></span>
  318. <h1 id="环境"><a href="#环境" class="headerlink" title="环境"></a>环境</h1><p>系统:CentOS 7</p>
  319. <p>Nginx版本:1.16.1</p>
  320. <h1 id="配置方式"><a href="#配置方式" class="headerlink" title="配置方式"></a>配置方式</h1><p>nginx配置为文件服务器的方式非常简单,打开nginx的配置文件,一般在这个路径下</p>
  321. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">vi /etc/nginx/nginx.conf</span><br></pre></td></tr></table></figure>
  322. <p>然后在location块中加入如下关键指令即可</p>
  323. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> proxy_set_header作用是设置请求头,代理会使部分信息丢失,因此需要重新设置方便获得真实访问信息</span></span><br><span class="line">proxy_set_header Host $host;</span><br><span class="line">proxy_set_header X-Real-IP $remote_addr;</span><br><span class="line">proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 关键 proxy_pass 代理转发需要到达的目的地,可以是其它任何想要访问的地址</span></span><br><span class="line">proxy_pass http://127.0.0.1:3000/;</span><br></pre></td></tr></table></figure>
  324. <p>具体示例</p>
  325. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">http &#123;</span><br><span class="line"> ......</span><br><span class="line"> server &#123;</span><br><span class="line"> ......</span><br><span class="line"> location / &#123;</span><br><span class="line"> proxy_set_header Host $host;</span><br><span class="line"> proxy_set_header X-Real-IP $remote_addr;</span><br><span class="line"> proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;</span><br><span class="line"> proxy_pass http://127.0.0.1:8080/;</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
  326. <p>写完配置后检查一下有没有写错(可省略)</p>
  327. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">nginx -t</span><br></pre></td></tr></table></figure>
  328. <p>最后就是让nginx重新加载让配置生效</p>
  329. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">nginx -s reload</span><br></pre></td></tr></table></figure>]]></content>
  330. <categories>
  331. <category>Nginx</category>
  332. </categories>
  333. <tags>
  334. <tag>服务器</tag>
  335. <tag>Nginx</tag>
  336. </tags>
  337. </entry>
  338. <entry>
  339. <title>Nginx配置为文件服务器</title>
  340. <url>/posts/4eef1a76.html</url>
  341. <content><![CDATA[<p>我们经常会遇到从远程服务器下载文件的情况,如果直接使用ftp或者sftp的进行下载的话,下载速度总是不甚满意,网络差的话简直让人抓狂要砸键盘了。这情况可以考虑用Nginx做文件服务器,然后使用IDM(设置为32个线程同时工作)下载,那下载速度可是杠杠的带宽都要跑满了。</p>
  342. <span id="more"></span>
  343. <h1 id="环境"><a href="#环境" class="headerlink" title="环境"></a>环境</h1><p>系统:CentOS 7</p>
  344. <p>Nginx版本:1.16.1</p>
  345. <h1 id="配置方式"><a href="#配置方式" class="headerlink" title="配置方式"></a>配置方式</h1><p>nginx配置为文件服务器的方式非常简单,打开nginx的配置文件,一般在这个路径下</p>
  346. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">vi /etc/nginx/nginx.conf</span><br></pre></td></tr></table></figure>
  347. <p>然后在location块中加入如下关键指令即可</p>
  348. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">语法: autoindex on | off;</span><br><span class="line">描述:开启或禁用目录浏览功能,默认是禁用</span><br><span class="line"></span><br><span class="line">语法:autoindex_exact_size off|on;</span><br><span class="line">描述:默认为on,显示出文件的确切大小,单位是bytes。一般会改为off,显示出文件的大概大小,单位是kB或者MB或者GB</span><br><span class="line"></span><br><span class="line">语法:autoindex_format html | xml | json | jsonp</span><br><span class="line">描述:设置目录列表的格式,默认是html</span><br><span class="line"></span><br><span class="line">语法:autoindex_localtime on|off; </span><br><span class="line">描述:on显示文件的本地时间(服务器时间),否则显示文件的GMT时间(如果不是在0时区,则会有对不上时间的烦恼),默认是off</span><br></pre></td></tr></table></figure>
  349. <p>具体示例</p>
  350. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">http &#123;</span><br><span class="line"> ......</span><br><span class="line"> server &#123;</span><br><span class="line"> ......</span><br><span class="line"> location / &#123;</span><br><span class="line"> root /home/demo/download; # 可下载文件的路径</span><br><span class="line"> autoindex on; # 开启目录浏览功能 最关键的一个一定要填</span><br><span class="line"> autoindex_exact_size off; # 不显示文件的大小</span><br><span class="line"> autoindex_format html; # 目录列表的格式是html</span><br><span class="line"> autoindex_localtime on; # 使用本地时间</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
  351. <p>写完配置文件后检查一下有没有写错(可省略)</p>
  352. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">nginx -t</span><br></pre></td></tr></table></figure>
  353. <p>最后就是让nginx重新加载让配置生效</p>
  354. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">nginx -s reload</span><br></pre></td></tr></table></figure>
  355. ]]></content>
  356. <categories>
  357. <category>Nginx</category>
  358. </categories>
  359. <tags>
  360. <tag>服务器</tag>
  361. <tag>Nginx</tag>
  362. </tags>
  363. </entry>
  364. <entry>
  365. <title>Redis的3种持久化方式</title>
  366. <url>/posts/9589c4d2.html</url>
  367. <content><![CDATA[<p>redis提供3种持久化机制用于在重启机器或者系统故障后重用数据(恢复场景)。</p>
  368. <span id="more"></span>
  369. <h1 id="方式一:RDB"><a href="#方式一:RDB" class="headerlink" title="方式一:RDB"></a>方式一:RDB</h1><p>RDB(snapshotting,快照,redis快照)某一时刻下redis的数据副本。默认的持久化方式。</p>
  370. <h1 id="方式二:AOF"><a href="#方式二:AOF" class="headerlink" title="方式二:AOF"></a>方式二:AOF</h1><p>AOF(append-only file,只追加文件):只有会更改redis中的数据的执行命令才会写入硬盘中的AOF文件。AOF由三种保存策略:1.no(让操作系统决定何时写入AOF文件);2.always(每次发生数据修改都会写入AOF文件,严重降低redis性能);3.everysec(每秒钟一次写入AOF,可以一次性将多个写入个命令)。AOF持久化方式实时性更好,是主流的持久化方案,而且使用everysec的策略,能够兼顾数据和写入性能,性能几乎没有损失,即使系统储问题也只是丢失1秒内的数据。</p>
  371. <h1 id="方式三:RDB和AOF混合"><a href="#方式三:RDB和AOF混合" class="headerlink" title="方式三:RDB和AOF混合"></a>方式三:RDB和AOF混合</h1><p>RDB和AOF混合,在AOF重写时把RDB的内容写到AOF文件开头,好处是结合了RDB和AOF的有点,快速加载的同时避免丢失过多的数据,缺点是AOF的文件可读性较差。</p>
  372. <h1 id="AOF重写"><a href="#AOF重写" class="headerlink" title="AOF重写"></a>AOF重写</h1><p>AOF重写:redis生成一个新的AOF文件,其保存的数据状态和旧的AOF文件一致,但体积更小(进行了命令优化,排除了无效的命令)。重写期间,redis会维持一个aof重写缓冲区,记录服务器在重写的这段时间执行的修改数据的命令,重建完后,把缓冲区的数据追加到新的AOF文件的末尾,就是一个新的经过重写的AOF文件了,同时也能保持与服务器种的数据状态的一致了。</p>
  373. ]]></content>
  374. <categories>
  375. <category>Redis</category>
  376. </categories>
  377. <tags>
  378. <tag>缓存</tag>
  379. <tag>Redis</tag>
  380. </tags>
  381. </entry>
  382. <entry>
  383. <title>Redis的5种基本数据类型</title>
  384. <url>/posts/7b35ed44.html</url>
  385. <content><![CDATA[<p>redis有5种基本数据类型:string,list,hash,set,sorted set。</p>
  386. <span id="more"></span>
  387. <p>使用场景如下: </p>
  388. <p>string:简单的key-value类型,是二进制安全的。一般用在需要计数的场景,比如:用户的访问次数、热点文章的点赞转发数量等。</p>
  389. <p>list:链表(redis实现的是双向链表),一般应用于发布与订阅或者说消息队列、慢查询</p>
  390. <p>hash:是一个string类型的field和value的映射表。特别适用于存储对象,后续操作时,可以直接仅仅修改对象中某个字段的值。</p>
  391. <p>set:无序集合,集合中的元素没有先后顺序且没有重复数据。适用于存放的数据不能重复以及获取多个数据源交集和并集等场景。</p>
  392. <p>sorted set:与set相比增加了一个权重参数score,能使集合中的元素按照score进行有序排列,适用于需要对数据根据某个权重进行排序的场景,比如在直播系统中,实时排行信息包含直播间在线用户列表,各种礼物排行榜,弹幕消息(可以理解为消息维度的消息排行榜)等信息。</p>
  393. ]]></content>
  394. <categories>
  395. <category>Redis</category>
  396. </categories>
  397. <tags>
  398. <tag>缓存</tag>
  399. <tag>Redis</tag>
  400. </tags>
  401. </entry>
  402. <entry>
  403. <title>Redis的淘汰策略</title>
  404. <url>/posts/e0bb8399.html</url>
  405. <content><![CDATA[<p>redis共有8种淘汰策略。具体可分成3种类型。</p>
  406. <span id="more"></span>
  407. <h1 id="淘汰策略"><a href="#淘汰策略" class="headerlink" title="淘汰策略"></a>淘汰策略</h1><p>类型一<br>no-eviction:禁止淘汰数据,当内存不足无法写入新数据时会报错,真实项目中应该没有人会使用。</p>
  408. <p>类型二(对所有数据而言)<br>allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰<br>allkeys-lru(least recently used):当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的 key(这个是最常用的)<br>allkeys-lfu(least frequently used):当内存不足以容纳新写入数据时,在键空间中,移除最不经常使用的 key</p>
  409. <p>类型三(对于设置了过期时间的数据而言)<br>volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰<br>volatile-ttl(time to live):从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰<br>volatile-lru(least recently used):从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰<br>volatile-lfu(least frequently used):从已设置过期时间的数据集(server.db[i].expires)中挑选最不经常使用的数据淘汰</p>
  410. <p>其中volatile-lfu和allkeys-lfu是4.0之后才加入的策略。</p>
  411. <h1 id="关于LFU和LRU的理解"><a href="#关于LFU和LRU的理解" class="headerlink" title="关于LFU和LRU的理解"></a>关于LFU和LRU的理解</h1><p>LFU按访问频次排序,一个数据被访问则频次+1,淘汰时,把频次最低的淘汰。<br>LRU按访问时间排序,淘汰时,把访问时间最旧的淘汰。</p>
  412. <h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><p>淘汰策略分为了可淘汰和不可淘汰两部分。可淘汰中根据目标数据范围分为了:所有数据和设置了过期时间 这两类,主要的淘汰策略是:随机(random)、最近最少使用(lru)和最不经常使用(lfu),对于设置了过期时间的数据而言还有一个策略就是挑选将要过期的数据(ttl)。</p>
  413. ]]></content>
  414. <categories>
  415. <category>Redis</category>
  416. </categories>
  417. <tags>
  418. <tag>缓存</tag>
  419. <tag>Redis</tag>
  420. </tags>
  421. </entry>
  422. <entry>
  423. <title>Java基本数据类型</title>
  424. <url>/posts/c80e1ec8.html</url>
  425. <content><![CDATA[<p>要用Java必然绕不开它的基本数据类型,</p>
  426. <span id="more"></span>
  427. <h1 id="8种基本数据类型"><a href="#8种基本数据类型" class="headerlink" title="8种基本数据类型"></a>8种基本数据类型</h1><p>Java的基本数据类型分为数值型、布尔值和字符三个大类,共计8种基本数据类型:byte、short、int、long、float、double、boolean、char。</p>
  428. <p><img src="/images/Java%E7%9A%848%E7%A7%8D%E5%9F%BA%E6%9C%AC%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B.png" alt="Java的8种基本数据类型"></p>
  429. <p>基本数据类型对应的位数、字节和默认值如下</p>
  430. <table>
  431. <thead>
  432. <tr>
  433. <th>基本数据类型</th>
  434. <th>位数</th>
  435. <th>字节</th>
  436. <th>默认值</th>
  437. </tr>
  438. </thead>
  439. <tbody><tr>
  440. <td>byte</td>
  441. <td>8</td>
  442. <td>1</td>
  443. <td>0</td>
  444. </tr>
  445. <tr>
  446. <td>short</td>
  447. <td>16</td>
  448. <td>2</td>
  449. <td>0</td>
  450. </tr>
  451. <tr>
  452. <td>int</td>
  453. <td>32</td>
  454. <td>4</td>
  455. <td>0</td>
  456. </tr>
  457. <tr>
  458. <td>long</td>
  459. <td>64</td>
  460. <td>8</td>
  461. <td>0L</td>
  462. </tr>
  463. <tr>
  464. <td>float</td>
  465. <td>32</td>
  466. <td>4</td>
  467. <td>0f</td>
  468. </tr>
  469. <tr>
  470. <td>double</td>
  471. <td>64</td>
  472. <td>8</td>
  473. <td>0d</td>
  474. </tr>
  475. <tr>
  476. <td>char</td>
  477. <td>16</td>
  478. <td>2</td>
  479. <td>u0000</td>
  480. </tr>
  481. <tr>
  482. <td>boolean</td>
  483. <td>1</td>
  484. <td></td>
  485. <td>false</td>
  486. </tr>
  487. </tbody></table>
  488. <p>注:对于boolean,官方文档未明确定义,它依赖于 JVM 厂商的具体实现。逻辑上理解是占用 1 位,但是实际中会考虑计算机高效存储因素。</p>
  489. ]]></content>
  490. <categories>
  491. <category>Java</category>
  492. </categories>
  493. <tags>
  494. <tag>Java</tag>
  495. </tags>
  496. </entry>
  497. <entry>
  498. <title>Java常用名词</title>
  499. <url>/posts/b0269417.html</url>
  500. <content><![CDATA[<p>接触Java开发已经很长一段时间了,对于常见的名词,如:JMS、JDBC、JPA,也基本知道代表的是什么,而JNDI、JTA这些就不知道了,今天特意做个备忘录,记录下在Java中遇到的这些名词,并在后续中不断更新。</p>
  501. <span id="more"></span>
  502. <table>
  503. <thead>
  504. <tr>
  505. <th align="center">名词</th>
  506. <th align="center">全称</th>
  507. <th align="center">中文</th>
  508. </tr>
  509. </thead>
  510. <tbody><tr>
  511. <td align="center">JDBC</td>
  512. <td align="center">Java DataBase Connectivity</td>
  513. <td align="center">Java数据库连接</td>
  514. </tr>
  515. <tr>
  516. <td align="center">JPA</td>
  517. <td align="center">Java Persistence API</td>
  518. <td align="center">Java持久化API</td>
  519. </tr>
  520. <tr>
  521. <td align="center">JTA</td>
  522. <td align="center">Java Transaction API</td>
  523. <td align="center">Java事务API</td>
  524. </tr>
  525. <tr>
  526. <td align="center">JMS</td>
  527. <td align="center">Java Message Service</td>
  528. <td align="center">Java消息服务</td>
  529. </tr>
  530. <tr>
  531. <td align="center">JNDI</td>
  532. <td align="center">Java Naming and Directory Interface</td>
  533. <td align="center">Java命名和目录接口</td>
  534. </tr>
  535. <tr>
  536. <td align="center">POJO</td>
  537. <td align="center">Plain Ordinary Java Object</td>
  538. <td align="center">简单Java对象</td>
  539. </tr>
  540. </tbody></table>
  541. ]]></content>
  542. <categories>
  543. <category>Java</category>
  544. </categories>
  545. <tags>
  546. <tag>Java</tag>
  547. </tags>
  548. </entry>
  549. <entry>
  550. <title>Java的foreach</title>
  551. <url>/posts/4c0b6fc5.html</url>
  552. <content><![CDATA[<p>开发中经常使用到foreach,现在是时候深入了解一下了。</p>
  553. <span id="more"></span>
  554. <h1 id="使用"><a href="#使用" class="headerlink" title="使用"></a>使用</h1><p>foreach是for的增强,基本语法结构:</p>
  555. <figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="comment">// 这里的collection 指数组或集合</span></span><br><span class="line"><span class="keyword">for</span>(T t : collection) &#123;</span><br><span class="line"> ... dosomething ...</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"># 数组</span><br><span class="line"><span class="keyword">int</span>[] a = <span class="keyword">new</span> <span class="keyword">int</span>[]&#123;<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>&#125;;</span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">int</span> i : a) &#123;</span><br><span class="line"> System.out.println(i);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"># 集合</span><br><span class="line">List&lt;String&gt; list = <span class="keyword">new</span> ArrayList();</span><br><span class="line"><span class="keyword">for</span>(String str : list) &#123;</span><br><span class="line"> System.out.println(str);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
  556. <h1 id="优缺点"><a href="#优缺点" class="headerlink" title="优缺点"></a>优缺点</h1><p>由上面的例子可以看到,在写法上foreach与for写法相比是简化了很多。</p>
  557. <p>要注意的一点是:使用foreach能遍历的,使用for也能遍历,反之则不一定能!!!</p>
  558. <p>其次还有一些缺点:</p>
  559. <ul>
  560. <li>对于数组,在遍历过程中需要使用元素下标的,则无能为力。</li>
  561. <li>对于集合,在遍历过程中无法对元素进行增删,否则会报异常,因为我们没法获得迭代器进行操作。</li>
  562. </ul>
  563. <h1 id="遍历的顺序"><a href="#遍历的顺序" class="headerlink" title="遍历的顺序"></a>遍历的顺序</h1><p>有时候我们可能对元素的遍历顺序有要求,那么使用foreach与for的遍历顺序是一致的吗?</p>
  564. <p>答案是一样的!!</p>
  565. <p>通过阅读官方的文档可以知道,对数组使用foreach写法,等同于下面的写法:</p>
  566. <figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; arr.length; i++) &#123;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
  567. <p>而对于集合而言,就和使用迭代器进行遍历一样:</p>
  568. <figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">for</span> (Iterator iterator = collection.iterator(); iterator.hasNext(); ) &#123;</span><br><span class="line"> iterator.next <span class="keyword">do</span> something......</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
  569. <h1 id="迭代器iterator"><a href="#迭代器iterator" class="headerlink" title="迭代器iterator"></a>迭代器iterator</h1><p>对于集合而言,使用foreach的遍历,其实就是在使用迭代器进行遍历,这点通过Java的规范文档可以了解到,也可以通过对Java的class文件反编译观察到,如下图所示:</p>
  570. <p><img src="http://ww1.sinaimg.cn/large/e6dffef4gy1gaqphag66lj21bb0bqtjk.jpg" alt="foreach与迭代器.png"></p>
  571. <p>但是与直接使用iterator不同,使用foreach的过程中,是无法对元素进行增删的,因为iterator是隐含的仅存在于编译后的class文件中,即开发中无法直接获取iterator,因而也就无法执行增删操作。</p>
  572. <h1 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h1><p><a href="https://www.jianshu.com/p/81cec83541be">Java中的foreach遍历顺序</a></p>
  573. <p><a href="https://docs.oracle.com/javase/specs/jls/se7/html/jls-14.html#jls-14.14.2">Java规范文档-看14.14.2. The enhanced for statement部分</a></p>
  574. ]]></content>
  575. <categories>
  576. <category>Java</category>
  577. </categories>
  578. <tags>
  579. <tag>Java</tag>
  580. </tags>
  581. </entry>
  582. <entry>
  583. <title>Map的N种遍历方法</title>
  584. <url>/posts/35b60266.html</url>
  585. <content><![CDATA[<p>开发中经常要使用到集合类Map,现在让我们来研究一下究竟有多少种遍历方法吧。</p>
  586. <span id="more"></span>
  587. <h1 id="使用"><a href="#使用" class="headerlink" title="使用"></a>使用</h1><p>遍历map时,我们想获得啥?</p>
  588. <p>键值对?键?值?</p>
  589. <p>贴心的Java已经定义了如下的三种方法供我们使用:</p>
  590. <ul>
  591. <li>entrySet():获取键值对集合,返回类型是Set</li>
  592. <li>keySet():获取键集合,返回类型是Set</li>
  593. <li>values():获取值集合,返回类型是Collection</li>
  594. </ul>
  595. <p>由上面的返回类型可以知道,我们要遍历map,其实就是要遍历Collection,常用的遍历Collection方法:</p>
  596. <ul>
  597. <li>增强型for</li>
  598. <li>迭代器</li>
  599. <li>Lambda</li>
  600. </ul>
  601. <figure class="highlight java"><table><tr><td class="code"><pre><span class="line">Map&lt;String, Integer&gt; map = <span class="keyword">new</span> HashMap&lt;&gt;();</span><br><span class="line">map.put(<span class="string">&quot;firstElement&quot;</span>, <span class="number">1</span>);</span><br><span class="line">map.put(<span class="string">&quot;secondElement&quot;</span>, <span class="number">2</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 使用for遍历</span></span><br><span class="line"><span class="keyword">for</span>(Map.Entry&lt;String, Integer&gt; entry : map.entrySet()) &#123;</span><br><span class="line"> System.out.println(<span class="string">&quot;for-entry 键:&quot;</span> + entry.getKey() + <span class="string">&quot;, 值:&quot;</span> + entry.getValue());</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span>(String k : map.keySet()) &#123;</span><br><span class="line"> System.out.println(<span class="string">&quot;for-key 键:&quot;</span> + k + <span class="string">&quot;, 值:&quot;</span> + map.get(k));</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span>(Integer v : map.values()) &#123;</span><br><span class="line"> System.out.println(<span class="string">&quot;for-value 值:&quot;</span> + v);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 使用迭代器遍历</span></span><br><span class="line">Iterator&lt;Map.Entry&lt;String, Integer&gt;&gt; iterator = map.entrySet().iterator();</span><br><span class="line"><span class="keyword">while</span> (iterator.hasNext()) &#123;</span><br><span class="line"> Map.Entry&lt;String, Integer&gt; entry = iterator.next();</span><br><span class="line"> System.out.println(<span class="string">&quot;iterator-entry 键:&quot;</span> + entry.getKey() + <span class="string">&quot;, 值:&quot;</span> + entry.getValue());</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">Iterator&lt;String&gt; kIterator = map.keySet().iterator();</span><br><span class="line"><span class="keyword">while</span> (kIterator.hasNext()) &#123;</span><br><span class="line"> String key = kIterator.next();</span><br><span class="line"> System.out.println(<span class="string">&quot;iterator-key 键:&quot;</span> + key + <span class="string">&quot;, 值:&quot;</span> + map.get(key));</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">Iterator&lt;Integer&gt; vIterator = map.values().iterator();</span><br><span class="line"><span class="keyword">while</span> (vIterator.hasNext()) &#123;</span><br><span class="line"> Integer value = vIterator.next();</span><br><span class="line"> System.out.println(<span class="string">&quot;iterator-value 值:&quot;</span> + value);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 使用Lambda</span></span><br><span class="line">map.forEach((k, v) -&gt; &#123;</span><br><span class="line"> System.out.println(<span class="string">&quot;Lambda-entry 键:&quot;</span> + k + <span class="string">&quot;, 值:&quot;</span> + v);</span><br><span class="line">&#125;);</span><br><span class="line">map.entrySet().forEach(entry -&gt; &#123;</span><br><span class="line"> System.out.println(<span class="string">&quot;Lambda-entry 键:&quot;</span> + entry.getKey() + <span class="string">&quot;, 值:&quot;</span> + entry.getValue());</span><br><span class="line">&#125;);</span><br><span class="line">map.keySet().forEach(key -&gt; System.out.println(<span class="string">&quot;Lambda-key 键:&quot;</span> + key + <span class="string">&quot;, 值:&quot;</span> + map.get(key)));</span><br><span class="line">map.values().forEach(value -&gt; System.out.println(<span class="string">&quot;Lambda-value 值:&quot;</span> + value));</span><br></pre></td></tr></table></figure>
  602. <h1 id="entrySet-、keySet-和values-的作用"><a href="#entrySet-、keySet-和values-的作用" class="headerlink" title="entrySet()、keySet()和values()的作用"></a>entrySet()、keySet()和values()的作用</h1><p>就像我们会遍历Collection集合一样,偶尔我们也会因业务需求遍历Map,但是Map的实现并不像Collection这么简单,底层是个数组或者链表什么的。</p>
  603. <p>以HashMap为例,它的底层数据结构是:数组+链表+红黑树,这样作为开发者的我们就要花费大量精力去实现怎么遍历。</p>
  604. <p>因此特意提供了entrySet()、keySet()和values()这三个方法,屏蔽底层的实现,提供简单易用的Collection。</p>
  605. <h1 id="3种遍历方法的本质"><a href="#3种遍历方法的本质" class="headerlink" title="3种遍历方法的本质"></a>3种遍历方法的本质</h1><blockquote>
  606. <p>迭代器模式:<strong>提供一种方法顺序的访问一个聚合对象中各个元素,而又不暴露该对象的内部表示</strong>。</p>
  607. </blockquote>
  608. <p>虽然上面提供了三种遍历方式,但其本质依然调用了迭代器:</p>
  609. <ul>
  610. <li>增强型for循环,其底层是使用了iterator,这点可以通过编译后的代码可以了解到。</li>
  611. <li>使用了Lambda表达式的forEach,其方法体内部依然是使用了增强型for循环。</li>
  612. </ul>
  613. <p>通过使用迭代器我们就能轻易的访问集合对象而又无须关注集合对象的内部实现。</p>
  614. ]]></content>
  615. <categories>
  616. <category>Java</category>
  617. </categories>
  618. <tags>
  619. <tag>Java</tag>
  620. </tags>
  621. </entry>
  622. <entry>
  623. <title>String、StringBuilder和StringBuffer</title>
  624. <url>/posts/2871eb40.html</url>
  625. <content><![CDATA[<p>String是Java中使用频率极高的一个类,但由于其是不可变,因此有StringBuffer和StringBuilder两个类来弥补在大量修改场景下的不足。</p>
  626. <span id="more"></span>
  627. <h1 id="String"><a href="#String" class="headerlink" title="String"></a>String</h1><p>当我们需要存储单一的字符时,使用的是基本数据类型<em>char</em>来进行存储,而要存储一连串的字符时,毫无疑问的是想到使用字符数组*char[]*来进行存储,如果代码中每次都要先声明数组才能存储字符串就显得非常冗余和烦琐了,因此贴心的Java为我们提供了String类。</p>
  628. <p>String类的数据结构如下</p>
  629. <figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">char</span>[] value;</span><br></pre></td></tr></table></figure>
  630. <p>可以看到String类确实就是用一个字符数组来存储字符串的,但这是Java版本1.9版本之前的内容。</p>
  631. <h2 id="数据类型的改变"><a href="#数据类型的改变" class="headerlink" title="数据类型的改变"></a>数据类型的改变</h2><p>在Java版本1.9之后,String类的数组的数据类型就由<em>char[]<em>改为了</em>byte[]</em></p>
  632. <figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">byte</span>[] value;</span><br></pre></td></tr></table></figure>
  633. <p>博主由于对这个变化了解的不是很透彻,因此摘抄了别人的解释,具体可看<a href="https://github.com/Snailclimb/JavaGuide/issues/675">这里</a>或者自行搜索相关内容。</p>
  634. <blockquote>
  635. <p>为什么使用byte字节而舍弃了char字符:</p>
  636. </blockquote>
  637. <blockquote>
  638. <p>节省内存占用,byte占一个字节(8位),char占用2个字节(16),相较char节省一半的内存空间。节省gc压力。<br>针对初始化的字符,对字符长度进行判断选择不同的编码方式。如果是 LATIN-1 编码,则右移0位,数组长度即为字符串长度。而如果是 UTF16 编码,则右移1位,数组长度的二分之一为字符串长度。</p>
  639. </blockquote>
  640. <h2 id="不可变性"><a href="#不可变性" class="headerlink" title="不可变性"></a>不可变性</h2><p>String类的不可变性是由几个方面实现</p>
  641. <ol>
  642. <li><p>String类本身由final修饰符进行修饰</p>
  643. <figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">final</span> <span class="class"><span class="keyword">class</span> <span class="title">String</span> <span class="keyword">implements</span> <span class="title">java</span>.<span class="title">io</span>.<span class="title">Serializable</span>, <span class="title">Comparable</span>&lt;<span class="title">String</span>&gt;, <span class="title">CharSequence</span> </span>&#123;</span><br></pre></td></tr></table></figure></li>
  644. <li><p>存储字符的属性值value由private修饰符修饰,且没有提供<em>setter</em>方法供外界进行修改</p>
  645. <figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">byte</span>[] value;</span><br></pre></td></tr></table></figure></li>
  646. <li><p>虽然存储字符的属性值value使用了final修饰符进行修饰,但是仅能做到变量value对于数组的引用不变而已,而无法阻止数组元素的修改,<strong>通过查看String的源码其实可以发现,Java的开发者很小心的处理String类中的每一行代码,从而做到在细节上实现了不可变(即没有修改数组元素)</strong></p>
  647. </li>
  648. </ol>
  649. <p>通过以上的几个方面,实现了String类无法被继承且内部元素无法被修改,做到了String的不可变,由于其不可变性,可以理解为一个常量,因此<strong>String类是线程安全的</strong>。</p>
  650. <p>注:如果真的要破坏String类的不可变性,只能通过使用反射的方式进行破坏,强行进行修改了。</p>
  651. <h1 id="StringBuilder和StringBuffer"><a href="#StringBuilder和StringBuffer" class="headerlink" title="StringBuilder和StringBuffer"></a>StringBuilder和StringBuffer</h1><p>由于String类的不可变性,每一次修改为不同的字符串就会生成一个新的String对象,这明显不利于在需要大量修改字符串内容的场景,因此Java提供了StringBuilder类和StringBuffer类来实现字符串的动态修改,只有在最后修改完毕后才才调用*toString()*方法真正的生成String对象。</p>
  652. <h2 id="抽象类AbstractStringBuilder"><a href="#抽象类AbstractStringBuilder" class="headerlink" title="抽象类AbstractStringBuilder"></a>抽象类AbstractStringBuilder</h2><p>StringBuilder类和StringBuffer类都是继承自<em>抽象类AbstractStringBuilder</em>,部分代码如下</p>
  653. <figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">abstract</span> <span class="class"><span class="keyword">class</span> <span class="title">AbstractStringBuilder</span> <span class="keyword">implements</span> <span class="title">Appendable</span>, <span class="title">CharSequence</span> </span>&#123;</span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * The value is used for character storage.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">byte</span>[] value;</span><br></pre></td></tr></table></figure>
  654. <p>可以看到注释,属性value就是存储字符串的地方,且没有使用final修饰符进行修饰,因此是可变的。</p>
  655. <p><em>AbstractStringBuilder</em>类本身提供且实现了大量的修改字符串内容的方法,如 <code>expandCapacity</code>、<code>append</code>、<code>insert</code>、<code>indexOf</code> 等公共方法,StringBuffer类和StringBuilder类的许多方法实现上都是直接调用的父类(AbstractStringBuilder)的方法。</p>
  656. <h2 id="线程安全和性能"><a href="#线程安全和性能" class="headerlink" title="线程安全和性能"></a>线程安全和性能</h2><p>虽说StringBuilder类和StringBuffer类都是继承自<em>抽象类AbstractStringBuilder</em>,整体上都是差不多,但是在性能和多线程操作处理上存在区别</p>
  657. <ul>
  658. <li><p>线程安全</p>
  659. <p>StringBuilder类并没有对方法做任何多线程方面的处理,因此是非线程安全的。</p>
  660. <p>StringBuffer类中大量的使用<strong>synchronized</strong>关键字对方法进行了加锁操作,因此是线程安全的。</p>
  661. </li>
  662. <li><p>性能</p>
  663. <p>StringBuffer类由于其方法上的加锁操作,因此性能要比StringBuilder类低。</p>
  664. </li>
  665. </ul>
  666. <p><strong>总结:需要考虑线程安全的就用StringBuffer,无线程安全问题且重视性能的就用StringBuilder,无脑操作就选StringBuffer。</strong></p>
  667. <h1 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h1><ul>
  668. <li><a href="https://www.jianshu.com/p/cd72099051f9">String类的不可变性</a></li>
  669. <li><a href="https://github.com/Snailclimb/JavaGuide/issues/675">Java 9 之后,String 类的实现改用 byte 数组存储字符串</a></li>
  670. </ul>
  671. ]]></content>
  672. <categories>
  673. <category>Java</category>
  674. </categories>
  675. <tags>
  676. <tag>Java</tag>
  677. </tags>
  678. </entry>
  679. <entry>
  680. <title>CAP理论和BASE理论</title>
  681. <url>/posts/7ae49b47.html</url>
  682. <content><![CDATA[<p>说起分布式肯定绕不开两个理论:CAP理论和BASE理论。限于水平有限,本篇文章仅作记录用。</p>
  683. <span id="more"></span>
  684. <h1 id="CAP理论"><a href="#CAP理论" class="headerlink" title="CAP理论"></a>CAP理论</h1><p>C即一致性,A即可用性,P即分区容错性。<br>CAP理论指出了三者中只能同时做到其中的两个,无法同时满足三个要求。<br>CAP理论是针对分布式数据库环境提出的,因此P属性是必须的。如果选择了A,那么分区间的数据可能会不一致;如果选择了C,则为了保持数据一致性而导致服务不可用。</p>
  685. <h2 id="拓展"><a href="#拓展" class="headerlink" title="拓展"></a>拓展</h2><p>Spring cloud中的eureka 属于AP,zookeeper属于CP。</p>
  686. <h1 id="BASE理论"><a href="#BASE理论" class="headerlink" title="BASE理论"></a>BASE理论</h1><p>BA(基本可用,Basically Available)、S(软状态,Soft-state)、C(最终一致性,Eventually Consistent)<br>BASE理论是由CAP理论发展而来,是一致性和可用性权衡的结果,即牺牲一致性来满足系统的可用性,然后在后续的过程中达到最终一致。</p>
  687. ]]></content>
  688. <categories>
  689. <category>分布式</category>
  690. </categories>
  691. <tags>
  692. <tag>分布式</tag>
  693. </tags>
  694. </entry>
  695. <entry>
  696. <title>CAS操作和ABA问题</title>
  697. <url>/posts/ce4f4d1f.html</url>
  698. <content><![CDATA[<p>多线程开发中,通常会加锁做并发控制,但是加锁会让性能降低,因此有了CAS操作,但CAS操作会引发ABA问题。</p>
  699. <span id="more"></span>
  700. <h1 id="什么是CAS"><a href="#什么是CAS" class="headerlink" title="什么是CAS"></a>什么是CAS</h1><p>CAS(Compare and Swap,比较和交换),是一种乐观锁(同时操作同一个对象的概率非常小,因此大部分加锁操作做的都是无用功)的实现方式,是以一种无锁的方式实现并发控制,即在多线程环境下,以不加锁的方式对数据进行修改。</p>
  701. <h2 id="CAS的操作过程"><a href="#CAS的操作过程" class="headerlink" title="CAS的操作过程"></a>CAS的操作过程</h2><p>CAS(V,E,N),V表示要更新变量的值(变量当前值),E表示预期值(变量的旧值),N表示新值。</p>
  702. <p>仅当 V值等于E值时,才会将V的值设为N,如果V值和E值不同,则说明已经有其他线程做更新,则当前线程则什么都不做。</p>
  703. <p>最后,CAS 返回当前V的真实值。</p>
  704. <h1 id="ABA问题"><a href="#ABA问题" class="headerlink" title="ABA问题"></a>ABA问题</h1><p>ABA问题,是指CAS操作中,其它线程把变量的值进行了修改但是修改的值与原始值一致,使CAS的比较判断出错,即无法感知数据被修改过,导致程序异常。</p>
  705. <p>避免方法:加入版本号进行记录,CAS操作时比较一下版本号就能判断出是不是属于自己的那次CAS操作了。</p>
  706. ]]></content>
  707. <categories>
  708. <category>多线程</category>
  709. </categories>
  710. <tags>
  711. <tag>多线程</tag>
  712. </tags>
  713. </entry>
  714. <entry>
  715. <title>临界段</title>
  716. <url>/posts/c3329247.html</url>
  717. <content><![CDATA[<p>临界段即多线程互斥使用共享资源的代码段,是一种加锁的机制,在任意时刻一个共享资源只能被一个线程使用。</p>
  718. <p>Java中使用关键字synchronized定义临界段,能对共享对象进行加锁操作。</p>
  719. ]]></content>
  720. <categories>
  721. <category>多线程</category>
  722. </categories>
  723. <tags>
  724. <tag>多线程</tag>
  725. </tags>
  726. </entry>
  727. <entry>
  728. <title>线程间的互斥和同步</title>
  729. <url>/posts/6117b918.html</url>
  730. <content><![CDATA[<p>多线程间是互相协助和互相联系的,因此多线程间存在互斥和同步。</p>
  731. <!-- more -->
  732. <h1 id="互斥和同步"><a href="#互斥和同步" class="headerlink" title="互斥和同步"></a>互斥和同步</h1><p>多线程间存在并发访问共享资源(修改资源)时就会出现互斥,保证共享数据在同一时刻只被一个线程使用。</p>
  733. <p>多线程同步是指一个线程由于某种原因(等待对象释放之类的)需要等待另一个线程执行完才能继续执行的现象,即线程间互相等待。</p>
  734. <p>互斥和同步是不可分离的,互斥是实现同步的一种手段,临界区、互斥量和信号量都是主要的互斥实现方式,互斥是因,同步是果,互斥是方法,同步是目的。</p>
  735. <h1 id="Java中的实现"><a href="#Java中的实现" class="headerlink" title="Java中的实现"></a>Java中的实现</h1><p>Java中wait()、notify()、notifyAll()三个方法就是用来实现线程同步的。</p>
  736. <p>wait()处于等待队列,或超时结束等待。notify()通知第一个处于等待的线程,notifyAll()则唤醒所有等待线程一起竞争cpu。</p>
  737. <p>Java中最基本的互斥同步手段就是synchronized。</p>
  738. ]]></content>
  739. <categories>
  740. <category>多线程</category>
  741. </categories>
  742. <tags>
  743. <tag>多线程</tag>
  744. </tags>
  745. </entry>
  746. <entry>
  747. <title>进程间的通信方式</title>
  748. <url>/posts/44e8cd7.html</url>
  749. <content><![CDATA[<p><strong>进程通信(Interprocess Communication,IPC)是一个进程与另一个进程间共享消息的一种通信方式</strong>。消息(message)是发送进程形成的一个消息块,将消息内容传送给接收进程。</p>
  750. <span id="more"></span>
  751. <h1 id="进程间通信的目的"><a href="#进程间通信的目的" class="headerlink" title="进程间通信的目的"></a>进程间通信的目的</h1><ul>
  752. <li><p>数据传输<br> 一个进程需要将其数据发送给另一进程,发送的数据量在一个字节到几M字节之间。</p>
  753. </li>
  754. <li><p>共享数据<br> 多个进程操作共享数据</p>
  755. </li>
  756. <li><p>事件通知<br> 一个进程需要向另一个或一组进程发送消息,通知它(它们)发生了某种事件(如进程终止时要通知父进程)。</p>
  757. </li>
  758. <li><p>资源共享<br> 多个进程之间共享同样的资源。<strong>为了作到这一点,需要内核提供锁和同步机制</strong>。</p>
  759. </li>
  760. <li><p>进程控制<br> 有些进程希望完全控制另一个进程的执行(如Debug进程),此时控制进程希望能够拦截另一个进程的所有陷入和异常,并能够及时知道它的状态改变。</p>
  761. </li>
  762. </ul>
  763. <h1 id="8种通信方式"><a href="#8种通信方式" class="headerlink" title="8种通信方式"></a>8种通信方式</h1><ol>
  764. <li><p>匿名管道</p>
  765. <p>是一种半双工的通信方式(即数据只能单向流动),且只能在具有亲缘关系的进程间使用(亲缘关系指的父子进程或者兄弟子进程),该管道只存在于内存之中。</p>
  766. </li>
  767. <li><p>流管道</p>
  768. <p>是一种全双工的通信方式(即数据能双向流动)</p>
  769. <p>注:对该方法不熟悉,请自行搜索更多相关内容</p>
  770. </li>
  771. <li><p>命名管道</p>
  772. <p>与匿名管道一样是一种半双工的通信方式(即数据只能单向流动),但<em>克服了匿名管道只能在具有亲缘关系的进程间使用的限制</em>,允许无亲缘关系的进程间使用,管道以一种特殊设备文件形式存在于文件系统中。</p>
  773. </li>
  774. <li><p>信号</p>
  775. <p>信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。</p>
  776. </li>
  777. <li><p>消息队列</p>
  778. <p>是消息的链表,存放在内核中,一个消息队列由一个标识符(即队列ID)来标识。</p>
  779. <p>消息队列是面向记录的,其中的消息具有特定的格式以及特定的优先级。</p>
  780. <p>消息队列独立于发送与接收进程。进程终止时,消息队列及其内容并不会被删除。</p>
  781. <p>消息队列可以实现消息的随机查询,消息不一定要以先进先出的次序读取,也可以按消息的类型读取。</p>
  782. </li>
  783. <li><p>共享内存</p>
  784. <p>两个或多个进程共享一个给定的存储区,是最快的一种 IPC,因为进程是直接对内存进行存取。</p>
  785. <p>因为多个进程可以同时操作,所以需要进行同步。</p>
  786. <p>信号量+共享内存通常结合在一起使用,信号量用来同步对共享内存的访问。</p>
  787. </li>
  788. <li><p>信号量</p>
  789. <p>信号量是一个计数器,用于实现进程间的互斥与同步,若要在进程间传递数据需要结合共享内存。</p>
  790. <p>信号量是基于操作系统的PV操作,程序对信号量的操作都是原子操作。</p>
  791. <p>每次对信号量的 PV 操作不仅限于对信号量值加 1 或减 1,而且可以加减任意正整数。</p>
  792. <p>支持信号量组。</p>
  793. </li>
  794. <li><p>套接字,即socket通信,与其他通信机制不同的是,它可用于不同机器间的进程通信。</p>
  795. </li>
  796. </ol>
  797. <h1 id="进程间的通信和线程间的通信的区别"><a href="#进程间的通信和线程间的通信的区别" class="headerlink" title="进程间的通信和线程间的通信的区别"></a>进程间的通信和线程间的通信的区别</h1><p>只有进程间需要通信,线程间由于共享进程的地址空间,因此没有通信必要,但要做好同步和互斥,保护共享的变量。</p>
  798. ]]></content>
  799. <categories>
  800. <category>多线程</category>
  801. </categories>
  802. <tags>
  803. <tag>多线程</tag>
  804. </tags>
  805. </entry>
  806. <entry>
  807. <title>docker服务及其容器自启动</title>
  808. <url>/posts/f31ac7c3.html</url>
  809. <content><![CDATA[<p>服务器重启后docker服务和容器都会停止运行,如果每次都手动启动的话就很繁琐了,因此配置为自启动就很有必要了。</p>
  810. <span id="more"></span>
  811. <h1 id="环境"><a href="#环境" class="headerlink" title="环境"></a>环境</h1><p>服务器系统:centos7</p>
  812. <p>docker 版本:19.03.5</p>
  813. <h1 id="docker服务自启动"><a href="#docker服务自启动" class="headerlink" title="docker服务自启动"></a>docker服务自启动</h1><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 开启自启动</span></span><br><span class="line">systemctl enable docker</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 关闭自启动</span></span><br><span class="line">systemctl disable docker</span><br></pre></td></tr></table></figure>
  814. <p>PS:systemctl就是直接操作系统服务,是service、chkconfig命令的组合,如果没有systemctl命令,请自行搜索其它方案。</p>
  815. <h1 id="docker容器自启动"><a href="#docker容器自启动" class="headerlink" title="docker容器自启动"></a>docker容器自启动</h1><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 创建容器前加入参数--restart</span></span><br><span class="line">docker run --restart=参数项</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 已创建容器则使用如下命令</span></span><br><span class="line">docker update --restart=参数项 [容器名]</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> --restart参数解析</span></span><br><span class="line">no:不要自动重启容器(默认)</span><br><span class="line">on-failure:如果容器由于非正常退出(非零退出代码)而停止运行则重新启动容器,可以加入重启次数,如--restart=on-failure:3 即尝试3次后不再重新启动</span><br><span class="line">always:总是重启容器,如果是手动停止,则仅在docker服务重启或重新手动启动该容器时才重新启动</span><br><span class="line">unless-stopped:总是重启容器,但是如果容器是已经停止了(手动停止或其他方式),即使docker服务重新启动也不会重新启动容器</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 例子</span></span><br><span class="line">docker update --restart=on-failure [容器名]</span><br><span class="line">docker update --restart=on-failure:3 [容器名]</span><br><span class="line">docker update --restart=always [容器名]</span><br></pre></td></tr></table></figure>
  816. ]]></content>
  817. <categories>
  818. <category>Docker</category>
  819. </categories>
  820. <tags>
  821. <tag>容器</tag>
  822. <tag>Docker</tag>
  823. </tags>
  824. </entry>
  825. <entry>
  826. <title>微服务的启动</title>
  827. <url>/posts/ce090114.html</url>
  828. <content><![CDATA[<p>由于项目由单体变成了微服务的形式,因此项目的启动由一次变成了多次,但是单体项目与微服务有个不同点,就是微服务的服务之间存在依赖关系,不当的启动顺序会导致服务启动失败。</p>
  829. <p>PS:以下仅作记录,没有真实使用过,</p>
  830. <span id="more"></span>
  831. <h1 id="手动启动"><a href="#手动启动" class="headerlink" title="手动启动"></a>手动启动</h1><p>按照依赖顺序依次启动服务,但是微服务架构的项目,单个服务的实例的次数都不止一个,更不要说整个项目了,手动启动的话肯定是不允许的。</p>
  832. <h1 id="wait-for-it-sh和服务健康检查"><a href="#wait-for-it-sh和服务健康检查" class="headerlink" title="wait-for-it.sh和服务健康检查"></a>wait-for-it.sh和服务健康检查</h1><p>为了便于微服务的分发和管理,使用Docker打包然后分发是一个很好的实践。</p>
  833. <p>对于微服务间的服务依赖,Docker官方给出的建议是:通过wait-for-it.sh脚本来控制,即通过脚本探测某个依赖的服务的tcp端口是否开放,否则一直等待,直到端口探测成功,才会启动后面的命令;也可以通过服务健康检查来实现。</p>
  834. <h1 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h1><p><a href="https://docs.docker.com/compose/startup-order/">https://docs.docker.com/compose/startup-order/</a></p>
  835. <p><a href="https://stackoverflow.com/questions/48684609/control-startup-order-in-docker-compose">https://stackoverflow.com/questions/48684609/control-startup-order-in-docker-compose</a></p>
  836. ]]></content>
  837. <categories>
  838. <category>Docker</category>
  839. </categories>
  840. <tags>
  841. <tag>Docker</tag>
  842. </tags>
  843. </entry>
  844. <entry>
  845. <title>Conda</title>
  846. <url>/posts/c3592b96.html</url>
  847. <content><![CDATA[<p>Conda是一个包管理、依赖管理和<em>环境管理</em>工具,虽然由Python程序创建,但它可以打包并分发任何语言的软件,例如:Python, R, Ruby, Lua, Scala, Java, JavaScript, C/ C++, FORTRAN。</p>
  848. <span id="more"></span>
  849. <h1 id="Conda简介"><a href="#Conda简介" class="headerlink" title="Conda简介"></a>Conda简介</h1><blockquote>
  850. <p>Conda是一个开源的包管理、依赖管理和环境管理工具,能运行在Windows、macOS和Linux上,具备快速安装、运行和更新包和依赖的能力,能够轻松的创建、保存、加载和切换不同的开发环境。虽然Conda由Python程序创建,但它可以打包并分发任何语言的软件。</p>
  851. </blockquote>
  852. <p>通过以上摘录自官网的译文可以知道,Conda对于经常要切换不同的开发环境的开发者来说,是一个极其合适的工具。</p>
  853. <h1 id="下载"><a href="#下载" class="headerlink" title="下载"></a>下载</h1><p>Conda作为一个管理工具,有两个常见的发行版本:Anaconda和Miniconda,其区别如下:</p>
  854. <p>Miniconda:仅仅拥有python,conda和一些必须的依赖包,除此之外没有任何附带的东西,操作时需要使用命令行的方式进行操作,占用极小的硬盘空间,但使用的时候需要自己安装所需要的包。<a href="https://conda.io/miniconda.html">&gt;&gt;&gt;下载&lt;&lt;&lt;</a></p>
  855. <p>Anaconda:拥有Miniconda所拥有的之外,还自带超过720个的开源包,并且具有图形化的操作界面,安装后即可使用,但占用较大的空间,以及会安装一些自己使用不到的包。<a href="https://www.anaconda.com/download/">&gt;&gt;&gt;下载&lt;&lt;&lt;</a></p>
  856. <p>综上来看:两个发行版该有的基本功能一样不缺,但相对而言,Miniconda更适合一些简约的人使用,如果需要省心的话Anaconda就是一个极好的选择,毕竟多占的一些硬盘空间对现在的硬盘来说不算什么,读者可以根据自身情况进行选择。</p>
  857. <p>博主比较喜欢简约因此使用的是Miniconda,同时为了更好的熟悉conda,下面将会直接使用命令行来进行操作演示。</p>
  858. <h1 id="环境变量"><a href="#环境变量" class="headerlink" title="环境变量"></a>环境变量</h1><p>在安装conda的过程中,其中有一个选项就是把conda加入系统环境变量中,官方提示是不建议勾选,因为重装之类的可能会导致找不到相应目录之类的,建议直接使用官方提供的命令行工具,在命令行下找到一个名为<em>Anaconda Prompt</em>的应用,如下所示:<br><img src="http://ws1.sinaimg.cn/large/e6dffef4gy1g5ppvqnx28j206w016aa2.jpg" alt="Anaconda Prompt"><br>运行后的效果如下所示:<br><img src="http://ws1.sinaimg.cn/large/e6dffef4gy1g5ppw9j5u6j20p50c2aa8.jpg" alt="Anaconda Prompt CMD"><br>但是经过一段时间的使用后发现还是加入到系统的环境变量中更方便,这样就可以随时随地在任何环境中使用了,如果已经安装了程序但又没有加入系统环境变量的,可以按照如下步骤重新加入:</p>
  859. <ol>
  860. <li>找到程序的安装根目录,要是安装时没有指定安装目录的话,一般都是安装在安装时使用的用户的用户目录之下,这里假设路径是conda_rootdir<br><img src="http://ws1.sinaimg.cn/large/e6dffef4gy1g5ppwjwa75j20pk0gy0uf.jpg" alt="conda安装根目录"></li>
  861. <li>打开系统环境变量的设置窗口:我的电脑点击鼠标右键-&gt;属性-&gt;高级系统设置-&gt;环境变量<br><img src="http://ws1.sinaimg.cn/large/e6dffef4gy1g5ppwvx4znj211u0i8b1e.jpg" alt="系统环境变量"></li>
  862. <li>在系统变量部分,找到变量名为Path的条目,选中并点击下方的编辑按钮,就能打开编辑界面<br><img src="http://ws1.sinaimg.cn/large/e6dffef4gy1g5ppx5njzxj20q00imdh7.jpg" alt="系统环境变量编辑窗口"></li>
  863. <li>把如下的路径添加到系统环境变量中,记得把conda_rootdir替换为自己电脑下conda的安装根目录<br><img src="http://ws1.sinaimg.cn/large/e6dffef4gy1g5ppxihyuxj20bc034mx0.jpg" alt="conda路径"></li>
  864. <li>点击确定,保存编辑的内容,然后重新打开命令行窗口,然后输入命令<em>conda info</em>,并显示相应内容的话,就表示配置成功,配置失败的请重新配置<br><img src="http://ws1.sinaimg.cn/large/e6dffef4gy1g5ppxqdloaj20rl0e5t95.jpg" alt="conda信息"></li>
  865. </ol>
  866. <h1 id="conda配置文件"><a href="#conda配置文件" class="headerlink" title="conda配置文件"></a>conda配置文件</h1><p>conda安装后会在用户目录下生成一个配置文件*.condarc*,如果没有的话可以自己创建一个,内容如下:</p>
  867. <figure class="highlight yaml"><table><tr><td class="code"><pre><span class="line"><span class="attr">channels:</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">defaults</span></span><br></pre></td></tr></table></figure>
  868. <p>配置文件中的channels属性指的是安装时的下载来源,defaults指的是默认的下载来源,如果想添加下载源的话只要按照格式添加就可以了。默认源在国内下载速度较慢,所以国内有清华镜像源即<a href="https://mirrors.tuna.tsinghua.edu.cn/help/anaconda/">Anaconda 镜像</a>,使用后速度会有明显的提升,但是在这里依然不建议使用国内的清华源,因为使用一段时间后发现清华源的版本比较旧而且还不全,直接使用默认源的话使用上是基本没有问题,下载时间也就相对清华源慢一些而已。</p>
  869. <p>默认情况下环境文件以及下载下来的包都是安装在软件根目录下的envs和pkgs文件夹下,如果想要更改安装路径的话,可以加入如下配置</p>
  870. <figure class="highlight yaml"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 环境目录</span></span><br><span class="line"><span class="attr">envs_dirs:</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">E:\Documents\Code\alpha\conda\envs</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 包目录</span></span><br><span class="line"><span class="attr">pkgs_dirs:</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">E:\Documents\Code\alpha\conda\pkgs</span></span><br></pre></td></tr></table></figure>
  871. <p>如果有想了解更多的可以直接访问官网了解详细的配置<a href="https://conda.io/docs/user-guide/configuration/use-condarc.html">&gt;&gt;&gt;传送门&lt;&lt;&lt;</a></p>
  872. <h1 id="Conda信息"><a href="#Conda信息" class="headerlink" title="Conda信息"></a>Conda信息</h1><p>如果想要查看Conda的信息的话,可以输入如下命令</p>
  873. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">conda info</span><br></pre></td></tr></table></figure>
  874. <p><img src="http://ws1.sinaimg.cn/large/e6dffef4gy1g5ppxqdloaj20rl0e5t95.jpg" alt="conda信息"><br>可以看到上一部分的配置信息也出现在内容展示中,说明配置是有效的。</p>
  875. <p>如果想要查看已有的开发环境,输入如下命令</p>
  876. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">conda info --env</span><br></pre></td></tr></table></figure>
  877. <p><img src="http://ws1.sinaimg.cn/large/e6dffef4gy1g5ppybug74j20fx02kt8i.jpg" alt="conda环境信息"><br>可以看到里面现在有两个环境,分别是base和tensorflow,其中base就是安装时默认的环境,而tensorflow就是博主自己创建的环境。</p>
  878. <p>在上述图片中还有个要注意的地方就是base环境前面是有个*号的,说明base环境处于激活的状态,即判断当前所处环境的方法就是查看*号出现在那个环境前。<br><img src="http://ws1.sinaimg.cn/large/e6dffef4gy1g5ppyn28j4j20g303q0sm.jpg" alt="激活了tensorflow环境"><br>而上面这张则是激活了tensorflow环境的,而这张还有一个特别地方就是前面直接写着名为tensorflow的环境名称,因此也可以作为当前处于那个激活环境的判断。</p>
  879. <p>那么到底怎么创建一个新的环境呢?</p>
  880. <h1 id="环境创建、克隆、激活和删除"><a href="#环境创建、克隆、激活和删除" class="headerlink" title="环境创建、克隆、激活和删除"></a>环境创建、克隆、激活和删除</h1><p>想要创建环境,只要输入如下命令:</p>
  881. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 不指定python版本</span></span><br><span class="line">conda create --name env-name</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 指定python版本</span></span><br><span class="line">conda create --name env-name python=2.7</span><br></pre></td></tr></table></figure>
  882. <p>其中env-name是该新建环境的名称;python是该环境中的python版本,默认情况下如果不写该参数,将会延用base环境中的python版本,而base环境中的python版本就是下载部分选择conda安装包时的python版本。<br><img src="http://ws1.sinaimg.cn/large/e6dffef4gy1g5ppyx53v9j20qp05gwec.jpg" alt="conda创建环境"><br>创建成功后就能看到如上的显示,想要激活环境,输入:</p>
  883. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">conda activate env-name</span><br></pre></td></tr></table></figure>
  884. <p>想要取消激活,输入:</p>
  885. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">conda deactivate</span><br></pre></td></tr></table></figure>
  886. <p>当然,也可以直接关闭命令窗口来退出已激活的环境。</p>
  887. <p>注意:在没有激活任何环境的情况下都是处于base环境之下的,就算激活了其它环境也只在激活的命令窗口下是激活环境,在激活环境下的任何操作,都不会对其它环境产生影响,当然这也就是conda的意义所在。</p>
  888. <p>在某些情况下如果想要复制已有的环境,可以输入:</p>
  889. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">conda create --name new-env-name --clone env-name</span><br></pre></td></tr></table></figure>
  890. <p>如果想删除现有的环境,必须在先取消激活目标环境,然后执行如下命令:</p>
  891. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">conda remove --name env-name --all</span><br></pre></td></tr></table></figure>
  892. <h1 id="包的查看、搜索、安装、更新和卸载"><a href="#包的查看、搜索、安装、更新和卸载" class="headerlink" title="包的查看、搜索、安装、更新和卸载"></a>包的查看、搜索、安装、更新和卸载</h1><p>注意:以下的一切命令请先激活环境后再执行,否则都将会作用于基本环境,即操作的对象是基本环境。</p>
  893. <p>创建好环境后,想要使用当然还需要安装自己所需要的包,这里使用tensorflow做例子,输入如下命令,查看当前已安装的包:</p>
  894. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">conda list</span><br></pre></td></tr></table></figure>
  895. <p><img src="http://ws1.sinaimg.cn/large/e6dffef4gy1g5ppz5ky2sj20hn08mq2y.jpg" alt="查看已安装的包"></p>
  896. <p>搜索可用的包</p>
  897. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">conda search tensorflow</span><br></pre></td></tr></table></figure>
  898. <p><img src="http://ws1.sinaimg.cn/large/e6dffef4gy1g5ppzem086j20e804xq2t.jpg" alt="搜索可用的包"></p>
  899. <p>安装包</p>
  900. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">conda install tensorflow</span><br></pre></td></tr></table></figure>
  901. <p>更新包</p>
  902. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">conda update tensorflow</span><br></pre></td></tr></table></figure>
  903. <p>卸载已安装的包</p>
  904. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">conda uninstall tensorflow</span><br></pre></td></tr></table></figure>
  905. <h1 id="环境配置的导入和导出"><a href="#环境配置的导入和导出" class="headerlink" title="环境配置的导入和导出"></a>环境配置的导入和导出</h1><p>在某些情况下,如果想要分享自己的开发环境,可以通过导出目标环境的环境配置来完成分享。</p>
  906. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">conda activate tensorflow</span><br><span class="line"></span><br><span class="line">conda env export &gt; path-to/environment.yml</span><br></pre></td></tr></table></figure>
  907. <p>注意:要先激活想要的分享目标环境,然后再执行导出命令</p>
  908. <p>导出命令的path-to是指定目标路径,environment.yml则是导出的环境配置文件,如果不写路径则将会导出到命令行当前的路径之下。</p>
  909. <p>别人拿到了你分享出来的环境配置文件又该如何使用呢,输入:</p>
  910. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">conda env create -f path-to/environment.yml</span><br></pre></td></tr></table></figure>
  911. <p>即可创建一个和环境配置文件描述的一摸一样的开发环境了。</p>
  912. <h1 id="结束语"><a href="#结束语" class="headerlink" title="结束语"></a>结束语</h1><p>至此,conda的基本用法已经讲述完,如过想要更深入了解的话可以在官网上查阅更详细的资料。</p>
  913. <h1 id="参考文献"><a href="#参考文献" class="headerlink" title="参考文献"></a>参考文献</h1><p><a href="https://conda.io/docs/index.html">conda官网</a></p>
  914. ]]></content>
  915. <categories>
  916. <category>工具</category>
  917. <category>开发工具</category>
  918. <category>Conda</category>
  919. </categories>
  920. <tags>
  921. <tag>Conda</tag>
  922. </tags>
  923. </entry>
  924. <entry>
  925. <title>Git常见使用问题</title>
  926. <url>/posts/36fb1fe.html</url>
  927. <content><![CDATA[<p>Git是使用频率非常高的一个工具,在使用过程中遇到过不少的问题,现在汇总一下遇到过的问题以及对应的解决方法。</p>
  928. <span id="more"></span>
  929. <h1 id="无法访问Github"><a href="#无法访问Github" class="headerlink" title="无法访问Github"></a>无法访问Github</h1><p>Github服务器位于国外,因此经常出现无法访问的情况,影响了代码的拉取和提交等。要解决只能使用代理或者修改hosts文件。</p>
  930. <p>注:值得一提的就是,如果拉取代码的速度慢,也可以考虑通过设置代理来提高下载速度。</p>
  931. <h2 id="使用代理"><a href="#使用代理" class="headerlink" title="使用代理"></a>使用代理</h2><p>使用代理是比较常见的方法,对于Github网页的访问,直接运行代理软件就可以了,对于Git工具就需要进行配置,对应的代理配置项是<em>http.proxy</em>和<em>https.proxy</em></p>
  932. <p>查看当前代理设置</p>
  933. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 查看全局代理配置</span></span><br><span class="line">git config --global http.proxy</span><br><span class="line">git config --global https.proxy</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 查看当前项目代理配置</span></span><br><span class="line">git config --local http.proxy</span><br><span class="line">git config --local https.proxy</span><br></pre></td></tr></table></figure>
  934. <p>设置代理配置</p>
  935. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 设置全局代理配置</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> http代理</span></span><br><span class="line">git config --global http.proxy &#x27;http://127.0.0.1:1080&#x27;</span><br><span class="line">git config --global https.proxy &#x27;https://127.0.0.1:1080&#x27;</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 设置当前项目代理配置</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> http代理</span></span><br><span class="line">git config --local http.proxy &#x27;http://127.0.0.1:1080&#x27;</span><br><span class="line">git config --local https.proxy &#x27;https://127.0.0.1:1080&#x27;</span><br></pre></td></tr></table></figure>
  936. <p>删除代理配置</p>
  937. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 删除全局代理配置</span></span><br><span class="line">git config --global --unset http.proxy</span><br><span class="line">git config --global --unset https.proxy</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 删除当前项目代理配置</span></span><br><span class="line">git config --local --unset http.proxy</span><br><span class="line">git config --local --unset https.proxy</span><br></pre></td></tr></table></figure>
  938. <h2 id="修改hosts文件"><a href="#修改hosts文件" class="headerlink" title="修改hosts文件"></a>修改hosts文件</h2><p>这样方法没用过,请自行搜索解决方案。</p>
  939. <h1 id="不支持具有-socks5-方案的代理"><a href="#不支持具有-socks5-方案的代理" class="headerlink" title="不支持具有 socks5 方案的代理"></a>不支持具有 socks5 方案的代理</h1><p>Git提交代码到远程服务器,虽然提交成功,但显示异常信息,异常信息如下</p>
  940. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">fatal: NotSupportedException encountered.</span><br><span class="line"> ServicePointManager 不支持具有 socks5 方案的代理。</span><br></pre></td></tr></table></figure>
  941. <p>关键词:<em>socks5</em>和<em>代理</em>,这两个词有点熟悉,就是代理设置时经常遇到的字眼,先查看git配置</p>
  942. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">git config --global -l</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 显示信息如下</span></span><br><span class="line">......</span><br><span class="line">http.proxy=socks5://127.0.0.1:1080</span><br><span class="line">https.proxy=socks5://127.0.0.1:1080</span><br></pre></td></tr></table></figure>
  943. <p>问题就是这里了,<em>http.proxy</em>和<em>https.proxy</em>支持的都是http协议,不能使用socks协议。</p>
  944. <p>因此需要改回使用http协议的代理</p>
  945. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">git config --global http.proxy &#x27;http://127.0.0.1:1080&#x27;</span><br><span class="line">git config --global https.proxy &#x27;https://127.0.0.1:1080&#x27;</span><br></pre></td></tr></table></figure>
  946. <p>或者考虑不使用代理</p>
  947. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">git config --global --unset http.proxy</span><br><span class="line">git config --global --unset https.proxy</span><br></pre></td></tr></table></figure>
  948. <h1 id="拒绝访问-Connection-refused"><a href="#拒绝访问-Connection-refused" class="headerlink" title="拒绝访问 Connection refused"></a>拒绝访问 Connection refused</h1><p>提交代码到远程时遇到如下问题</p>
  949. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">fatal: unable to access &#x27;https://github.com/xxxxxxxxx.git/&#x27;: Failed to connect to 127.0.0.1 port 1080: Connection refused</span><br></pre></td></tr></table></figure>
  950. <p>这个问题很明显就是配置了代理信息,但是又忘记运行代理软件,导致无法连通远程服务器。</p>
  951. ]]></content>
  952. <categories>
  953. <category>工具</category>
  954. <category>开发工具</category>
  955. <category>Git</category>
  956. </categories>
  957. <tags>
  958. <tag>Git</tag>
  959. </tags>
  960. </entry>
  961. <entry>
  962. <title>Gogs配置为服务开机自启动</title>
  963. <url>/posts/bdb89eee.html</url>
  964. <content><![CDATA[<p><code>Gogs是一款极易搭建的自助 Git 服务</code>,安装起来也确实是这样,在安装目录下输入命令<code>./gogs web</code>就能启动Gogs服务,但如果是通过二进制方式进行安装每次都要输入命令拉起服务就很不方便了,因此需要手动把Gogs配置为Linux服务并开机自启动。</p>
  965. <span id="more"></span>
  966. <p><strong>注:假设当前的操作用户是git(为啥要用git用户下文细说),安装目录是/home/git/gogs !!!</strong></p>
  967. <h1 id="环境"><a href="#环境" class="headerlink" title="环境"></a>环境</h1><p>系统:CentOS 7</p>
  968. <p>Gogs版本:0.12.3</p>
  969. <h1 id="配置Gogs服务"><a href="#配置Gogs服务" class="headerlink" title="配置Gogs服务"></a>配置Gogs服务</h1><p>要配置为Linux服务,先要写一个配置脚本,而这一步Gogs已经贴心的帮我们完成了,放在了如下的位置</p>
  970. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">/home/git/gogs/scripts/systemd/gogs.service</span><br></pre></td></tr></table></figure>
  971. <p>然后复制到<code>/usr/lib/systemd/system/</code>目录下</p>
  972. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">cp /home/git/gogs/scripts/systemd/gogs.service /usr/lib/systemd/system/</span><br></pre></td></tr></table></figure>
  973. <p>执行如下命令,让Linux重新加载服务的配置信息</p>
  974. <figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">systemctl daemon-reload</span><br></pre></td></tr></table></figure>
  975. <p>如果不执行这一步会弹出警告信息</p>
  976. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">Warning: gogs.service changed on disk. Run &#x27;systemctl daemon-reload&#x27; to reload units.</span><br></pre></td></tr></table></figure>
  977. <p>到了这里就可以正常使用了。</p>
  978. <h1 id="Gogs服务自启动"><a href="#Gogs服务自启动" class="headerlink" title="Gogs服务自启动"></a>Gogs服务自启动</h1><p>配置好Gogs服务,剩下的就和其它的Linux服务没区别,直接用<code>systemctl</code>命令来控制就可以了。</p>
  979. <p>开启自启动</p>
  980. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">systemctl enable gogs</span><br></pre></td></tr></table></figure>
  981. <p>关闭自启动</p>
  982. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">systemctl disable gogs</span><br></pre></td></tr></table></figure>
  983. <p>手动启动服务</p>
  984. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">systemctl start gogs</span><br></pre></td></tr></table></figure>
  985. <p>手动关闭服务</p>
  986. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">systemctl stop gogs</span><br></pre></td></tr></table></figure>
  987. <p>查看服务状态</p>
  988. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">systemctl status gogs</span><br></pre></td></tr></table></figure>
  989. <h1 id="Gogs默认用户git"><a href="#Gogs默认用户git" class="headerlink" title="Gogs默认用户git"></a>Gogs默认用户git</h1><p>翻看一下Gogs安装目录下的脚本可以发现,很多地方的默认用户都是git,例如上文提到的<code>gogs.service</code>脚本</p>
  990. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 打开gogs.service脚本</span></span><br><span class="line">vi /home/git/gogs/scripts/systemd/gogs.service</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash">这里只截取了部分内容</span></span><br><span class="line">[Service]</span><br><span class="line"><span class="meta">#</span><span class="bash"> Modify these two values and uncomment them <span class="keyword">if</span> you have</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> repos with lots of files and get an HTTP error 500 because</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> of that</span></span><br><span class="line"><span class="meta">#</span><span class="bash"><span class="comment">##</span></span></span><br><span class="line"><span class="meta">#</span><span class="bash">LimitMEMLOCK=infinity</span></span><br><span class="line"><span class="meta">#</span><span class="bash">LimitNOFILE=65535</span></span><br><span class="line">Type=simple</span><br><span class="line">User=git</span><br><span class="line">Group=git</span><br><span class="line">WorkingDirectory=/home/git/gogs</span><br><span class="line">ExecStart=/home/git/gogs/gogs web</span><br><span class="line">Restart=always</span><br><span class="line">Environment=USER=git HOME=/home/git</span><br></pre></td></tr></table></figure>
  991. <p>因此怕麻烦不想修改脚本的,可以考虑新建一个git用户,不会新建的看这里<a href="https://www.zhixing.icu/archives/linux-cao-zuo-zhi-nan-01--xin-jian-yong-hu">Linux操作指南:01-新建用户</a>。</p>
  992. ]]></content>
  993. <categories>
  994. <category>工具</category>
  995. <category>开发工具</category>
  996. <category>Gogs</category>
  997. </categories>
  998. <tags>
  999. <tag>Gogs</tag>
  1000. </tags>
  1001. </entry>
  1002. <entry>
  1003. <title>IDEA输出中文乱码解决方法</title>
  1004. <url>/posts/3d0562c8.html</url>
  1005. <content><![CDATA[<p>IDEA输出中文乱码是个常见的问题了,记录下问题的解决方法,以及网上方法无效的原因。</p>
  1006. <span id="more"></span>
  1007. <p>先上结论:首先要确认是idea的问题,如果是则打开idea,选择help-&gt;Edit Custom VM Options,加入参数-Dfile.encoding=UTF-8,保存并重启,即可解决问题。</p>
  1008. <h1 id="定位"><a href="#定位" class="headerlink" title="定位"></a>定位</h1><p>要解决中文乱码问题,首先要知道是哪里导致了中文乱码,才能进行针对性的配置。</p>
  1009. <p>定位的方法很简单,就是使用排除法:</p>
  1010. <ul>
  1011. <li>直接用<em>java -jar</em>直接运行程序</li>
  1012. <li>直接用构建工具运行程序</li>
  1013. <li>是web程序则直接用tomcat运行</li>
  1014. </ul>
  1015. <p>这样就很清楚的知道是哪里的问题了。</p>
  1016. <p>但是!但是!但是!一般情况下上面的环节其实都是没问题的,主要问题是在idea的身上!</p>
  1017. <h1 id="配置"><a href="#配置" class="headerlink" title="配置"></a>配置</h1><blockquote>
  1018. <p>windows默认使用GBK,idea新装的时候也是使用GBK</p>
  1019. </blockquote>
  1020. <p>看到中文乱码,我们会自然的联想到是编码问题,所以会把GBK改为兼容性更好的UTF-8,具体操作如下:</p>
  1021. <ol>
  1022. <li>打开idea</li>
  1023. <li>选中工具栏中的<strong>Help</strong>标签下的<strong>Edit Custom VM Options</strong></li>
  1024. <li>加入参数 <strong>-Dfile.encoding=UTF-8</strong></li>
  1025. <li>保存并重启idea</li>
  1026. </ol>
  1027. <p>经过上述步骤,中文乱码就迎刃而解了。</p>
  1028. <h1 id="本质"><a href="#本质" class="headerlink" title="本质"></a>本质</h1><p>搜索引擎上能搜索到很多解决idea中文乱码的文章,都是在<strong>vmoptions</strong>中添加参数 <strong>-Dfile.encoding=UTF-8</strong>,但是就是没有效果!为啥?</p>
  1029. <p>其实是因为idea在用户目录下有一个<strong>vmoptions</strong>副本!!</p>
  1030. <p>跟着文章通常修改的是idea安装目录下的idea.exe.vmoptions和idea64.exe.vmoptions,说白点就是你修改的和idea使用的根本不是同一个,才会导修改没有效果。</p>
  1031. <h1 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h1><p><a href="https://www.cnblogs.com/sxdcgaq8080/p/7648400.html">重点在评论14楼</a></p>
  1032. ]]></content>
  1033. <categories>
  1034. <category>工具</category>
  1035. <category>开发工具</category>
  1036. <category>IDEA</category>
  1037. </categories>
  1038. <tags>
  1039. <tag>IDEA</tag>
  1040. </tags>
  1041. </entry>
  1042. <entry>
  1043. <title>Windows下的包管理工具scoop</title>
  1044. <url>/posts/b4c6dbe7.html</url>
  1045. <content><![CDATA[<p>在Windows系统上,安装软件总是要到官网上去下载安装,又不想使用XX管家类的软件,因此如果有像Linux上的包管理工具就方便了,<em>scoop</em>就是Windows下的包管理工具!</p>
  1046. <span id="more"></span>
  1047. <h1 id="安装"><a href="#安装" class="headerlink" title="安装"></a>安装</h1><p>scoop的安装很简单,官方提供了执行脚本让我们使用了,具体可看官网<a href="https://scoop.sh/">Installs in seconds</a>,步骤大概如下:</p>
  1048. <p>安装要求:</p>
  1049. <ol>
  1050. <li>PowerShell 5 或更高的版本</li>
  1051. <li>.NET Framework 4.5 或更高的版本</li>
  1052. </ol>
  1053. <p>安装命令如下</p>
  1054. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">Invoke-Expression (New-Object System.Net.WebClient).DownloadString(&#x27;https://get.scoop.sh&#x27;)</span><br></pre></td></tr></table></figure>
  1055. <p>或者</p>
  1056. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">iwr -useb get.scoop.sh | iex</span><br></pre></td></tr></table></figure>
  1057. <p>上面两条命令的效果是一样的。</p>
  1058. <p>如果安装时抛出异常,可以尝试如下命令修改执行策略,然后再尝试重新安装</p>
  1059. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">Set-ExecutionPolicy RemoteSigned -scope CurrentUser</span><br></pre></td></tr></table></figure>
  1060. <h1 id="scoop文件结构"><a href="#scoop文件结构" class="headerlink" title="scoop文件结构"></a>scoop文件结构</h1><p>scoop是安装在当前用户的用户文件夹下的,例如当前用户是test,则在Windows的位置如下</p>
  1061. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">C:\Users\test\scoop</span><br></pre></td></tr></table></figure>
  1062. <p>scoop根目录下,有如下几个文件夹</p>
  1063. <ul>
  1064. <li>apps:应用安装区域,所有应用都会安装在这里,每个安装的软件都有一个以自己名字命名的文件夹,内部如下<ul>
  1065. <li>以版本命名的文件夹,该文件夹下存放的是指定版本的该软件</li>
  1066. <li>current:快捷方式,连接到当前使用的版本</li>
  1067. </ul>
  1068. </li>
  1069. <li>buckets:安装源</li>
  1070. <li>cache:下载缓存</li>
  1071. <li>persist:应用的配置文件放置地方</li>
  1072. <li>shims:映射应用的bin中的文件,集中存放应用命令的链接或调用脚本,自动加入 path 路径中(自动进行兼容性处理),方便命令行的使用,且这样 path 的定义就会比较简洁,也容易管理。</li>
  1073. </ul>
  1074. <h1 id="常用操作"><a href="#常用操作" class="headerlink" title="常用操作"></a>常用操作</h1><p>安装完成后就可以开始使用了,打开cmd命令行界面输入所需命令即可。</p>
  1075. <p>不知道怎么用?使用帮助,即可了解到所有的命令及其用法</p>
  1076. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">scoop help</span><br></pre></td></tr></table></figure>
  1077. <p>注:下面以软件potplayer为例</p>
  1078. <p>输入关键字搜索想安装的软件,如果能安装则会显示可安装的软件列表,不能则会显示<em>Not Found</em>字眼</p>
  1079. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">scoop search potplayer</span><br></pre></td></tr></table></figure>
  1080. <p>安装软件</p>
  1081. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">scoop install potplayer</span><br></pre></td></tr></table></figure>
  1082. <p>卸载软件</p>
  1083. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">scoop uninstall potplayer</span><br></pre></td></tr></table></figure>
  1084. <p>更新软件</p>
  1085. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">scoop update potplayer</span><br></pre></td></tr></table></figure>
  1086. <p>更新scoop本身</p>
  1087. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">scoop update</span><br></pre></td></tr></table></figure>
  1088. <p>查看已安装软件列表</p>
  1089. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">scoop list</span><br></pre></td></tr></table></figure>
  1090. <p>查看当前的软件状态(显示当前的版本信息和可更新的版本信息)</p>
  1091. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">scoop status</span><br></pre></td></tr></table></figure>
  1092. <h1 id="添加bucket"><a href="#添加bucket" class="headerlink" title="添加bucket"></a>添加bucket</h1><p>bucket就是我们下载软件的源,查看scoop可以直接识别并添加的bucket</p>
  1093. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">scoop bucket known</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 显示如下</span></span><br><span class="line">main # 默认就有,但收录条件严格,软件较少</span><br><span class="line">extras # 这个最常用,软件最多</span><br><span class="line">versions</span><br><span class="line">nightlies</span><br><span class="line">nirsoft</span><br><span class="line">php</span><br><span class="line">nerd-fonts</span><br><span class="line">nonportable</span><br><span class="line">java</span><br><span class="line">games</span><br><span class="line">jetbrains</span><br></pre></td></tr></table></figure>
  1094. <p>添加bucket(这里以extras为例)</p>
  1095. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">scoop bucket add extras</span><br></pre></td></tr></table></figure>
  1096. <p>展示已有的bucket</p>
  1097. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">scoop bucket list</span><br></pre></td></tr></table></figure>
  1098. <p>移除bucket(这里以extras为例)</p>
  1099. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">scoop bucket rm extras</span><br></pre></td></tr></table></figure>
  1100. <h2 id="添加第三方bucket"><a href="#添加第三方bucket" class="headerlink" title="添加第三方bucket"></a>添加第三方bucket</h2><p>上面添加的bucket是官方认证的,我们也可以添加自己的bucket或者别人制作的bucket,这里是一个按照 Github score(由 Star 数量、Fork 数量和 App 数量综合决定的 Github score)排列的 bucket 列表:<a href="https://github.com/rasa/scoop-directory/blob/master/by-score.md">Scoop buckets by Github score</a>。对于第三方的操作稍微有些不一样:</p>
  1101. <p>添加第三方的bucket</p>
  1102. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">scoop bucket add &lt;仓库名&gt; &lt;仓库地址&gt;</span><br></pre></td></tr></table></figure>
  1103. <p>安装第三方bucket的应用</p>
  1104. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">scoop install &lt;仓库名&gt;/&lt;应用名&gt;</span><br></pre></td></tr></table></figure>
  1105. <p>安装应用前,可以用关键词“应用名+scoop”搜索一下,看看存不存在对应的bucket。</p>
  1106. <p>注:如果动手能力强的可以自己制作bucket。</p>
  1107. <h1 id="配置"><a href="#配置" class="headerlink" title="配置"></a>配置</h1><p>scoop允许我们对其进行配置,而我遇到过需要配置的就只有设置代理和aria2下载加速。</p>
  1108. <p>设置配置方式如下,如果多次设置则以最新的为准</p>
  1109. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">scoop config 配置名 配置值</span><br></pre></td></tr></table></figure>
  1110. <p>查看已设置的配置(这里只能一个一个查看,没有列出所有的方法)</p>
  1111. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">scoop config 配置名</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 如果设置了的话会显示配置的值</span></span><br><span class="line">配置值</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 如果没有设置的话会显示如下信息</span></span><br><span class="line">配置名 is not set</span><br></pre></td></tr></table></figure>
  1112. <p>移除配置</p>
  1113. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">scoop config rm 配置名</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 成功移除显示如下信息</span></span><br><span class="line">配置名 has been removed</span><br></pre></td></tr></table></figure>
  1114. <h2 id="配置代理"><a href="#配置代理" class="headerlink" title="配置代理"></a>配置代理</h2><p>有时候在国内下载速度慢,可以通过设置代理来提高下载速度。</p>
  1115. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">scoop config proxy &#x27;127.0.0.1:8080&#x27;</span><br></pre></td></tr></table></figure>
  1116. <p>这里只列举了我知道的方式,还有其它的设置代理方式<a href="https://github.com/lukesampson/scoop/wiki/Using-Scoop-behind-a-proxy">Configuring Scoop to use your proxy</a></p>
  1117. <h1 id="配置aria2下载加速"><a href="#配置aria2下载加速" class="headerlink" title="配置aria2下载加速"></a>配置aria2下载加速</h1><p>单纯的使用scoop下载速度可能不够快,这时候可以用scoop下载aria2来进一步提高下载速度,scoop会自动调用下载的aria2(注:一定要用scoop安装)</p>
  1118. <p>安装aria2</p>
  1119. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">scoop install aria2</span><br></pre></td></tr></table></figure>
  1120. <p>本身有默认参数值</p>
  1121. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">aria2-enabled (default: true) # 是否使用aria2加速下载,开启true,关闭false</span><br><span class="line">aria2-retry-wait (default: 2)</span><br><span class="line">aria2-split (default: 5)</span><br><span class="line">aria2-max-connection-per-server (default: 5) # 同时下载的线程数</span><br><span class="line">aria2-min-split-size (default: 5M)</span><br></pre></td></tr></table></figure>
  1122. <p>也可以自己进行参数设置</p>
  1123. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">scoop config aria2-max-connection-per-server 16</span><br><span class="line">scoop config aria2-split 16</span><br><span class="line">scoop config aria2-min-split-size 1M</span><br></pre></td></tr></table></figure>
  1124. <p>具体的参考<a href="https://scoop-docs.now.sh/docs/misc/Multi-connection-downloads-with-aria2.html">Multi-connection downloads with <code>aria2</code></a></p>
  1125. <h1 id="设置不同的开发环境版本"><a href="#设置不同的开发环境版本" class="headerlink" title="设置不同的开发环境版本"></a>设置不同的开发环境版本</h1><p>做程序开发的对于同一个开发环境可能需要安装不同的版本,例如:Java8和Java11、python2和python3,如果由自己做环境控制,就很麻烦了,通过scoop可以轻易的进行切换</p>
  1126. <p>假设我安装了jdk8和jdk11</p>
  1127. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">scoop list</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 下面显示的是已安装的软件列表</span></span><br><span class="line">......</span><br><span class="line">openjdk11 11.0.2-9 </span><br><span class="line">openjdk8-redhat 8u282-b08</span><br><span class="line">......</span><br></pre></td></tr></table></figure>
  1128. <p>切换至jdk8</p>
  1129. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">scoop reset openjdk8-redhat</span><br></pre></td></tr></table></figure>
  1130. <p>切换至jdk11</p>
  1131. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">scoop reset openjdk11</span><br></pre></td></tr></table></figure>
  1132. <h1 id="批量导入和导出"><a href="#批量导入和导出" class="headerlink" title="批量导入和导出"></a>批量导入和导出</h1><p>scoop安装了一系列软件后,换台设备还想继续使用这些软件,但是一个一个手动安装的话就太麻烦了,对于这方面scoop没有提供原生的支持,但是也有额外的方式能实现该要求:</p>
  1133. <p><a href="https://github.com/lukesampson/scoop/issues/1543#issuecomment-308894312">方式一:通过记录应用列表来实现</a></p>
  1134. <p><a href="%5BScoopBackup-pwsh%5D(https://github.com/Cologler/ScoopBackup-pwsh)">方式二:使用备份工具</a></p>
  1135. ]]></content>
  1136. <categories>
  1137. <category>工具</category>
  1138. <category>scoop</category>
  1139. </categories>
  1140. <tags>
  1141. <tag>scoop</tag>
  1142. </tags>
  1143. </entry>
  1144. <entry>
  1145. <title>深入操作系统-01环境创建</title>
  1146. <url>/posts/d1f7f56f.html</url>
  1147. <content><![CDATA[<p>要开发一个操作系统,搭建开发环境是必不可少的,本篇文章就介绍如何使用Linux、bochs搭建开发环境。</p>
  1148. <span id="more"></span>
  1149. <p>注意:本文章还没有涉及到C语言,所以环境搭建没有涉及到这部分,将会在后续进行补充。</p>
  1150. <h1 id="开发流程"><a href="#开发流程" class="headerlink" title="开发流程"></a>开发流程</h1><p>在不考虑其它的情况下,先要知道一个OS源码最后要怎么在机器上运行。</p>
  1151. <ol>
  1152. <li>编写一个汇编源码文件(a.asm)</li>
  1153. <li>使用nasm把汇编文件a.asm编译成二进制文件a.bin</li>
  1154. <li>把二进制文件a.bin写入到磁盘中(在开发环境中即a.img)</li>
  1155. <li>在bochs使用已写入汇编源码的磁盘(a.img)进行测试运行</li>
  1156. </ol>
  1157. <p>即源码文件经历了如下流程:.asm -&gt; a.bin -&gt; a.img</p>
  1158. <p>现在已经整个开发流程有了一个基本的认知了,下面逐一讲解需要用到的工具。</p>
  1159. <h1 id="Linux"><a href="#Linux" class="headerlink" title="Linux"></a>Linux</h1><p>是基本的编译环境,其次把编译好的二进制文件写入到磁盘中也需要用到Linux中的指令,即源码的编译与文件的写入都离开不了Linux。</p>
  1160. <h1 id="Nasm"><a href="#Nasm" class="headerlink" title="Nasm"></a>Nasm</h1><p>是一个汇编指令的编译软件,能把汇编文件编译成二进制文件。</p>
  1161. <h1 id="Bochs"><a href="#Bochs" class="headerlink" title="Bochs"></a>Bochs</h1><p>已经写好的程序该放到哪里运行呢?放到自己的电脑上,程序有故障怎么办!所以最好的办法是使用虚拟机,可以随便折腾,有问题也不怕,但是我们需要调试程序,所以使用普通的虚拟机也不行。</p>
  1162. <p>因此使用bochs就是一个极好的选择,既是虚拟机又带有调试功能。</p>
  1163. <p>在这里省略bochs的安装过程,主要看看使用bochs时需要用到的配置文件(注意:文件后缀是bxrc的就是bochs用到的配置文件,例:bochsrc.bxrc)</p>
  1164. <figure class="highlight plain"><table><tr><td class="code"><pre><span class="line"># 为虚拟机分配的内存(RAM)大小,默认单位是MB</span><br><span class="line">megs: 32</span><br><span class="line"></span><br><span class="line"># 这里还没研究</span><br><span class="line">romimage: file&#x3D;$BXSHARE&#x2F;BIOS-bochs-latest</span><br><span class="line">vgaromimage: file&#x3D;$BXSHARE&#x2F;VGABIOS-lgpl-latest</span><br><span class="line"></span><br><span class="line"># 使用的磁盘列表</span><br><span class="line">floppya: 1_44&#x3D;boot.img, status&#x3D;inserted</span><br><span class="line"></span><br><span class="line"># 选择引导磁盘 cdroom即光驱 floppy即软驱 disk即硬盘</span><br><span class="line">boot: floppy</span><br><span class="line"></span><br><span class="line"># 输出的日志文件</span><br><span class="line">log: bochsout.txt</span><br><span class="line"></span><br><span class="line"># 是否启用鼠标</span><br><span class="line">mouse: enabled&#x3D;0</span><br><span class="line"></span><br><span class="line"># 键盘布局</span><br><span class="line">keyboard: keymap&#x3D;$BXSHARE&#x2F;keymaps&#x2F;x11-pc-us.map</span><br></pre></td></tr></table></figure>
  1165. <p>注意:上文中提到的$BXSHARE即为bochs的安装目录。</p>
  1166. <p>通过配置文件可以知道,要运行我们自己写的操作系统,只需要在配置文件中的磁盘列表加入我们创建的磁盘,并在以到磁盘项中选择我们的磁盘,然后运行bochs即可。</p>
  1167. <h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><p>以上便是开发一个操作系统需要的基本开发环境,目前涉及到的C语言部分将在后面完善。</p>
  1168. ]]></content>
  1169. <categories>
  1170. <category>操作系统</category>
  1171. </categories>
  1172. <tags>
  1173. <tag>操作系统</tag>
  1174. </tags>
  1175. </entry>
  1176. <entry>
  1177. <title>圆周率的来历</title>
  1178. <url>/posts/5d007e64.html</url>
  1179. <content><![CDATA[<p>圆周率是通过实际<strong>测量</strong>得出的,即<strong>一个圆的周长和其直径的比率</strong>。</p>
  1180. <span id="more"></span>
  1181. <h1 id="结束语"><a href="#结束语" class="headerlink" title="结束语"></a>结束语</h1><p>不知道是学了忘记,还是说从来就不知道,今天才发现,所以特意记下圆周率是怎么来的。</p>
  1182. <h1 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h1><p><a href="https://zh.wikipedia.org/wiki/%E5%9C%93%E5%91%A8%E7%8E%87">维基百科:圆周率</a></p>
  1183. ]]></content>
  1184. <categories>
  1185. <category>数学</category>
  1186. </categories>
  1187. <tags>
  1188. <tag>数学</tag>
  1189. </tags>
  1190. </entry>
  1191. <entry>
  1192. <title>MySQL存储IP地址</title>
  1193. <url>/posts/e38e4cbe.html</url>
  1194. <content><![CDATA[<p>在MySQL中,没有专门用于存储IP地址的数据类型,但是可以使用inet_aton()函数把IP地址转换成整型数值进行存储,使用inet_ntoa()函数把整型数值转换回IP地址。</p>
  1195. <span id="more"></span>
  1196. <h1 id="inet-aton-和inet-ntoa-函数"><a href="#inet-aton-和inet-ntoa-函数" class="headerlink" title="inet_aton()和inet_ntoa()函数"></a>inet_aton()和inet_ntoa()函数</h1><p>inet_aton()和inet_ntoa()是MySQL提供的一对函数,一般情况下都是互相配合使用的:</p>
  1197. <ul>
  1198. <li>inet_aton():把IP地址转换成一个整型数值,其中的aton可以理解成 IP Address-&gt;Number</li>
  1199. <li>inet_ntoa():把整型数值转换成IP地址,其中的ntoa可以理解成Number-&gt;IP Address</li>
  1200. </ul>
  1201. <p>具体的流程:inet_aton(IP地址)—&gt;整型数值,inet_ntoa(整型数值)-&gt;IP地址</p>
  1202. <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta">&gt;</span><span class="bash"> select inet_aton(<span class="string">&#x27;255.255.255.255&#x27;</span>);</span></span><br><span class="line"><span class="meta">&gt;</span><span class="bash"> 4294967295</span></span><br><span class="line"></span><br><span class="line"><span class="meta">&gt;</span><span class="bash"> select inet_ntoa(<span class="string">&#x27;4294967295&#x27;</span>);</span></span><br><span class="line"><span class="meta">&gt;</span><span class="bash"> 255.255.255.255</span></span><br><span class="line"></span><br><span class="line"><span class="meta">&gt;</span><span class="bash"> select inet_aton(<span class="string">&#x27;0.0.0.0&#x27;</span>);</span> </span><br><span class="line"><span class="meta">&gt;</span><span class="bash"> 0</span></span><br><span class="line"></span><br><span class="line"><span class="meta">&gt;</span><span class="bash"> select inet_ntoa(<span class="string">&#x27;0&#x27;</span>);</span></span><br><span class="line"><span class="meta">&gt;</span><span class="bash"> 0.0.0.0</span></span><br></pre></td></tr></table></figure>
  1203. <h1 id="性能"><a href="#性能" class="headerlink" title="性能"></a>性能</h1><p>在不知道inet_aton()和inet_ntoa()函数存在的情况下,我们会想到使用varchar解决IP地址长度不固定的存储问题。但是为了更高的性能,MySQL为我们提供了专用的函数。</p>
  1204. <blockquote>
  1205. <p>IP地址范围:0.0.0.0 - 255.255.255.255</p>
  1206. </blockquote>
  1207. <p>根据IP地址的范围,使用varchar类型,存储IP地址的最小值(0.0.0.0)要占用7个字符,存储IP地址的最大值(255.255.255.255)要占用15个字符,按照一般使用UTF-8编码计算,存储占用在<strong>22~46个字节</strong>之间。</p>
  1208. <p>使用inet_aton()函数,IP地址的最大值(255.255.255.255)转换后产生的整型数值为<em>4294967295</em>,即只需要一个int类型即可存储,而一个int类型数据在数据库中只占用<strong>4个字节</strong>。</p>
  1209. <p>通过以上的分析可以了解到,使用函数对IP地址转换后进行存储比直接存储字符串在存储空间上要节省得多,其次在运算上也有明显的优势。</p>
  1210. <p>注意:因为没有在真实的场景中用IP地址进行过运算,这里没法给出例子,等以后以后遇到了再回来修改!</p>
  1211. ]]></content>
  1212. <categories>
  1213. <category>MySQL</category>
  1214. </categories>
  1215. <tags>
  1216. <tag>数据库</tag>
  1217. <tag>MySQL</tag>
  1218. </tags>
  1219. </entry>
  1220. <entry>
  1221. <title>MySQL开发时异常记录</title>
  1222. <url>/posts/a7ec3638.html</url>
  1223. <content><![CDATA[<p>记录开发过程中遇到过的MySQL异常。</p>
  1224. <span id="more"></span>
  1225. <h1 id="Unknown-error-1045"><a href="#Unknown-error-1045" class="headerlink" title="Unknown error 1045"></a>Unknown error 1045</h1><p>数据库的账号密码输入错误。</p>
  1226. <h1 id="Data-truncation-22001"><a href="#Data-truncation-22001" class="headerlink" title="Data truncation: #22001"></a>Data truncation: #22001</h1><figure class="highlight"><table><tr><td class="code"><pre><span class="line">Cause: com.mysql.cj.jdbc.exceptions.MysqlDataTruncation: Data truncation: #22001</span><br></pre></td></tr></table></figure>
  1227. <p>插入的数据值范围超过了字段在数据库中定义的范围。</p>
  1228. <h1 id="The-server-time-zone-value-‘�й���׼ʱ��’-is-unrecognized-or-represents-more-than-one-time-zone"><a href="#The-server-time-zone-value-‘�й���׼ʱ��’-is-unrecognized-or-represents-more-than-one-time-zone" class="headerlink" title="The server time zone value ‘�й���׼ʱ��’ is unrecognized or represents more than one time zone"></a>The server time zone value ‘�й���׼ʱ��’ is unrecognized or represents more than one time zone</h1><p>在较新版本的<em>mysql-connector-java</em>里,需要在连接数据库的url上加入<em>serverTimeZone</em>参数</p>
  1229. <figure class="highlight java"><table><tr><td class="code"><pre><span class="line"># 需要注意serverTimeZone的大小写</span><br><span class="line">jdbc:mysql:<span class="comment">//localhost:3306/test?serverTimezone=Asia/Shanghai&amp;useUnicode=true&amp;characterEncoding=utf-8</span></span><br></pre></td></tr></table></figure>
  1230. <p>一般情况使用参数<em>serverTimezone=Asia/Shanghai</em>,代表中国的时区(UTC+8)</p>
  1231. <p>如果有多国的时差问题,直接使用<em>serverTimezone=UTC</em>,即全球标准时间</p>
  1232. <p>可用参数参考:<a href="https://blog.csdn.net/Shezzer/article/details/80201264">mysql serverTimezone</a></p>
  1233. <h1 id="java-sql-SQLException-HY000"><a href="#java-sql-SQLException-HY000" class="headerlink" title="java.sql.SQLException: #HY000"></a>java.sql.SQLException: #HY000</h1><p>字段在数据库中定义为非空字段,但是插入数据时该字段对应的值却为空。</p>
  1234. ]]></content>
  1235. <categories>
  1236. <category>MySQL</category>
  1237. </categories>
  1238. <tags>
  1239. <tag>数据库</tag>
  1240. <tag>MySQL</tag>
  1241. </tags>
  1242. </entry>
  1243. <entry>
  1244. <title>事务操作和事务自动提交</title>
  1245. <url>/posts/11188dee.html</url>
  1246. <content><![CDATA[<p>写了这么久的SQL,怎么手动操作事务竟然快忘了,是时候复习一下了。</p>
  1247. <span id="more"></span>
  1248. <h1 id="环境"><a href="#环境" class="headerlink" title="环境"></a>环境</h1><p>数据库:MySQL 8(注:一定要使用支持事务的引擎,例如:InnoDB,MyISAM是不支持事务的)</p>
  1249. <h1 id="显式事务操作"><a href="#显式事务操作" class="headerlink" title="显式事务操作"></a>显式事务操作</h1><p>显式操作事务,无非就是3个动作:开启事务、提交、回滚 。</p>
  1250. <p>开启事务有如下两个命令,其效果都是一样的</p>
  1251. <figure class="highlight sql"><table><tr><td class="code"><pre><span class="line"><span class="keyword">start</span> transaction</span><br></pre></td></tr></table></figure>
  1252. <p>或</p>
  1253. <figure class="highlight sql"><table><tr><td class="code"><pre><span class="line"><span class="keyword">begin</span></span><br></pre></td></tr></table></figure>
  1254. <p>提交命令如下</p>
  1255. <figure class="highlight sql"><table><tr><td class="code"><pre><span class="line"><span class="keyword">commit</span></span><br></pre></td></tr></table></figure>
  1256. <p>回滚命令如下</p>
  1257. <figure class="highlight sql"><table><tr><td class="code"><pre><span class="line"><span class="keyword">rollback</span></span><br></pre></td></tr></table></figure>
  1258. <p>例子</p>
  1259. <figure class="highlight sql"><table><tr><td class="code"><pre><span class="line"># 提交</span><br><span class="line"><span class="keyword">start</span> transaction;</span><br><span class="line">......</span><br><span class="line"><span class="keyword">commit</span>;</span><br><span class="line"></span><br><span class="line"># 回滚</span><br><span class="line"><span class="keyword">begin</span>;</span><br><span class="line">......</span><br><span class="line"><span class="keyword">rollback</span>;</span><br></pre></td></tr></table></figure>
  1260. <p><strong>注:这里只是简单的展示了使用方法,复杂的需要用到条件语句,从而判断是使用commit还是rollback。</strong></p>
  1261. <h1 id="事务自动提交"><a href="#事务自动提交" class="headerlink" title="事务自动提交"></a>事务自动提交</h1><p>一般情况下数据库都是开启了事务自动提交的,因除非显式的开始一个事务,否则每个查询都被当做一个单独的事务执行。</p>
  1262. <p>是否自动提交,可以通过参数<strong>autocommit</strong>设置。通过如下命令查看当前的状态</p>
  1263. <figure class="highlight sql"><table><tr><td class="code"><pre><span class="line"><span class="keyword">show</span> variables <span class="keyword">like</span> <span class="string">&#x27;autocommit&#x27;</span>;</span><br></pre></td></tr></table></figure>
  1264. <table>
  1265. <thead>
  1266. <tr>
  1267. <th align="left">Variable_name</th>
  1268. <th>Value</th>
  1269. </tr>
  1270. </thead>
  1271. <tbody><tr>
  1272. <td align="left">autocommit</td>
  1273. <td>ON</td>
  1274. </tr>
  1275. </tbody></table>
  1276. <p>ON表示开启自动提交;OFF表示关闭自动提交,需要手动输入<em>commit</em>或<em>rollback</em>才能让事务生效。</p>
  1277. <figure class="highlight sql"><table><tr><td class="code"><pre><span class="line"># 开启自动提交</span><br><span class="line"><span class="keyword">set</span> autocommit<span class="operator">=</span><span class="number">1</span>;</span><br><span class="line"><span class="keyword">set</span> autocommit<span class="operator">=</span><span class="keyword">ON</span>;</span><br><span class="line"></span><br><span class="line"># 关闭自动提交</span><br><span class="line"><span class="keyword">set</span> autocommit<span class="operator">=</span><span class="number">0</span>;</span><br><span class="line"><span class="keyword">set</span> autocommit<span class="operator">=</span>OFF;</span><br></pre></td></tr></table></figure>
  1278. <p><strong>注意:设置的时候1和ON、0和OFF的效果是等同的。</strong></p>
  1279. ]]></content>
  1280. <categories>
  1281. <category>数据库</category>
  1282. </categories>
  1283. <tags>
  1284. <tag>数据库</tag>
  1285. <tag>MySQL</tag>
  1286. </tags>
  1287. </entry>
  1288. <entry>
  1289. <title>数据库事务</title>
  1290. <url>/posts/5874180.html</url>
  1291. <content><![CDATA[<p>事务是数据库中经常碰到的一个概念,总结一下相关知识,汇总对事务的理解。</p>
  1292. <span id="more"></span>
  1293. <h1 id="什么是事务"><a href="#什么是事务" class="headerlink" title="什么是事务"></a>什么是事务</h1><p>事务是逻辑上的一组操作,要么都执行,要么都不执行。</p>
  1294. <h1 id="事务的四大特性ACID"><a href="#事务的四大特性ACID" class="headerlink" title="事务的四大特性ACID"></a>事务的四大特性ACID</h1><ul>
  1295. <li>原子性(Atomicity):事务是最小的操作单位,不允许再分割,原子性确保了操作要么都执行要么都不执行。</li>
  1296. <li>一致性(Consistency):事务执行前后数据保持一致。理解上就是一个基本的转账操作,执行前后总额不变,不能多或少了。</li>
  1297. <li>隔离性(Isolation):并发访问数据库时,一个用户的事务不能被其它事务干扰。</li>
  1298. <li>持久性(Durability):事务提交后,对数据库中的数据的改变是持久的,即使数据库出现故障也不应该对其有任何影响。</li>
  1299. </ul>
  1300. <h1 id="并发事务带来的问题"><a href="#并发事务带来的问题" class="headerlink" title="并发事务带来的问题"></a>并发事务带来的问题</h1><p>为了提高性能,并发是必须的,多个事务经常会操作相同的数据来完成各自的任务,但会引发相关的问题:</p>
  1301. <ul>
  1302. <li>脏读(dirty-read):一个事务修改了数据但还没进行提交,这时另一个事务则读取并使用了该数据,这就是脏读。这个数据可能只是一个中间结果,未提交前都是不准确的,依据这样的数据做的处理都是不正确的,对于另一个事务而言,这个数据就是“脏数据”。</li>
  1303. <li>丢失修改(lost to modify):一个事务修改了某个数据,然后另一个事务也紧接着进行了修改,这样第一个事务的修改结果就会丢失。</li>
  1304. <li>不可重复读(Unrepeatable read):一个事务内多次读取同一个数据,事务未结束时,另一个事务对该数据进行了修改,那么第一个事务在两次读取之中,读到了不一样的数据。</li>
  1305. <li>幻读(phantom read):与不可重复读类似,一个事务多次读取多行记录时,另一个事务插入或删除了几行数据,导致第一个事务两次读取之中,读到了不一样的数据。</li>
  1306. </ul>
  1307. <h3 id="不可重复读和幻读的区别"><a href="#不可重复读和幻读的区别" class="headerlink" title="不可重复读和幻读的区别"></a>不可重复读和幻读的区别</h3><p>不可重复读的重点是某行记录的修改,例如:多次读取某个数据,发现数据被修改了。</p>
  1308. <p>幻读的重点是多行记录的新增或删除,例如:多次读取数据,返现记录增加或者减少了。</p>
  1309. <h1 id="事务的四个隔离级别"><a href="#事务的四个隔离级别" class="headerlink" title="事务的四个隔离级别"></a>事务的四个隔离级别</h1><p>SQL标准定义了四个隔离级别</p>
  1310. <p>读取未提交(read-uncommitted):最低的隔离级别,允许读取尚未提交的数据变更,无法防止:脏读、不可重复读和幻读。</p>
  1311. <p>读取已提交(read-committed):允许读取事务已经提交的数据,可以防止脏读,但是仍无法防止:不可重复读和幻读。</p>
  1312. <p>可重复读(repeatable-read):对同一个数据的多此读取结果都是一样的,除非是被本身的事务所修改,可以防止:脏读、不可重复读,但是仍无法防止:幻读。</p>
  1313. <p>串行化(serializable):最高的隔离级别,所有事务逐个执行,这样事务间就不会互相干扰,但是性能也是最差的,可以防止:脏读、不可重复读以及幻读。</p>
  1314. <table>
  1315. <thead>
  1316. <tr>
  1317. <th><em><strong>*隔离级别*</strong></em></th>
  1318. <th><em><strong>*脏读*</strong></em></th>
  1319. <th><em><strong>*不可重复读*</strong></em></th>
  1320. <th><em><strong>*幻读*</strong></em></th>
  1321. </tr>
  1322. </thead>
  1323. <tbody><tr>
  1324. <td>READ-UNCOMMITTED</td>
  1325. <td>√</td>
  1326. <td>√</td>
  1327. <td>√</td>
  1328. </tr>
  1329. <tr>
  1330. <td>READ-COMMITTED</td>
  1331. <td>×</td>
  1332. <td>√</td>
  1333. <td>√</td>
  1334. </tr>
  1335. <tr>
  1336. <td>REPEATABLE-READ</td>
  1337. <td>×</td>
  1338. <td>×</td>
  1339. <td>√</td>
  1340. </tr>
  1341. <tr>
  1342. <td>SERIALIZABLE</td>
  1343. <td>×</td>
  1344. <td>×</td>
  1345. <td>×</td>
  1346. </tr>
  1347. </tbody></table>
  1348. ]]></content>
  1349. <categories>
  1350. <category>数据库</category>
  1351. </categories>
  1352. <tags>
  1353. <tag>数据库</tag>
  1354. <tag>MySQL</tag>
  1355. </tags>
  1356. </entry>
  1357. <entry>
  1358. <title>双向链表和双向循环链表</title>
  1359. <url>/posts/12626135.html</url>
  1360. <content><![CDATA[<p>双向链表是一种非常常用的数据结构,在双向链表的基础上还有一个双向循环链表。</p>
  1361. <span id="more"></span>
  1362. <h1 id="双向链表"><a href="#双向链表" class="headerlink" title="双向链表"></a>双向链表</h1><p>一个元素节点中包含两个额外的指针,一个prev指向前驱节点,一个next指向后继节点</p>
  1363. <p><img src="/images/%E5%8F%8C%E5%90%91%E9%93%BE%E8%A1%A8.png" alt="双向链表"></p>
  1364. <h1 id="双向循环链表"><a href="#双向循环链表" class="headerlink" title="双向循环链表"></a>双向循环链表</h1><p>在双向链表的基础上,尾部元素的next指向链表的头部,头部元素的prev指向链表的尾部</p>
  1365. <p><img src="/images/%E5%8F%8C%E5%90%91%E5%BE%AA%E7%8E%AF%E9%93%BE%E8%A1%A8.png" alt="双向循环链表"></p>
  1366. ]]></content>
  1367. <categories>
  1368. <category>数据结构</category>
  1369. </categories>
  1370. <tags>
  1371. <tag>数据结构</tag>
  1372. </tags>
  1373. </entry>
  1374. <entry>
  1375. <title>博客之2019</title>
  1376. <url>/posts/87daa986.html</url>
  1377. <content><![CDATA[<p>2019年的第三个月即将过去了,现在才写这篇文章好像迟了一点,不过种一棵树最好的时间是十年前,其次是现在,这样子安慰自己的话,好像还不算晚。</p>
  1378. <p>在2018年里仅仅写了几篇文章,不过幸运的是因为有个博客,所以总想着弄点什么来写写,从而养成了写文档的习惯,遇到不懂的、特别的都有记录下来,期望在后面的时间里写到博客上。</p>
  1379. <p>在前段时间,突然萌生了换个博客的想法,wordpress、typecho、hugo这些都研究了一圈,感觉就像换了一个博客所有的事情都将变得会不一样似的,就像2018年里的目标并没有达成,反而是东学学西学学但并没有实质性的进展。</p>
  1380. <p>最后的最后,其实自己需要的是一点坚持——对目标的坚持,也是对适合自己的学习方法的一个概括:坚持!每天运动一下、学习一下、记录一下,明天就会有那么一点不一样!</p>
  1381. <p>题外话:最后还是没忍住折腾劲,对博客进行了修改,当然博客程序还是那个,但是配置上做了很多修改,对以前的文章的结构、分类、命名、内容这些也不大满意,所以也进行了修改。</p>
  1382. ]]></content>
  1383. <categories>
  1384. <category>日志</category>
  1385. </categories>
  1386. <tags>
  1387. <tag>日志</tag>
  1388. </tags>
  1389. </entry>
  1390. <entry>
  1391. <title>博客之始</title>
  1392. <url>/posts/40124174.html</url>
  1393. <content><![CDATA[<p>以前总是看别人写的博客,用OneNote做的笔记,当面试的时候被问到:你有写博客吗?我的回答是NO! 那时候以为写博客离自己很遥远,觉得自己的水平低写不出什么东西来,但是现在仔细想想,不正是因为自己的水平低才更要写博客吗!</p>
  1394. <p>通过写博客来做笔记并且加入自己的思考,摆脱以前一贯的只记忆不思考的习惯,一次又一次地修改完善,才能更好的提高自己的能力。</p>
  1395. <p>在这特殊的一天,踏出新的一步,祝2018年大家越来越好!</p>
  1396. ]]></content>
  1397. <categories>
  1398. <category>日志</category>
  1399. </categories>
  1400. <tags>
  1401. <tag>日志</tag>
  1402. </tags>
  1403. </entry>
  1404. <entry>
  1405. <title>wait()和sleep()方法的区别</title>
  1406. <url>/posts/9a65c93a.html</url>
  1407. <content><![CDATA[<p>多线程开发中,让线程暂停执行是常见场景,Java提供了*sleep()<em>和</em>wait()*两种实现方法,但在具体使用上又有稍微差别。</p>
  1408. <span id="more"></span>
  1409. <h1 id="异同"><a href="#异同" class="headerlink" title="异同"></a>异同</h1><ul>
  1410. <li>相同点:*sleep()<em>和</em>wait()*的作用都是暂停线程的执行,进入阻塞状态,让出CPU时间片段。</li>
  1411. <li>区别<ul>
  1412. <li>锁资源的释放:*sleep()<em>方法调用后线程不会释放锁资源;</em>wait()*方法调用后线程会释放锁资源。</li>
  1413. <li>使用场景:*sleep()<em>仅用于线程暂停执行;</em>wait()*通常用于线程间交互或通信;</li>
  1414. <li>线程唤醒:*sleep()*调用后线程会自动唤醒(由系统调度器唤醒,时间到了被调度);wait()调用后,线程不会自动唤醒(需要其它线程使用同一个对象上的notify()或者notifyAll()方法唤醒),也可以使用带有超时设置的wait()方法超时后自动唤醒。</li>
  1415. </ul>
  1416. </li>
  1417. </ul>
  1418. ]]></content>
  1419. <categories>
  1420. <category>Java</category>
  1421. <category>多线程</category>
  1422. </categories>
  1423. <tags>
  1424. <tag>Java</tag>
  1425. </tags>
  1426. </entry>
  1427. <entry>
  1428. <title>线程和线程池的关闭</title>
  1429. <url>/posts/c6b69b48.html</url>
  1430. <content><![CDATA[<p>为了最大限度的提高系统性能,线程和线程池的使用都是必不可少的,使用后往往面临一个相同的问题:关闭!</p>
  1431. <span id="more"></span>
  1432. <h1 id="线程的关闭"><a href="#线程的关闭" class="headerlink" title="线程的关闭"></a>线程的关闭</h1><p>由于不知道线程的运行状态,因此在运行途中直接关闭一个线程是非常危险的操作,JDK文档上就有这样一个例子:假如线程获取了某把锁,然后强制关闭了,会导致锁资源无法被释放的严重后果。因此Thread类上的<em>stop()<em>方法在Java版本1.2就</em>不推荐使用</em>了。</p>
  1433. <p>运行途中线程何时能关闭,只有线程自己知道,开发者能做的就是调用中断方法*interrupt()*通知线程关闭。</p>
  1434. <p>调用*interrupt()*方法,在不同的场景下会有不同的效果(版本:Java11)</p>
  1435. <ul>
  1436. <li><p>被<em>Object类的wait()、wait(long)、wait(long, int)方法</em>或者<em>Thread类的join()、join(long)、join(long, int)、sleep(long)、sleep(long, int)方法</em>调用而阻塞的线程,将会<strong>清除中断状态</strong>,同时<strong>抛出异常InterruptedException</strong></p>
  1437. </li>
  1438. <li><p>对于被IO阻塞的线程</p>
  1439. <ul>
  1440. <li>如果是被NIO中的channel操作而阻塞的,将会<strong>设置中断状态</strong>,同时<strong>抛出异常ClosedByInterruptException</strong></li>
  1441. <li>如果是被NIO中的Selectorl操作而阻塞的,只会<strong>设置中断状态</strong></li>
  1442. </ul>
  1443. </li>
  1444. <li><p>不符合以上条件的,就直接<strong>设置中断状态</strong></p>
  1445. </li>
  1446. <li><p>对于还没启动的线程或者线程已被销毁的,调用*interrupt()*方法是<strong>没有任何效果</strong>的</p>
  1447. </li>
  1448. </ul>
  1449. <p>调用*interrupt()<em>方法后,如果抛出异常,我们就可以通过捕获异常来让线程正常退出了,如果没有抛出异常仅是设置了中断状态,就要依靠线程中的代码逻辑来判断了,在代码中的适当位置调用</em>isInterrupted()*来查看自己是否被中断,进而让线程正常退出。</p>
  1450. <p>要注意的是:线程先调用*interrupt()*方法再被阻塞的话,就会抛出异常,但是捕获异常后再被阻塞的话,将不会再次抛出异常。</p>
  1451. <p>Thread类还有一些其它类似的方法:</p>
  1452. <ul>
  1453. <li>isInterrupted()方法:测试当前线程是否被中断,但是不会修改中断状态。</li>
  1454. <li>interrupted()方法:测试当前线程是否被中断,但是会清除中断状态,即原本是设置了中断状态的线程,调用该方法后,会变成没有将中断。</li>
  1455. <li>isAlive()方法:测试当前线程是否存在(存在指的是:线程已启动且还没被销毁)。</li>
  1456. <li>Thread.interrupted()静态方法:与*interrupted()*方法的效果一样,但是实现方式不同。</li>
  1457. </ul>
  1458. <h1 id="线程池的关闭"><a href="#线程池的关闭" class="headerlink" title="线程池的关闭"></a>线程池的关闭</h1><p>线程池提供了两个关闭线程池的方法:**shutdownNow()<strong>和</strong>shutdown()**。</p>
  1459. <ul>
  1460. <li><p>shutdownNow方法:尝试停止正在执行的任务,暂停等待任务的处理,并返回正在等待执行的任务列表,这个方法不保证能停止正在执行的任务。</p>
  1461. </li>
  1462. <li><p>shutdown方法:依次关闭之前提交执行的任务,并且拒绝接收新的任务,如果线程池已关闭但又调用了该方法将不会有任何影响。</p>
  1463. </li>
  1464. </ul>
  1465. <p>调用**shutdownNow()<strong>或</strong>shutdown()*<em>方法后,线程池并不是立刻关闭的,要想等待线程池关闭,需要调用</em>awaitTermination()*方法来阻塞等待。</p>
  1466. <h2 id="简单的源码分析"><a href="#简单的源码分析" class="headerlink" title="简单的源码分析"></a>简单的源码分析</h2><p>shutdownNow()关键源码如下</p>
  1467. <figure class="highlight java"><table><tr><td class="code"><pre><span class="line">advanceRunState(STOP);</span><br><span class="line">interruptWorkers();</span><br><span class="line">tasks = drainQueue();</span><br></pre></td></tr></table></figure>
  1468. <p>第一段是设置线程池的状态为停止,第二段是遍历工作队列调用线程的调用*interrupt()*方法,第三段是返回任务队列。</p>
  1469. <p>shutdown()关键源码是类似的</p>
  1470. <figure class="highlight java"><table><tr><td class="code"><pre><span class="line">advanceRunState(SHUTDOWN);</span><br><span class="line">interruptIdleWorkers();</span><br></pre></td></tr></table></figure>
  1471. <p>第一段是设置线程池的状态为关闭,第二段是遍历工作队列调用线程的调用*interrupt()*方法。</p>
  1472. <p><em>注意:上述源码分析非常粗浅,请自行查阅相关资料。</em></p>
  1473. ]]></content>
  1474. <categories>
  1475. <category>Java</category>
  1476. <category>多线程</category>
  1477. </categories>
  1478. <tags>
  1479. <tag>Java</tag>
  1480. </tags>
  1481. </entry>
  1482. <entry>
  1483. <title>MyBatis的占位符</title>
  1484. <url>/posts/daf2aad3.html</url>
  1485. <content><![CDATA[<p>代码中访问数据库的时候,经常需要传输参数用作语句条件,这就不得不用到MyBatis提供的占位符。</p>
  1486. <span id="more"></span>
  1487. <h1 id="占位符:-和"><a href="#占位符:-和" class="headerlink" title="占位符:#{ } 和 ${ }"></a>占位符:#{ } 和 ${ }</h1><p>MyBatis中有两种占位符:**#{ }** 和 **${ }**,MyBatis对它们的处理方式是不同的:</p>
  1488. <ul>
  1489. <li>#{}是预编译处理:告诉 MyBatis 创建一个预处理语句(PreparedStatement)参数,在 JDBC 中,这样的一个参数在 SQL 中会由一个“?”来标识,并被传递到一个新的预处理语句中。</li>
  1490. <li>${}是字符串替换:用于在SQL语句中插入一个不转义的字符串。MyBatis 不会修改或转义字符串。当 SQL 语句中的元数据(如表名或列名)是动态生成的时候,字符串替换将会非常有用。用这种方式接受用户的输入,并将其用于语句中的参数是不安全的,会导致潜在的 SQL 注入攻击,因此要么不允许用户输入这些字段,要么自行转义并检验</li>
  1491. </ul>
  1492. <h2 id="用法"><a href="#用法" class="headerlink" title="用法"></a>用法</h2><p>两种占位符的用法基本上是一致的,在Java代码中使用注解*@Param*,通过注解定指可用的参数及其参数名,例:</p>
  1493. <figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="comment">// 参数是基本类型</span></span><br><span class="line"><span class="function">User <span class="title">findById</span><span class="params">(<span class="meta">@Param(&quot;demoId&quot;)</span> <span class="keyword">long</span> id)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 参数是对象</span></span><br><span class="line"><span class="function">List&lt;User&gt; <span class="title">find</span><span class="params">(<span class="meta">@Param(&quot;demoQuery&quot;)</span> Query query)</span></span>;</span><br></pre></td></tr></table></figure>
  1494. <p>然后在xml配置文件中通过占位符传入参数,对于参数是基本数据类型获取方式如下</p>
  1495. <figure class="highlight xml"><table><tr><td class="code"><pre><span class="line">select * from test where id = #&#123;demoId&#125;;</span><br><span class="line">select * from test where id = $&#123;demoId&#125;;</span><br></pre></td></tr></table></figure>
  1496. <p>对于参数是对象,需要显式指定需要传入的对象属性,例如</p>
  1497. <figure class="highlight xml"><table><tr><td class="code"><pre><span class="line">select * from test where id = #&#123;demoQuery.id&#125;;</span><br><span class="line">select * from test where id = $&#123;demoQuery.id&#125;;</span><br></pre></td></tr></table></figure>
  1498. <p>稍微要提一下的是,虽然**#{ }** 和 **${ }**均为通过参数名来获得对应的值,但使用上还是有细微差别的。</p>
  1499. <p>对于参数是基本数据类型,**${ }<strong>的变量名必须为@Param注解中指定的参数名,</strong>#{ }**中的变量名可以是@Param注解中指定的参数名或者方法中的参数名,例如</p>
  1500. <figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="comment">// 参数是基本类型</span></span><br><span class="line"><span class="function">User <span class="title">findById</span><span class="params">(<span class="meta">@Param(&quot;demoId&quot;)</span> <span class="keyword">long</span> id)</span></span>;</span><br></pre></td></tr></table></figure>
  1501. <figure class="highlight xml"><table><tr><td class="code"><pre><span class="line"><span class="comment">&lt;!-- #&#123;&#125;中的变量名可以是@Param注解中指定的参数名或者方法中的参数名 --&gt;</span></span><br><span class="line">select * from test where id = #&#123;id&#125;;</span><br><span class="line">select * from test where id = #&#123;demoId&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">&lt;!-- $&#123;&#125;的变量名必须为@Param注解中指定的参数名 --&gt;</span></span><br><span class="line">select * from test where id = $&#123;demoId&#125;;</span><br></pre></td></tr></table></figure>
  1502. <h2 id="性能和安全"><a href="#性能和安全" class="headerlink" title="性能和安全"></a>性能和安全</h2><ul>
  1503. <li>性能方面:**${ }<strong>是字符串替换,</strong>#{ }<strong>是预编译的,而相同的预编译SQL是可以重复利用的,因此</strong>#{}**性能更高。</li>
  1504. <li>安全方面:由于**${ }<strong>是字符串替换,参数传入什么就使用的是什么,如果没有经过检查和转义的话会有SQL注入的风险,而预编译的</strong>#{ }**没有这方面的顾虑</li>
  1505. </ul>
  1506. <p>因此在实际开发中,能用**#{ }<strong>的就用</strong>#{ }**。</p>
  1507. <h1 id="拓展"><a href="#拓展" class="headerlink" title="拓展"></a>拓展</h1><h2 id="MyBatis中SQL执行顺序"><a href="#MyBatis中SQL执行顺序" class="headerlink" title="MyBatis中SQL执行顺序"></a>MyBatis中SQL执行顺序</h2><ol>
  1508. <li><p>对SQL语句进行动态解析,主要包括:</p>
  1509. <ul>
  1510. <li>占位符的处理</li>
  1511. <li>动态SQL的处理</li>
  1512. <li>参数类型校验</li>
  1513. </ul>
  1514. </li>
  1515. <li><p>SQL预编译</p>
  1516. </li>
  1517. </ol>
  1518. <h2 id="SQL预编译"><a href="#SQL预编译" class="headerlink" title="SQL预编译"></a>SQL预编译</h2><p>MyBatis默认情况下,将对所有的 sql 进行预编译。</p>
  1519. <p>SQL预编译指的是数据库驱动在发送SQL 语句和参数给 DBMS 之前对 SQL语句进行编译,这样 DBMS 执行 SQL时,就不需要重新编译。</p>
  1520. <p>在Java中通过JDBC中的PreparedStatement实现预编译</p>
  1521. <figure class="highlight java"><table><tr><td class="code"><pre><span class="line">String selectPerson = <span class="string">&quot;SELECT * FROM PERSON WHERE ID=?&quot;</span>;</span><br><span class="line">PreparedStatement ps = conn.prepareStatement(selectPerson);</span><br><span class="line">ps.setInt(<span class="number">1</span>,id);</span><br></pre></td></tr></table></figure>
  1522. <p>预编译有两个好处:</p>
  1523. <ol>
  1524. <li>优化SQl的执行:预编译之后的SQL多数情况下可以直接执行,DBMS 不需要再次编译,越复杂的SQL,编译的复杂度将越大,预编译阶段可以合并多次操作为一个操作。</li>
  1525. <li>预编译语句对象可以重复利用:把一个SQL预编译后产生的 PreparedStatement 对象缓存下来,下次对于同一个SQL,可以直接使用这个缓存的 PreparedState 对象。</li>
  1526. </ol>
  1527. <h1 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h1><p><a href="https://segmentfault.com/a/1190000004617028">https://segmentfault.com/a/1190000004617028</a></p>
  1528. <p><a href="https://www.cnblogs.com/huanyou/p/7201480.html">https://www.cnblogs.com/huanyou/p/7201480.html</a></p>
  1529. ]]></content>
  1530. <categories>
  1531. <category>Java</category>
  1532. <category>框架</category>
  1533. <category>MyBatis</category>
  1534. </categories>
  1535. <tags>
  1536. <tag>MyBatis</tag>
  1537. </tags>
  1538. </entry>
  1539. <entry>
  1540. <title>MyBatis缓存机制</title>
  1541. <url>/posts/201dbebe.html</url>
  1542. <content><![CDATA[<p>MyBatis提供了强大的事务性查询缓存机制,用于提高查询性能!</p>
  1543. <span id="more"></span>
  1544. <p>MyBatis的缓存分为:本地缓存和二级缓存,另外还可以实现自己的缓存或者使用第三方的缓存机制。</p>
  1545. <h1 id="本地缓存"><a href="#本地缓存" class="headerlink" title="本地缓存"></a>本地缓存</h1><p>MyBatis默认开启本地缓存,且无法手动关闭。</p>
  1546. <p>本地缓存属于会话级别的(sqlsession),生命周期与sqlsession一致,只对同一个sqlsession有效,不同sqlsession之间不共享缓存,</p>
  1547. <p>任何的修改操作(insert、update、delete)都会导致缓存清除,也可以通过配置使得查询前清空缓存。</p>
  1548. <h1 id="二级缓存"><a href="#二级缓存" class="headerlink" title="二级缓存"></a>二级缓存</h1><p>二级缓存默认关闭,需要手动开启。</p>
  1549. <p>二级缓存属于全局级别的(sqlsessionfactory),能够跨会话访问,弥补本地缓存无法跨会话访问的缺陷,开启后缓存使用时是先访问二级缓存再访问一级缓存。</p>
  1550. <h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><p>对于MyBatis的缓存机制只是流于表面,还没有更多的深入了解,且实现自己的缓存或使用第三方缓存机制这些也没有涉略,因此该篇文章仅做记录用。</p>
  1551. ]]></content>
  1552. <categories>
  1553. <category>Java</category>
  1554. <category>框架</category>
  1555. <category>MyBatis</category>
  1556. </categories>
  1557. <tags>
  1558. <tag>MyBatis</tag>
  1559. </tags>
  1560. </entry>
  1561. <entry>
  1562. <title>注解@Autowired和@Resource区别</title>
  1563. <url>/posts/f6f32af4.html</url>
  1564. <content><![CDATA[<p>Spring提供了注解@Autowired用于依赖注入,同时也支持使用Java本身提供的注解@Resource用于依赖注入,这两个注解有什么异同呢?</p>
  1565. <span id="more"></span>
  1566. <h1 id="相同点"><a href="#相同点" class="headerlink" title="相同点"></a>相同点</h1><p><em>@Autowired</em>和*@Resource*都是用来装配bean的,都可以注解在字段上和setter方法上</p>
  1567. <h1 id="区别"><a href="#区别" class="headerlink" title="区别"></a>区别</h1><ul>
  1568. <li>归属上:*@Autowired<em>是属于Spring的,</em>@Resource*是属于Java的。</li>
  1569. <li>装配方式:<ul>
  1570. <li><em>@Autowired</em>默认按照类型装配(默认情况下依赖对象必须存在,如果允许null,可以设置required属性为false),如果需要按照名称匹配需要结合@Qualifier使用。要注意只能有一个实现类否则存在多个候选对象会报错。</li>
  1571. <li>@Resource默认按照名称装配,名称通过name属性指定(不指定时取字段名或者setter方法上的属性名),当根据名称找不到时会按照类型进行装配,如果name一旦指定就只会按照名称进行装配。使用@Resource能较少代码耦合。</li>
  1572. </ul>
  1573. </li>
  1574. </ul>
  1575. <p>注:速度上,这两种方式都是直接指定name是最快的。</p>
  1576. ]]></content>
  1577. <categories>
  1578. <category>Java</category>
  1579. <category>框架</category>
  1580. <category>Spring</category>
  1581. </categories>
  1582. <tags>
  1583. <tag>Spring</tag>
  1584. </tags>
  1585. </entry>
  1586. </search>