-
Notifications
You must be signed in to change notification settings - Fork 0
/
atom.xml
448 lines (278 loc) · 167 KB
/
atom.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>ytlm</title>
<subtitle>stay hungry, stay foolish.</subtitle>
<link href="/atom.xml" rel="self"/>
<link href="https://ytlm.github.io/"/>
<updated>2019-07-04T10:25:44.054Z</updated>
<id>https://ytlm.github.io/</id>
<author>
<name>ytlm</name>
</author>
<generator uri="http://hexo.io/">Hexo</generator>
<entry>
<title>arch linux 初次安装成功</title>
<link href="https://ytlm.github.io/2018/06/arch-linux-%E5%88%9D%E6%AC%A1%E5%AE%89%E8%A3%85%E6%88%90%E5%8A%9F/"/>
<id>https://ytlm.github.io/2018/06/arch-linux-初次安装成功/</id>
<published>2018-06-28T08:59:34.000Z</published>
<updated>2019-07-04T10:25:44.054Z</updated>
<content type="html"><![CDATA[<p>之前一直对archlinux有很大的兴趣,期间也去尝试去安装,不过全部都失败了,最近又有时间,终于安装完成,并且安装了gnome桌面。感觉用的时候是非常好的。everything is simple。首先说一下现在装好,感觉最难的就是磁盘分区和格式化,选择什么样的分区方法,怎样分区。</p><a id="more"></a><h3 id="准备"><a href="#准备" class="headerlink" title="准备"></a>准备</h3><p>首先要到官网上下在<a href="https://www.archlinux.org/download/" target="_blank" rel="noopener">iso</a>,做一个u盘启动盘,或者软盘,或者用virtualbox安装。</p><blockquote><p>linux系统可以直接用<strong>dd</strong>,windows系统可以用<strong><a href="https://rufus.akeo.ie/" target="_blank" rel="noopener">rufus</a></strong></p></blockquote><h4 id="确认引导方式"><a href="#确认引导方式" class="headerlink" title="确认引导方式"></a>确认引导方式</h4><p>用命令<code>ls /sys/firmware/efi/efivars</code>,<a href="https://wiki.archlinux.org/index.php/GRUB" target="_blank" rel="noopener">详细情况看这里</a></p><ul><li><code>ls: cannot access '/sys/firmware/efi/efivars': No such file or directory</code> 这样表示是BIOS引导方式</li><li><img src="https://drive.google.com/uc?export=view&id=1lFfBZtn6oL1W1nelZuSl8sCATzpXZD5z" alt>如果显示的是这样表示是UEFI引导方式<blockquote><p>我这里就是这样的,为UEFI引导方式启动的,一下全部按照这种方式进行操作的。</p></blockquote></li></ul><h4 id="分区并格式化"><a href="#分区并格式化" class="headerlink" title="分区并格式化"></a>分区并格式化</h4><p>分区用的是fdisk,当然还有其它的工具分区,基本上都是大同小异的</p><ul><li><p>[1] 首先用<code>fdisk -l</code>查看磁盘情况,这里我只有一块磁盘,所以显示的是<code>/dev/sda</code>还有此块磁盘相关的一些信息如下:<img src="https://drive.google.com/uc?export=view&id=15MIAiNNPz0J19got9ErdWhp-8FfbxNAk" alt></p></li><li><p>[2] 我这里分区是按照<code>/</code>,<code>/boot</code> , <code>/home</code>, <code>swap</code>这四个分区</p><blockquote><p>大小 <code>/</code> 10G , <code>/home</code> 5G , <code>/boot</code> 1G , <code>swap</code> 4G<br>类型 <code>/</code> linux filesystem , <code>/home</code> linux filesystem , <code>/boot</code> EFI , <code>swap</code> linux swap</p></blockquote></li><li><p>[3] 然后<code>fdisk /dev/sda</code>,开始分区,<a href="https://wiki.archlinux.org/index.php/Fdisk" target="_blank" rel="noopener">详细情况看这里</a></p><ul><li>(3.1) 首先输入 <code>g</code> create a new empty GPT partition table<ul><li><img src="https://drive.google.com/uc?export=view&id=1fp_ufEkX_RCeCzAfAyLPkBAU8CuHE5eT" alt></li></ul></li><li>(3.2) 创建分区,详细如下图,分别创建4个分区, 输入<code>w</code>保存<ul><li><img src="https://drive.google.com/uc?export=view&id=1gzp4RPP4cy2p-jXw794bfTeYf5NsMQ3s" alt></li><li>最后分区结果如下: 其中 <code>/dev/sda1</code>代表<code>/</code>,<code>/dev/sda2</code>代表<code>/home</code>,<code>/dev/sda3</code>代表<code>/boot</code>,<code>/dev/sda4</code>代表<code>swap</code></li><li><img src="https://drive.google.com/uc?export=view&id=14wS7E084xrQNzBWMA8iM9UNH-nCsKiAs" alt></li></ul></li><li>(3.3) 修改分区类型,<code>/dev/sda1</code>和<code>/dev/sda2</code>不变,默认就好,<code>/dev/sda3</code>改成<code>UFI</code>,<code>/dev/sda4</code>改成<code>linux swap</code><ul><li>输入 <code>t</code>; 选择需要修改类型的分区编号; 输入<code>L</code>查看所有分区类型;选择需要的类型的编号; 确认; 输入<code>w</code>保存。</li><li><img src="https://drive.google.com/uc?export=view&id=1GXHIjz14aF-7jlJG-I2q3h0FQ7qi_all" alt></li></ul></li></ul></li><li><p>[4] 格式化分区</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">mkfs.ext4 /dev/sda1 <span class="comment"># / 格式化为 ext4</span></span><br><span class="line">mkfs.ext4 /dev/sda2 <span class="comment"># /home 格式化为 ext4</span></span><br><span class="line"></span><br><span class="line">mkfs.fat /dev/sda3 <span class="comment"># /boot 格式化为 EFI format</span></span><br><span class="line"></span><br><span class="line">mkswap /dev/sda4 <span class="comment"># 创建交换分区</span></span><br><span class="line">swapon /dev/sda4 <span class="comment"># 启用交换分区</span></span><br></pre></td></tr></table></figure></li><li><p>[5] 挂载分区</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">mount /dev/sda1 /mnt <span class="comment"># `/`分区挂载到`/mnt`</span></span><br><span class="line">mkdir /mnt/boot && mount /dev/sda3 /mnt/boot <span class="comment"># `/boot`分区挂载到`/mnt/boot`</span></span><br><span class="line">mkdir /mnt/home mount /dev/sda2 /mnt/home <span class="comment"># `/home`分区挂载到`/mnt/home`</span></span><br></pre></td></tr></table></figure></li></ul><h4 id="安装基础系统"><a href="#安装基础系统" class="headerlink" title="安装基础系统"></a>安装基础系统</h4><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">vim /etc/pacman.d/mirrorlist <span class="comment"># 修改源镜像,一般是不用动的,我这里就是默认的</span></span><br><span class="line"></span><br><span class="line">dhcpcd <span class="comment"># 检查网络,使用有线网络,我这里没有动,网络自动已经连接好了</span></span><br><span class="line"></span><br><span class="line">wifi-menu <span class="comment"># 使用无线网络</span></span><br><span class="line"></span><br><span class="line">ping www.baidu.com <span class="comment"># 检查是否可用</span></span><br><span class="line"></span><br><span class="line">pacstrap -i /mnt base base-devel dialog wpa_supplicant <span class="comment"># 安装基础系统,这个可能要花费一些时间,和网速有关</span></span><br><span class="line"></span><br><span class="line">genfstab -U /mnt >> /mnt/etc/fstab <span class="comment"># 生fstab文件</span></span><br><span class="line"></span><br><span class="line">cat /mnt/etc/fstab <span class="comment"># 查看上一部的fstab是否生效,这里可以看到,每一个分区的情况</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 对比**blkid**命令下硬盘分区UID和此文件是否对应,我这里就是因为没有mount好,生成的fstab也不对,导致安装完成无法启动</span></span><br></pre></td></tr></table></figure><h3 id="配置系统"><a href="#配置系统" class="headerlink" title="配置系统"></a>配置系统</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line">arch-chroot /mnt <span class="comment"># 进入系统</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime <span class="comment"># 修改时区</span></span><br><span class="line">hwclock --systohc <span class="comment"># 同步时间到硬件</span></span><br><span class="line"></span><br><span class="line">vi /etc/locale.gen <span class="comment"># 设置语言</span></span><br><span class="line"><span class="comment"># 我这里将这三个取消注释,这个需要根据自己的情况进行更改</span></span><br><span class="line">en_US.UTF-8 UTF-8</span><br><span class="line">zh_CN.UTF-8 UTF-8</span><br><span class="line">locale-gen <span class="comment"># 使刚才的修改生效</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="built_in">echo</span> <span class="string">'LANG=en_US.UTF-8'</span> > /etc/locale.conf</span><br><span class="line"><span class="comment"># 设置默认系统语言,建议设置成英文,中文的话可能会出现意想不到的问题,哈哈</span></span><br><span class="line"></span><br><span class="line">设置主机名称</span><br><span class="line"><span class="built_in">echo</span> <span class="string">'myhostname'</span> > /etc/hostname</span><br><span class="line"></span><br><span class="line">修改hosts</span><br><span class="line">/etc/hosts</span><br><span class="line">127.0.0.1 localhost</span><br><span class="line">::1 localhost</span><br><span class="line">127.0.1.1 myhostname.localdomain myhostname</span><br><span class="line"></span><br><span class="line">为root用户设置密码</span><br><span class="line">passwd</span><br><span class="line"></span><br><span class="line">设置dhcp自启动</span><br><span class="line">systemctl <span class="built_in">enable</span> dhcpcd</span><br></pre></td></tr></table></figure><h4 id="启动项"><a href="#启动项" class="headerlink" title="启动项"></a>启动项</h4><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">这里都是按照 UEFI 这种引导方式进行设置的</span><br><span class="line">pacman -S dosfstools grub efibootmgr</span><br><span class="line">grub-install --target=x86_64-efi --efi-directory=/boot --bootloader-id=grub</span><br><span class="line"><span class="comment"># /boot 这里保证是boot挂在分区的目录</span></span><br><span class="line">grub-mkconfig -o /boot/grub/grub.cfg</span><br></pre></td></tr></table></figure><h4 id="用户"><a href="#用户" class="headerlink" title="用户"></a>用户</h4><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">useradd -m -G wheel `username` <span class="comment"># 创建`username`并添加到wheel用户组</span></span><br><span class="line">passwd `username` <span class="comment"># 为`username`设置密码</span></span><br></pre></td></tr></table></figure><h4 id="sudo"><a href="#sudo" class="headerlink" title="sudo"></a>sudo</h4><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">pacman -S sudo vim <span class="comment"># 安装sudo包</span></span><br><span class="line">visudo <span class="comment"># 配置sudo</span></span><br><span class="line"><span class="comment"># 将这里取消注释,那以后非root用户,就可以用sudo的方式执行root命令</span></span><br><span class="line">%wheel ALL=(ALL)ALL</span><br></pre></td></tr></table></figure><h3 id="重启"><a href="#重启" class="headerlink" title="重启"></a>重启</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">exit</span> <span class="comment"># 退出chroot环境,用`exit`命令或者直接使用`Ctrl+d`快捷键</span></span><br><span class="line"></span><br><span class="line">umount -R /mnt <span class="comment"># 卸载分区</span></span><br><span class="line"></span><br><span class="line">shutdown -h now <span class="comment"># 关机,拔掉U盘,开机</span></span><br></pre></td></tr></table></figure><ul><li><p>配置virtualbox,因为我这里是用virtualbox安装的archlinxu,在第一次重启系统的时候,会进入EFI shell,并没有进入系统,这里要修改如下:</p><blockquote><p><img src="https://drive.google.com/uc?export=view&id=1JbhKYyY-isnwA-qsuMgpSeYksdl673Mo" alt><br><img src="https://drive.google.com/uc?export=view&id=1qBgHFilPxMwoR1ulaPTSnJlPuKch8up0" alt><br><img src="https://drive.google.com/uc?export=view&id=1prTLwyU3mKzXkRoQAaHHc_lULZ8W5o_T" alt></p></blockquote><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">fs0:</span><br><span class="line">edit startup.nsh</span><br><span class="line">\EFI\grub\grubx64.efi</span><br><span class="line">reset</span><br></pre></td></tr></table></figure></li><li><p>配置安装gnome</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">sudo pacman -S xf86-video-intel <span class="comment"># intel显卡驱动,如果是其它的需要安装对应的驱动</span></span><br><span class="line">sudo pacman -S xorg</span><br><span class="line">sudo pacman -S gnome gnome-extra gnome-tweak-tool</span><br><span class="line">sudo systemctl <span class="built_in">enable</span> gdm</span><br></pre></td></tr></table></figure></li><li><p>简单配置gnome安装常用软件<br>编辑 /etc/pacman.conf 文件,在文件末加入(源可以替换为更适合自己的)</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">[archlinuxcn]</span><br><span class="line">SigLevel = Optional TrustedOnly</span><br><span class="line">Server = http://mirrors.163.com/archlinux-cn/<span class="variable">$arch</span></span><br><span class="line"></span><br><span class="line">pacman -Syu && pacman -Sy archlinuxcn-keyring <span class="comment"># 更新</span></span><br><span class="line">pacman -S yaourt fakeroot <span class="comment"># 安装yaourt用于构建</span></span><br><span class="line"></span><br><span class="line">yaourt -S google-chrome wireshark-gtk vlc ffmpeg vim sublime-text-deve tcpdump</span><br><span class="line">yaourt -S fcitx fcitx-configtool fcitx-im fcitx-googlepinyin <span class="comment"># 中文输入法</span></span><br><span class="line"> > 在.bashrc中添加一下环境变量</span><br><span class="line"> > <span class="built_in">export</span> XMODIFIERS=<span class="string">"@im=fcitx"</span></span><br><span class="line"> > <span class="built_in">export</span> GTK_IM_MODULE=<span class="string">"fcitx"</span></span><br><span class="line"> > <span class="built_in">export</span> QT_IM_MODULE=<span class="string">"fcitx"</span></span><br><span class="line">yaourt -S noto-fonts-cjk <span class="comment"># 中文字体</span></span><br><span class="line">yaourt -S screenfetch <span class="comment"># 一个shell脚本</span></span><br></pre></td></tr></table></figure></li><li><p>最后放一张图,oh yeah!<br><img src="https://drive.google.com/uc?export=view&id=1s3kku_8TcZwSmtKnB18DeLNI0GfHzVyM" alt></p></li></ul><h3 id="后记"><a href="#后记" class="headerlink" title="后记"></a>后记</h3><p>感觉这个系统真的很适合我啊,决定以后开发环境都在这上面了,哈哈</p><h3 id="参考连接"><a href="#参考连接" class="headerlink" title="参考连接"></a>参考连接</h3><blockquote><p><a href="https://wiki.archlinux.org/index.php/Installation_guide" target="_blank" rel="noopener">https://wiki.archlinux.org/index.php/Installation_guide</a><br><a href="https://wiki.gentoo.org/wiki/Handbook:AMD64/Installation/Disks/zh-cn" target="_blank" rel="noopener">https://wiki.gentoo.org/wiki/Handbook:AMD64/Installation/Disks/zh-cn</a><br><a href="https://wiki.archlinux.org/index.php/GNOME" target="_blank" rel="noopener">https://wiki.archlinux.org/index.php/GNOME</a><br><a href="https://blog.tse.moe/archlinuxan-zhuang-zhuo-mian-he-chang-yong-ruan-jian/" target="_blank" rel="noopener">https://blog.tse.moe/archlinuxan-zhuang-zhuo-mian-he-chang-yong-ruan-jian/</a></p></blockquote><hr><p><strong>* 如有疑问欢迎批评指正,谢谢! *</strong></p>]]></content>
<summary type="html">
<p>之前一直对archlinux有很大的兴趣,期间也去尝试去安装,不过全部都失败了,最近又有时间,终于安装完成,并且安装了gnome桌面。感觉用的时候是非常好的。everything is simple。首先说一下现在装好,感觉最难的就是磁盘分区和格式化,选择什么样的分区方法,怎样分区。</p>
</summary>
<category term="arch" scheme="https://ytlm.github.io/categories/arch/"/>
<category term="arch" scheme="https://ytlm.github.io/tags/arch/"/>
</entry>
<entry>
<title>f-stack初探</title>
<link href="https://ytlm.github.io/2018/05/f-stack%E5%88%9D%E6%8E%A2/"/>
<id>https://ytlm.github.io/2018/05/f-stack初探/</id>
<published>2018-05-03T01:28:15.000Z</published>
<updated>2019-07-04T10:25:44.054Z</updated>
<content type="html"><![CDATA[<h3 id="介绍"><a href="#介绍" class="headerlink" title="介绍"></a>介绍</h3><p><a href="http://www.f-stack.org/" target="_blank" rel="noopener">f-stack</a>是基于<a href="https://dpdk.org" target="_blank" rel="noopener">DPDK</a>(Data Plante Development Kit)实现的一个用户态的协议栈;DPDK主要是操作系统内核数据平面,重载网卡驱动,减少内核中断,内存拷贝和上下文切换;在此之前Linux数据平面和控制平面混在一起,不适合处理大规模的网络数据包;f-stack是基于DPDK从FressBsd协议栈移植而来的用户态协议栈;详细解释何以看相关blog,论坛和官网文档;</p><a id="more"></a><h3 id="编译"><a href="#编译" class="headerlink" title="编译"></a>编译</h3><ul><li><p>环境</p><blockquote><ul><li>Linux centos 4.16.5-1.el7.elrepo.x86_64 #1 SMP Thu Apr 26 09:54:55 EDT 2018 x86_64 x86_64 x86_64 GNU/Linux</li><li>00:19.0 Ethernet controller: Intel Corporation Ethernet Connection (3) I218-LM (rev 03)</li></ul></blockquote></li><li><p>依赖</p><blockquote><p><code>yum install kernel-devel kernel-headers pciutils net-tools libpcap-devel numactl* gcc*</code><br>主要就是kernel-devel和kernel-headers安装kernel对应的版本</p></blockquote></li><li><p>编译</p><blockquote><ul><li><p>下载</p><blockquote><p>可以直接从<a href="https://github.com/F-Stack/f-stack" target="_blank" rel="noopener">github</a>上clone</p></blockquote></li><li><p>编译DPDK</p><blockquote><p>1),<code>cd f-stack/dpdk</code> # 进入dpdk文件夹<br>2),<code>make config T=x86_64-native-linuxapp-gcc</code> # 这里选择x86_64-native-linuxapp-gcc<br>3),<code>make</code> # 编译,这里可能会出现一些错误,基本都是kernel版本和dpdk版本不匹配造成的,可以搜索相关的patch</p></blockquote></li><li><p>编译f-stack</p><blockquote><p>1),设置环境变量 <code>export FF_PATH=/data/f-stack</code>和<code>export FF_DPDK=/data/f-stack/dpdk/x86_64-native-linuxapp-gcc</code> <code>FF_PATH</code>是f-stack所在的目录,<code>FF_DPDK</code>是dpdk编译好的目录<br>2),<code>cd f-stack/lib && make</code></p></blockquote></li><li><p>编译nginx</p><blockquote><p>1),<code>cd f-stack/app/nginx-1.11.10</code> # 进入f-stack中nginx的目录<br>2).<code>./configure --prefix=/data/nginx-fstack --with-ff_module && make && make install</code> # –prefix选择安装目录,–with-ff_module包含fstack nginx module</p></blockquote></li></ul></blockquote></li></ul><h3 id="配置"><a href="#配置" class="headerlink" title="配置"></a>配置</h3><p>1), 在配置之前要保存网卡的相关信息,包括ip地址,netmask子网掩码,gateway网关,broadcast广播地址</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 确认网卡名称,我这里是enp0s25</span></span><br><span class="line">myip=`ip addr show enp0s25 | grep inet | grep -v <span class="string">':'</span> | awk <span class="string">'{print $2}'</span> | awk -F <span class="string">'/'</span> <span class="string">'{print $1}'</span>`</span><br><span class="line">mybroadcast=`ip addr show enp0s25 | grep brd | grep -v <span class="string">':'</span> | awk <span class="string">'{print $4}'</span>`</span><br><span class="line">mynetmask=`ipcalc -m $(ip addr show enp0s25 | grep inet | grep -v <span class="string">":"</span> | awk <span class="string">'{print $2}'</span>) | awk -F <span class="string">'='</span> <span class="string">'{print $2}'</span>`</span><br><span class="line">mygateway=`route -n | grep 0.0.0.0 | grep enp0s25 | grep UG | awk -F <span class="string">' '</span> <span class="string">'{print $2}'</span>`</span><br><span class="line"></span><br><span class="line"><span class="comment"># 替换配置文件中的相关配置</span></span><br><span class="line">sed <span class="string">"s/addr=192.168.1.2/addr=<span class="variable">${myip}</span>/"</span> -i f-stack/config.ini</span><br><span class="line">sed <span class="string">"s/netmask=255.255.255.0/netmask=<span class="variable">${mynetmask}</span>/"</span> -i f-stack/config.ini</span><br><span class="line">sed <span class="string">"s/broadcast=192.168.1.255/broadcast=<span class="variable">${mybroadcast}</span>/"</span> -i f-stack/config.ini</span><br><span class="line">sed <span class="string">"s/gateway=192.168.1.1/gateway=<span class="variable">${mygateway}</span>/"</span> -i f-stack/config.ini</span><br></pre></td></tr></table></figure><p>2), 配置大页内存 set hugepage</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># single-node system</span></span><br><span class="line"><span class="built_in">echo</span> 1024 > /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages</span><br><span class="line"></span><br><span class="line"><span class="comment"># NUMA</span></span><br><span class="line"><span class="built_in">echo</span> 1024 > /sys/devices/system/node/node0/hugepages/hugepages-2048kB/nr_hugepages</span><br><span class="line"><span class="built_in">echo</span> 1024 > /sys/devices/system/node/node1/hugepages/hugepages-2048kB/nr_hugepages</span><br><span class="line"></span><br><span class="line">mkdir /mnt/huge</span><br><span class="line">mount -t hugetlbfs nodev /mnt/huge</span><br></pre></td></tr></table></figure><p>3), 安装DPDK驱动并绑定网卡</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 确保依赖,要不然安装的时候会出前错误,类似 unknow symbol in module</span></span><br><span class="line">modinfo f-stack/dpdk/x86_64-native-linuxapp-gcc/kmod/igb_uio.ko | grep depends</span><br><span class="line">modinfo f-stack/dpdk/x86_64-native-linuxapp-gcc/kmod/rte_kni.ko | grep depends</span><br><span class="line">modprobe uio <span class="comment"># 我这里只有uio一个</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 安装</span></span><br><span class="line">insmod f-stack/dpdk/x86_64-native-linuxapp-gcc/kmod/igb_uio.ko</span><br><span class="line">insmod f-stack/dpdk/x86_64-native-linuxapp-gcc/kmod/rte_kni.ko</span><br><span class="line"></span><br><span class="line">python f-stack/dpdk/tools/dpdk-devbind.py --status <span class="comment"># 用于查看设备的状态</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 绑定网卡</span></span><br><span class="line">ip link <span class="built_in">set</span> enp0s25 down <span class="comment"># 绑定之前需要处于非激活状态</span></span><br><span class="line">python f-stack/dpdk/tools/dpdk-devbind.py --<span class="built_in">bind</span>=igb_uio enp0s25</span><br></pre></td></tr></table></figure><h3 id="测试"><a href="#测试" class="headerlink" title="测试"></a>测试</h3><ul><li><p>启动</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cd</span> /data/nginx-fstack && ./sbin/nginx && ps -ef | grep nginx</span><br></pre></td></tr></table></figure></li><li><p>运行</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">curl -vo <span class="string">"http://192.168.55.177/"</span> <span class="comment"># 192.168.55.177是${myip},这里会看到nginx的响应,说名安装成功</span></span><br></pre></td></tr></table></figure></li></ul><h3 id="后记"><a href="#后记" class="headerlink" title="后记"></a>后记</h3><ul><li>一些DPDK的详细概念,和f-stack的详细配置,可以参看相关文档;</li><li>这些都是在自己的机器上做的,在其它的机器上可能有一些会不一样,本文仅作参考;</li><li>对于性能还没有来得及测试,后续有机器可以补上;</li></ul><h3 id="参考连接"><a href="#参考连接" class="headerlink" title="参考连接"></a>参考连接</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">https://dpdk.org/</span><br><span class="line">http://www.f-stack.org/</span><br><span class="line">https://github.com/F-Stack/f-stack</span><br><span class="line">https://www.jianshu.com/p/0ff8cb4deaef</span><br><span class="line">https://cloud.tencent.com/developer/column/1275</span><br></pre></td></tr></table></figure><hr><p><strong>* 如有疑问欢迎批评指正,谢谢! *</strong></p>]]></content>
<summary type="html">
<h3 id="介绍"><a href="#介绍" class="headerlink" title="介绍"></a>介绍</h3><p><a href="http://www.f-stack.org/" target="_blank" rel="noopener">f-stack</a>是基于<a href="https://dpdk.org" target="_blank" rel="noopener">DPDK</a>(Data Plante Development Kit)实现的一个用户态的协议栈;DPDK主要是操作系统内核数据平面,重载网卡驱动,减少内核中断,内存拷贝和上下文切换;在此之前Linux数据平面和控制平面混在一起,不适合处理大规模的网络数据包;f-stack是基于DPDK从FressBsd协议栈移植而来的用户态协议栈;详细解释何以看相关blog,论坛和官网文档;</p>
</summary>
<category term="dpdk" scheme="https://ytlm.github.io/categories/dpdk/"/>
<category term="f-stack" scheme="https://ytlm.github.io/tags/f-stack/"/>
<category term="nginx" scheme="https://ytlm.github.io/tags/nginx/"/>
<category term="dpdk" scheme="https://ytlm.github.io/tags/dpdk/"/>
</entry>
<entry>
<title>define中特殊符号的用法</title>
<link href="https://ytlm.github.io/2018/02/define%E4%B8%AD%E7%89%B9%E6%AE%8A%E7%AC%A6%E5%8F%B7%E7%9A%84%E7%94%A8%E6%B3%95/"/>
<id>https://ytlm.github.io/2018/02/define中特殊符号的用法/</id>
<published>2018-02-07T07:06:22.000Z</published>
<updated>2019-07-04T10:25:44.054Z</updated>
<content type="html"><![CDATA[<p>在C语言中宏定义#define 是一个很有用处的一个特性,在看其它一些源码的时候宏定义#define中会出现一些特殊的符号,主要有<code>#</code> <code>##</code> <code>do{}while(0)</code>,这里记录以下这几种特殊符号的含义和用法</p><a id="more"></a><p>1,<code>#</code> 字符串化操作符</p><blockquote><p>可以将宏定义中传入的参数转换成用一对双引号括起来的字符串</p></blockquote><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><stdio.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> STRING(str) #str</span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">(<span class="keyword">int</span> argv, <span class="keyword">char</span>* argc[])</span> </span>{</span><br><span class="line"> <span class="keyword">char</span>* str1 = STRING(test1);</span><br><span class="line"> <span class="keyword">char</span>* str2 = STRING( a bc e); <span class="comment">// 参数中间出现空格,会将连续的空格替换成一个</span></span><br><span class="line"></span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"str1 : %s\n"</span>, str1); <span class="comment">//结果 str1 : test1</span></span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"str2 : %s\n"</span>, str2); <span class="comment">//结果 str2 : a bc e</span></span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>2,<code>##</code>符号连接符</p><blockquote><p>将宏定义中的多个参数连结成一个参数</p></blockquote><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><stdio.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> CONCAT(n) t##n</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> PRINT(n) printf(<span class="meta-string">"t"</span> #n <span class="meta-string">" = %d\n"</span>, t ## n) <span class="comment">// `##` 前后空格可有可无</span></span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">(<span class="keyword">int</span> argv, <span class="keyword">char</span>* argc[])</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">int</span> <span class="title">CONCAT</span><span class="params">(<span class="number">1</span>)</span> </span>= <span class="number">10</span>; <span class="comment">// int t1 = 10;</span></span><br><span class="line"> <span class="function"><span class="keyword">int</span> <span class="title">CONCAT</span><span class="params">(<span class="number">2</span>)</span> </span>= <span class="number">20</span>; <span class="comment">// int t2 = 20;</span></span><br><span class="line"> PRINT(<span class="number">1</span>); <span class="comment">// printf("t1 = %d\n", t1);</span></span><br><span class="line"> PRINT(<span class="number">2</span>); <span class="comment">// printf("t2 = %d\n", t2);</span></span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>3,<code>do{}while(0)</code></p><ul><li><p>不需要do{}while(0)的情况</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">define</span> TEST(x) action1(x); \</span></span><br><span class="line"> action2(x);</span><br><span class="line"><span class="keyword">if</span> (<span class="literal">NULL</span> == p)</span><br><span class="line"> TEST(p);</span><br><span class="line"><span class="comment">// 在这种情况下会出现action1()会执行,action2()不会被执行的情况</span></span><br></pre></td></tr></table></figure></li><li><p>仅仅使用{}的情况</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">define</span> SWAP(x, y) {int tmp; tmp = x; x = y; y = tmp;}</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span>(x > y)</span><br><span class="line"> SWAP(x y);</span><br><span class="line"><span class="comment">//这种情况下编译直接报错了,因为多了一个`;`</span></span><br></pre></td></tr></table></figure></li></ul><hr><p><strong>* 如有疑问欢迎批评指正,谢谢! *</strong></p>]]></content>
<summary type="html">
<p>在C语言中宏定义#define 是一个很有用处的一个特性,在看其它一些源码的时候宏定义#define中会出现一些特殊的符号,主要有<code>#</code> <code>##</code> <code>do{}while(0)</code>,这里记录以下这几种特殊符号的含义和用法</p>
</summary>
<category term="C" scheme="https://ytlm.github.io/categories/C/"/>
<category term="C" scheme="https://ytlm.github.io/tags/C/"/>
<category term="define" scheme="https://ytlm.github.io/tags/define/"/>
</entry>
<entry>
<title>初识SystemTap</title>
<link href="https://ytlm.github.io/2017/12/%E5%88%9D%E8%AF%86SystemTap/"/>
<id>https://ytlm.github.io/2017/12/初识SystemTap/</id>
<published>2017-12-28T01:45:38.000Z</published>
<updated>2019-07-04T10:25:44.054Z</updated>
<content type="html"><![CDATA[<p>systemtap是一个诊断linux系统性能和功能问题的开源软件,并且允许开发人员编写和重用简单的脚本深入探查linux系统的活动,可以快速安全的提取过滤总结数据,以便能够诊断复杂的性能或功能问题。</p><a id="more"></a><h3 id="环境"><a href="#环境" class="headerlink" title="环境"></a>环境</h3><ul><li>Cenots 7.4.1708 Core</li><li>Kernel 3.10.0-693.11.1.el7.x86_64</li></ul><h3 id="安装"><a href="#安装" class="headerlink" title="安装"></a>安装</h3><ul><li>sudo yum install systemtap systemtap-runtime</li><li>sudo yum install kernel-devel-<code>uname -r</code> kernel-debuginfo-<code>uname -r</code></li><li>stap -v -e ‘probe vfs.read {printf(“Hello World\n”); exit()}’</li></ul><blockquote><p>在安装kernel-devel kernel-debuginfo 的时候一定要安装和kernel版本一致的版本,否则是没用的<br>还可以直接下载rpm包安装<a href="http://debuginfo.centos.org/" target="_blank" rel="noopener">地址</a><br>最后一个步骤是检查是否安装成功,如果正确的安装过后,会输出<code>Hello World</code></p></blockquote><h3 id="流程"><a href="#流程" class="headerlink" title="流程"></a>流程</h3><ul><li>基本思想是name events(命名事件),并给它们处理程序。每当事件发生的时候,linux内核运行处理程序,就像一个子程序一样,之后恢复。处理程序是一系列的脚本语言,用于指定事件完成时要完成的工作,这种工作通常包括是提取数据,打印结果等;</li><li>systemtap通过stap将脚本装换成C源代码,运行系统的时候创建一个内核模块,当模块加在的时候,它通过挂载到内核的钩子来激活所有的探测事件。最后,这次事件结束的时候,挂载的钩子断开连接执行清楚进程,移除模块,退出所有相关的程序;</li></ul><h3 id="语法"><a href="#语法" class="headerlink" title="语法"></a>语法</h3><p>从语法上来讲很多都是和C语言通用的,条件结构,顺序结构,循环结构,等等</p><h4 id="类型模式"><a href="#类型模式" class="headerlink" title="类型模式"></a>类型模式</h4><ul><li>begin;在脚本开始的时触发</li><li>end;在脚本结束时触发</li><li>kernel.function(“sys_sync”);在调用sys_sync时触发</li><li>kernel.function(“sys_sync”).call;在调用sys_sync时触发</li><li>kernel.function(“sys_sync”).return;在sys_sync返回时触发</li><li>kernel.syscall.* ;在进行任何系统调用时触发</li><li>kernel.function(“*@kernel/fork.c:934”);在执行到fork.c的第934行时触发</li><li>timer.ms(200);每隔200毫秒触发一次</li><li>timer.ms(200).randomize(50);每隔200毫秒触发一次,带有线性分布的随机附加时间(-50到+50)</li><li>timer.jiffies(1000);每隔1000个内核<a href="http://man7.org/linux/man-pages/man7/time.7.html" target="_blank" rel="noopener">jiffy</a>触发一次</li></ul><h3 id="例子"><a href="#例子" class="headerlink" title="例子"></a>例子</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">#!/usr/bin/env stap</span><br><span class="line">global syscalllist</span><br><span class="line">probe begin {</span><br><span class="line"> printf("start ... \n")</span><br><span class="line">}</span><br><span class="line">probe syscall.* {</span><br><span class="line"> syscalllist[pid(), execname()]++</span><br><span class="line">}</span><br><span class="line">probe timer.s(5) {</span><br><span class="line"> printf("-----------------------------\n")</span><br><span class="line"> foreach ( [pid, cname] in syscalllist ) {</span><br><span class="line"> printf("%s[%d] = %d\n", cname, pid, syscalllist[pid, cname])</span><br><span class="line"> }</span><br><span class="line"> delete syscalllist</span><br><span class="line"> exit()</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>begin 开始的时候会打印出”start … “<br>syscall.* 这里会统计所有的系统调用,并按照pid和name进程名称的方式存到syscalllist数组中<br>timer.s(5) 每隔5秒就会调用一次,这里遍历syscalllist数组,打印相关信息<br>这里只打印了当前5秒之内的系统调用,之后就exit()退出了<br>通过<code>stap call.stp</code>来执行call.stp这个脚本,下面是我这里运行的时候截取的一部分输出</p><blockquote><p>stapio[24669] = 93<br>EMT-1[8464] = 11181<br>EMT-0[8464] = 7126<br>Chrome_IOThread[3595] = 4852<br>Timer[8464] = 670<br>chrome[3595] = 11339<br>Chrome_ChildIOT[3818] = 2418<br>Compositor[3818] = 1500<br>chrome[4276] = 1624<br>nginx[21997] = 3<br>avahi-daemon[854] = 9888<br>VirtualBox[8464] = 423<br>X[1785] = 966<br>gnome-shell[2557] = 1373<br>VUsbPeriodFrm[8464] = 512<br>INTNET-RECV[8464] = 611</p></blockquote><h3 id="后记"><a href="#后记" class="headerlink" title="后记"></a>后记</h3><ul><li>这里只是简单的接触和学习了一下SystemTap,想要把这个用到实际的项目中还需要继续深入的研究和学习。</li></ul><h3 id="参考连接"><a href="#参考连接" class="headerlink" title="参考连接"></a>参考连接</h3><blockquote><p><a href="https://www.ibm.com/developerworks/cn/linux/l-systemtap/index.html" target="_blank" rel="noopener">https://www.ibm.com/developerworks/cn/linux/l-systemtap/index.html</a><br><a href="https://sourceware.org/systemtap/" target="_blank" rel="noopener">https://sourceware.org/systemtap/</a><br><a href="https://en.wikipedia.org/wiki/DTrace" target="_blank" rel="noopener">https://en.wikipedia.org/wiki/DTrace</a><br><a href="https://en.wikipedia.org/wiki/SystemTap" target="_blank" rel="noopener">https://en.wikipedia.org/wiki/SystemTap</a></p></blockquote><hr><p><strong>* 如有疑问欢迎批评指正,谢谢! *</strong></p>]]></content>
<summary type="html">
<p>systemtap是一个诊断linux系统性能和功能问题的开源软件,并且允许开发人员编写和重用简单的脚本深入探查linux系统的活动,可以快速安全的提取过滤总结数据,以便能够诊断复杂的性能或功能问题。</p>
</summary>
<category term="systemtap" scheme="https://ytlm.github.io/categories/systemtap/"/>
<category term="systemtap" scheme="https://ytlm.github.io/tags/systemtap/"/>
</entry>
<entry>
<title>centos安装配置mariadb</title>
<link href="https://ytlm.github.io/2017/12/centos%E5%AE%89%E8%A3%85%E9%85%8D%E7%BD%AEmariadb/"/>
<id>https://ytlm.github.io/2017/12/centos安装配置mariadb/</id>
<published>2017-12-28T01:44:42.000Z</published>
<updated>2019-07-04T10:25:44.054Z</updated>
<content type="html"><![CDATA[<p>这里简单介绍一下在centos环境下mariadb的安装和配置</p><a id="more"></a><h3 id="环境"><a href="#环境" class="headerlink" title="环境"></a>环境</h3><ul><li>CentOS 7.4.1708 Core</li><li>Kernel 3.10.0-693.11.1.el7.x86_64</li></ul><h3 id="安装"><a href="#安装" class="headerlink" title="安装"></a>安装</h3><p><code>sudo yum install mariadb mariadb-server</code></p><blockquote><p>这里可能需要安装epel扩展源<br>只需要一行命令,就是那么任性0.0</p></blockquote><h3 id="配置"><a href="#配置" class="headerlink" title="配置"></a>配置</h3><h4 id="命令"><a href="#命令" class="headerlink" title="命令"></a>命令</h4><ul><li><code>sudo systemctl start mariadb</code> 启动数据库</li><li><code>sudo systemctl enable</code> 开机自启</li><li><code>mysql -uroot -p'password'</code> 通过密码登陆</li><li><code>sudo systemctl restart mariadb</code> 重启数据库</li></ul><h4 id="初始配置"><a href="#初始配置" class="headerlink" title="初始配置"></a>初始配置</h4><p><code>mysql_secure_installation</code> 初始配置,这里要先启动数据库</p><blockquote><p>Enter current password for root (enter for none): “初始运行,没有密码,直接回车”<br>Set root password? [Y/n] “是否设置密码,这里需要设置密码所以输入y,然后回车”<br>New password: “输入密码”<br>Re-enter new password: “再次输入密码确认”<br>Remove anonymous users? [Y/n] “是否删除匿名用户,这里输入y,然后回车”<br>Disallow root login remotely? [Y/n] “是否禁止root远程登陆,因为可能需要远程登陆,所以这里输入n,然后回车”<br>Remove test database and access to it? [Y/n] “是否删除测试数据库,根据需要”<br>Reload privilege tables now? [Y/n] “是否重新加载权限,数据y,然后回车”<br>至此初始化配置已经完成,可以尝试登陆和学习</p></blockquote><h4 id="字符集配置"><a href="#字符集配置" class="headerlink" title="字符集配置"></a>字符集配置</h4><ul><li><p>打开 <code>/etc/my.cnf</code>,在[mysqld]下添加如下配置</p><blockquote><p>[mydqld]<br>init_connect=’SET collation_connection = utf8_unicode_ci’<br>init_connect=’SET NAMES utf8’<br>character-set-server=utf8<br>collation-server=utf8_unicode_ci<br>skip-character-set-client-handshake</p></blockquote></li><li><p>打开<code>/etc/my.cnf.d/client.cnf</code>,在[client]下添加如下配置</p><blockquote><p>[client]<br>default-character-set=utf8</p></blockquote></li><li><p>打开<code>/etc/my.cnf.d/mysql-clients.cnf</code>,在[mysql]下添加如下配置</p><blockquote><p>[mysql]<br>default-character-set=utf8</p></blockquote></li><li><p>重启数据库</p></li></ul><h3 id="权限配置"><a href="#权限配置" class="headerlink" title="权限配置"></a>权限配置</h3><ul><li><p>允许外网登陆</p><blockquote><p><code>grant all privileges on *.* to root@'%' identified by 'password';</code></p></blockquote></li><li><p>授权用户可以授权</p><blockquote><p><code>grant all privileges on *.* to root@'127.0.0.1' identified by 'password' with grant option;</code></p></blockquote></li><li><p>使这些配置生效,这里一定要执行</p><blockquote><p><code>flush privileges;</code></p></blockquote></li><li><p>外网登陆命令</p><blockquote><p><code>mysql -h 'ip' -u 'root' -P 3306 -p'password'</code><br>-h <code>ip</code>为远程数据库ip地址,<br>-P <code>3306</code>是数据库默认端口,<br>-u root 登陆用户名,<br>-p<code>password</code> 登陆用户对应的密码;</p><ul><li>外网登陆的时候可能会遇到防火墙的原因,导致连接失败,需要根据以下配置防火墙</li><li><code>iptables -A INPUT -p tcp -m state --state NEW -m tcp --dport 3306 -j ACCEPT</code></li><li><code>iptables-save > /etc/iptables/iptables.rules</code></li><li><code>systemctl reload iptables</code> || <code>iptables-restore < /etc/iptables/iptables.rules</code></li></ul></blockquote></li></ul><h3 id="后记"><a href="#后记" class="headerlink" title="后记"></a>后记</h3><ul><li>之前装过一次,在本地登陆进去之后,创建数据库的时候一直有权限错误,在搜索之后并没有得到解决,所以就把这些全部删除,尤其是要把之前的数据库删除,一般默认位置是在<code>/var/lib/mysql</code>目录下面,然后重新安装配置一遍就正常了,这里简单的记录一下以后有问题可以来此查看。</li></ul><hr><p><strong>* 如有疑问欢迎批评指正,谢谢! *</strong></p>]]></content>
<summary type="html">
<p>这里简单介绍一下在centos环境下mariadb的安装和配置</p>
</summary>
<category term="mariadb" scheme="https://ytlm.github.io/categories/mariadb/"/>
<category term="mariadb" scheme="https://ytlm.github.io/tags/mariadb/"/>
</entry>
<entry>
<title>lua学习之协程</title>
<link href="https://ytlm.github.io/2017/06/lua%E5%AD%A6%E4%B9%A0%E4%B9%8B%E5%8D%8F%E7%A8%8B/"/>
<id>https://ytlm.github.io/2017/06/lua学习之协程/</id>
<published>2017-06-27T03:01:27.000Z</published>
<updated>2019-07-04T10:25:44.054Z</updated>
<content type="html"><![CDATA[<p>lua中的另一个高级功能是coroutine(协程),协同式多线程的意思,不同于线程和进程,协程仅在显示的调用一个让出(yield)函数时才会挂起当前的执行,同一时间内只有一个协程正在运行,非抢占式的。</p><a id="more"></a><h3 id="api介绍"><a href="#api介绍" class="headerlink" title="api介绍"></a>api介绍</h3><blockquote><ul><li><code>coroutine.create( fun )</code> <strong>* 参数: *</strong> 是一个函数,是这个协程的主体函数。<strong>* 返回值: *</strong> 返回一个新的协程,类型为”thread”。<strong>* 作用: *</strong> 创建一个新的协程。</li><li><code>coroutine.yield( ... )</code> <strong>* 参数: *</strong> 任意变长参数。<strong>* 返回值: *</strong> 状态true或者false表示这个协程有没有挂起成功,然后返回传递的变长参数,全部返回给上次的coroutine.resume()调用。<strong>* 作用: *</strong> 挂起一个正在运行的协程,这个是有限制的,比如在调用C函数中和一些迭代器中是不能yield的。</li><li><code>coroutine.resume( co, ... )</code> <strong>* 参数: *</strong> 一个协程,通过coroutine.create()创建的,加上自定义参数,这些自定义参数都会传递给协程的主函数。<strong>*<br>返回值: *</strong> 一个boolean型的值表示有没有正确执行,之后的返回值都是coroutine.yield()中的参数。如果第一个值是false,后面的是错误信息。<strong>* 作用: *</strong> 运行一个协程直到函数执行完或者函数调用coroutine.yield()主动退出。</li><li><code>coroutine.wrap( fun )</code>,<strong>* 参数: *</strong> 一个函数。<strong>* 返回值: *</strong> 和coroutinue.resume()相同,只不过没有boolean变量。<strong>* 作用: *</strong> 和coroutine.create()相似,只不过返回的是一个函数,每次调用这个函数就继续执行这个协程。传递给这个函数的参数都将作为coroutine.resume()额外的参数。</li><li><code>coroutine.running( )</code> <strong>* 参数: *</strong> 无。<strong>* 返回值: *</strong> 返回正在运行的协程否则返回nil。</li><li><code>coroutine.status( co )</code> <strong>* 参数: *</strong> 一个协程。<strong>* 返回值: *</strong> 返回这个协程当前的状态,主要有,* running * 表示正在运行;* suspended * 表示没有运行或者yield让出的状态;* normal * 表示协程是活的,但是并不在运行(正在延续其它的协程);* dead * 表示协程执行完毕或者因错误停止。</li></ul></blockquote><h3 id="代码"><a href="#代码" class="headerlink" title="代码"></a>代码</h3><figure class="highlight lua"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">local</span> <span class="function"><span class="keyword">function</span> <span class="title">test</span><span class="params">(a)</span></span></span><br><span class="line"> <span class="built_in">print</span>(<span class="string">"test : "</span>, a)</span><br><span class="line"> <span class="keyword">return</span> coroutine.<span class="built_in">yield</span>(<span class="number">2</span> * a)</span><br><span class="line"><span class="keyword">end</span></span><br><span class="line"><span class="keyword">local</span> co = coroutine.<span class="built_in">create</span>( <span class="function"><span class="keyword">function</span><span class="params">(b, c)</span></span></span><br><span class="line"> <span class="built_in">print</span>(<span class="string">"running : "</span>, coroutine.<span class="built_in">running</span>())</span><br><span class="line"> <span class="built_in">print</span>(<span class="string">"co-body 1 : "</span>, b, c)</span><br><span class="line"> <span class="keyword">local</span> r = test(b + <span class="number">1</span>)</span><br><span class="line"> <span class="built_in">print</span>(<span class="string">"co-body 2 : "</span>, r)</span><br><span class="line"> <span class="keyword">local</span> n, m = coroutine.<span class="built_in">yield</span>(b - c, b + c)</span><br><span class="line"> <span class="built_in">print</span>(<span class="string">"co-body 3 : "</span>, n, m)</span><br><span class="line"> <span class="keyword">return</span> <span class="string">"begin"</span>, <span class="string">"end"</span></span><br><span class="line"><span class="keyword">end</span>)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">"test status 1 : "</span>, coroutine.<span class="built_in">status</span>(co))</span><br><span class="line"><span class="built_in">print</span>(<span class="string">"main 1 : "</span>, coroutine.<span class="built_in">resume</span>(co, <span class="number">1</span>, <span class="number">9</span>))</span><br><span class="line"><span class="built_in">print</span>(<span class="string">"main 2 : "</span>, coroutine.<span class="built_in">resume</span>(co, <span class="string">"r"</span>))</span><br><span class="line"><span class="built_in">print</span>(<span class="string">"main 3 : "</span>, coroutine.<span class="built_in">resume</span>(co, <span class="string">"n"</span>, <span class="string">"m"</span>))</span><br><span class="line"><span class="built_in">print</span>(<span class="string">"main 4 : "</span>, coroutine.<span class="built_in">resume</span>(co, <span class="string">"x"</span>, <span class="string">"y"</span>))</span><br><span class="line"><span class="built_in">print</span>(<span class="string">"test status 3 : "</span>, coroutine.<span class="built_in">status</span>(co))</span><br></pre></td></tr></table></figure><blockquote><p>结果如下</p></blockquote><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">test status 1 : suspended</span><br><span class="line">running : thread: 0x1e64df0</span><br><span class="line">co-body 1 : 1 9</span><br><span class="line">test : 2</span><br><span class="line">main 1 : true 4</span><br><span class="line">co-body 2 : r</span><br><span class="line">main 2 : true -8 10</span><br><span class="line">co-body 3 : n m</span><br><span class="line">main 3 : true begin end</span><br><span class="line">main 4 : false cannot resume dead coroutine</span><br><span class="line">test status 3 : dead</span><br></pre></td></tr></table></figure><p>结合上面的介绍和代码可以简单的理解各个函数的作用,并且对lua的协程有一个感性的认知。</p><h3 id="示例"><a href="#示例" class="headerlink" title="示例"></a>示例</h3><p>经典的生产者消费者问题,我们用lua协程的方式来实现一遍</p><figure class="highlight lua"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">local</span> <span class="function"><span class="keyword">function</span> <span class="title">send</span><span class="params">(p)</span></span></span><br><span class="line"> <span class="built_in">print</span>(<span class="string">"product send : "</span>, p)</span><br><span class="line"> coroutine.<span class="built_in">yield</span>(p)</span><br><span class="line"><span class="keyword">end</span></span><br><span class="line"><span class="keyword">local</span> product = coroutine.<span class="built_in">create</span>(<span class="function"><span class="keyword">function</span><span class="params">()</span></span></span><br><span class="line"> <span class="keyword">while</span>(<span class="literal">true</span>) <span class="keyword">do</span></span><br><span class="line"> <span class="keyword">local</span> p = <span class="built_in">io</span>.<span class="built_in">read</span>()</span><br><span class="line"> send(p)</span><br><span class="line"> <span class="keyword">end</span></span><br><span class="line"><span class="keyword">end</span>)</span><br><span class="line"><span class="keyword">local</span> <span class="function"><span class="keyword">function</span> <span class="title">receive</span><span class="params">(co)</span></span></span><br><span class="line"> <span class="keyword">local</span> ok, res = coroutine.<span class="built_in">resume</span>(co)</span><br><span class="line"> <span class="keyword">if</span> ok <span class="keyword">then</span></span><br><span class="line"> <span class="built_in">print</span>(<span class="string">"consumer received : "</span>, res)</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> <span class="built_in">print</span>(<span class="string">"consumer receive failed : "</span>, res)</span><br><span class="line"> <span class="keyword">end</span></span><br><span class="line"><span class="keyword">end</span></span><br><span class="line"><span class="keyword">local</span> <span class="function"><span class="keyword">function</span> <span class="title">consumer</span><span class="params">(co)</span></span></span><br><span class="line"> <span class="keyword">while</span> (<span class="literal">true</span>) <span class="keyword">do</span></span><br><span class="line"> receive(co)</span><br><span class="line"> <span class="keyword">end</span></span><br><span class="line"><span class="keyword">end</span></span><br><span class="line">consumer(product)</span><br></pre></td></tr></table></figure><blockquote><p>运行结果</p></blockquote><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">hello world</span><br><span class="line">product send : hello world</span><br><span class="line">consumer received : hello world</span><br><span class="line">1234567890</span><br><span class="line">product send : 1234567890</span><br><span class="line">consumer received : 1234567890</span><br><span class="line">1 + 1 = 2</span><br><span class="line">product send : 1 + 1 = 2</span><br><span class="line">consumer received : 1 + 1 = 2</span><br></pre></td></tr></table></figure><p>大致的解释一遍,程序会创建一个product协程,然后consumer函数调用recieve的时候会唤醒生产者协程主函数,主函数会把得到的值yield出去,这一步做了两个事情,一个是把得到的值返回给消费者,另一个是挂起自己,等待下次被激活。</p><h3 id="后记"><a href="#后记" class="headerlink" title="后记"></a>后记</h3><ul><li>通过lua的协程我们可以用同步的方式写出异步的程序。</li><li>当然本文只是简单的介绍lua的协程机制,具体到实际应用的话,还是会有很多变化的,<a href="https://github.com/pintsized/lua-resty-http" target="_blank" rel="noopener">lua-resty-http</a>是使用ngx_lua socket实现的一个http客户端,其中就有用到协程相关,有兴趣可以看看具体的实现。</li></ul><hr><p><strong>* 如有疑问欢迎批评指正,谢谢! *</strong></p>]]></content>
<summary type="html">
<p>lua中的另一个高级功能是coroutine(协程),协同式多线程的意思,不同于线程和进程,协程仅在显示的调用一个让出(yield)函数时才会挂起当前的执行,同一时间内只有一个协程正在运行,非抢占式的。</p>
</summary>
<category term="lua" scheme="https://ytlm.github.io/categories/lua/"/>
<category term="lua" scheme="https://ytlm.github.io/tags/lua/"/>
</entry>
<entry>
<title>lua学习之元表和元方法</title>
<link href="https://ytlm.github.io/2017/06/lua%E5%AD%A6%E4%B9%A0%E4%B9%8B%E5%85%83%E8%A1%A8%E5%92%8C%E5%85%83%E6%96%B9%E6%B3%95/"/>
<id>https://ytlm.github.io/2017/06/lua学习之元表和元方法/</id>
<published>2017-06-26T07:14:05.000Z</published>
<updated>2019-07-04T10:25:44.054Z</updated>
<content type="html"><![CDATA[<p>学习lua也有大概一年了,对lua的一些基本的语法很熟练了,也做了一些简单的业务,但是对于lua的高级特性还是不是很熟,最近有时间得以系统的学习学习。本文主要讲述的是lua高级特性之一的元表和元方法。</p><h3 id="文字简述"><a href="#文字简述" class="headerlink" title="文字简述"></a>文字简述</h3><ul><li><p>metatable(元表) 本质上来讲元表也是一个表,不过这个表是用来定义对lua的值进行自定义运算行为的地方。</p></li><li><p>metamethod(元方法) 本质上来讲就是一个lua函数,不过这个函数是用来绑定lua中特定的值,这些特定的值可以称为事件。这个函数我们可以进行我们一些自定义的操作。</p><blockquote><p>元表之中的事件其实是一些定义的值,这些值后面会讲到;<br>实际上我们只能对lua中table类型的值进行修改元表和元方法的操作,其它的一些例如number, string等都已经有自己内置的元表和元方法,且不可改变。</p></blockquote></li><li><p>通过元表和元方法,我们可以实现lua的面向对象编程。</p></li></ul><a id="more"></a><h3 id="代码讲解"><a href="#代码讲解" class="headerlink" title="代码讲解"></a>代码讲解</h3><h4 id="api-介绍"><a href="#api-介绍" class="headerlink" title="api 介绍"></a>api 介绍</h4><p>简单的介绍一下会用到的api。</p><blockquote><p><code>setmetatable(table, metatable)</code> 设置table的元表为metatable并且返回这个table。不能为除table类型之外的值设置元表,如果metatable为nil,则将指定的元表移除 。如果存在<code>__metatable</code>,则会抛出一个错误。<br><code>getmetatable(obj)</code> 返回一个类型的元表,如果没有元表返回nil。如果存在<code>__metatable</code>,则返回这个域的值。<br><code>rawget(table, index)</code> 在不触发任何元方法的情况下获取table中的值。也就是跳过元表和元方法。<br><code>rawset(table, index, value)</code> 在不触发任何元方法的情况下设置table[index]的值为value,index不能是nil和NaN</p></blockquote><h4 id="元方法介绍"><a href="#元方法介绍" class="headerlink" title="元方法介绍"></a>元方法介绍</h4><p>我们都知道对于两个number型的值,我们可以进行加,减,乘,除等的元算,但是对于table我们是不能直接进行这些预定义的运算的。但是通过通过元表和元方法我们是可以实现的;首先介绍下有哪些特定的值被用于绑定元方法,也称为事件,如下:</p><figure class="highlight lua"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">__index</span> <span class="comment">-- 用于取操作</span></span><br><span class="line"><span class="built_in">__newindex</span> <span class="comment">-- 用于赋值操作</span></span><br><span class="line"><span class="built_in">__metatable</span> <span class="comment">-- 限定元表操作</span></span><br><span class="line"><span class="built_in">__call</span> <span class="comment">-- 用于把一个函数当成函数调用的操作</span></span><br><span class="line"><span class="built_in">__add</span> <span class="comment">-- '+' 加</span></span><br><span class="line"><span class="built_in">__sub</span> <span class="comment">-- '-' 减</span></span><br><span class="line"><span class="built_in">__mul</span> <span class="comment">-- '*' 乘</span></span><br><span class="line"><span class="built_in">__div</span> <span class="comment">-- '/' 除</span></span><br><span class="line"><span class="built_in">__mod</span> <span class="comment">-- '%' 取余</span></span><br><span class="line"><span class="built_in">__pow</span> <span class="comment">-- '^' 次方</span></span><br><span class="line"><span class="built_in">__unm</span> <span class="comment">-- '-' 取反</span></span><br><span class="line"><span class="built_in">__concat</span> <span class="comment">-- '..' 连接</span></span><br><span class="line"><span class="built_in">__tostring</span> <span class="comment">-- 字符串序列话</span></span><br><span class="line"><span class="built_in">__len</span> <span class="comment">-- '#' 取长</span></span><br><span class="line"><span class="built_in">__eq</span> <span class="comment">-- '==’ 相等</span></span><br><span class="line"><span class="built_in">__lt</span> <span class="comment">-- '<' 小于</span></span><br><span class="line"><span class="built_in">__le</span> <span class="comment">-- '<=' 小于等于</span></span><br></pre></td></tr></table></figure><blockquote><p>对于不同的lua版本可能这些事件还有区别,具体详细的可以看lua对应版本的介绍,这里只列出了一些常用的。<br>对于一些特定的事件进行一些简单的介绍</p><blockquote><ul><li>__index 当我们在取一个table中的不存在这个index的值的时候,如果有元表的话,会触发这个操作,会到元表中进行查询,并且返回这个值,元表中月不存在的时候返回nil。</li><li>__newindex 当我们对一个table中的一个不存在的index赋值的时候,如果有元表的话,会触发这个操作,如果元表中有定义这个行为,就按照这个进行。</li><li>__metatable 使用这个元方法的时候是保护元表,进值对元表中的成员进行获取或者修改</li><li>__call 使用这个的时候我们可以吧table当成函数来进行调用。</li></ul></blockquote></blockquote><h4 id="代码分析"><a href="#代码分析" class="headerlink" title="代码分析"></a>代码分析</h4><h5 id="简单的元方法"><a href="#简单的元方法" class="headerlink" title="简单的元方法"></a>简单的元方法</h5><figure class="highlight lua"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">local</span> t1 = {<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>}</span><br><span class="line"><span class="keyword">local</span> t2 = {<span class="number">5</span>, <span class="number">6</span>, <span class="number">7</span>, <span class="number">9</span>}</span><br><span class="line"><span class="keyword">local</span> t = {</span><br><span class="line"> <span class="built_in">__add</span> = <span class="function"><span class="keyword">function</span><span class="params">(a, b)</span></span></span><br><span class="line"> <span class="keyword">local</span> tmp = {}</span><br><span class="line"> <span class="keyword">for</span> i = <span class="number">1</span>, #a <span class="keyword">do</span></span><br><span class="line"> tmp[i] = a[i] + b[i]</span><br><span class="line"> <span class="keyword">end</span></span><br><span class="line"> <span class="keyword">for</span> i = #tmp + <span class="number">1</span>, #b <span class="keyword">do</span></span><br><span class="line"> tmp[i] = b[i]</span><br><span class="line"> <span class="keyword">end</span></span><br><span class="line"> <span class="keyword">return</span> tmp</span><br><span class="line"> <span class="keyword">end</span>,</span><br><span class="line"> <span class="built_in">__tostring</span> = <span class="function"><span class="keyword">function</span><span class="params">(a)</span></span></span><br><span class="line"> <span class="keyword">local</span> str = <span class="string">""</span></span><br><span class="line"> <span class="keyword">local</span> split = <span class="string">""</span></span><br><span class="line"> <span class="keyword">for</span> i = <span class="number">1</span>, #a <span class="keyword">do</span></span><br><span class="line"> str = str .. split .. a[i]</span><br><span class="line"> split = <span class="string">"|"</span></span><br><span class="line"> <span class="keyword">end</span></span><br><span class="line"> <span class="keyword">return</span> str</span><br><span class="line"> <span class="keyword">end</span></span><br><span class="line">}</span><br><span class="line"><span class="built_in">setmetatable</span>(t1, t)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">"t1 : "</span>, t1)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">"t2 : "</span>, t2)</span><br><span class="line"><span class="keyword">local</span> tmp = t1 + t2</span><br><span class="line"><span class="built_in">print</span>(<span class="string">"tmp : "</span>, tmp)</span><br><span class="line"><span class="built_in">setmetatable</span>(t2, t)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">" - t2 : "</span>, t2)</span><br><span class="line"><span class="built_in">setmetatable</span>(tmp, t)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">" - tmp : "</span>, tmp)</span><br></pre></td></tr></table></figure><blockquote><p>运行结果如下</p></blockquote><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">t1 : 1|2|3</span><br><span class="line">t2 : table: 0x16984f0</span><br><span class="line">tmp : table: 0x16981c0</span><br><span class="line"> - t2 : 5|6|7|9</span><br><span class="line"> - tmp : 6|8|10|9</span><br></pre></td></tr></table></figure><blockquote><p>当对两个table进行加(+)的操作的时候,会查找元表中对应的元方法,然后按照元方法的行为去做。其它的一些算术运算都和这个例子大同小异,就不多做介绍了。</p></blockquote><h5 id="index"><a href="#index" class="headerlink" title="__index"></a>__index</h5><figure class="highlight lua"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">local</span> t1 = {}</span><br><span class="line"><span class="keyword">local</span> t2 = {}</span><br><span class="line">t2.a = <span class="number">10</span></span><br><span class="line"><span class="built_in">setmetatable</span>(t1, {<span class="built_in">__index</span> = t2})</span><br><span class="line"><span class="built_in">print</span>(t1.a)</span><br></pre></td></tr></table></figure><blockquote><p>运行结果如下</p></blockquote><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">10</span><br></pre></td></tr></table></figure><blockquote><p>当访问t1中的a的时候,t1中并没有这个值,但是t1有元表,则会到元表中查询a,并返回;<br>__index 也可以是一个函数,用于自定义的一些行为。</p></blockquote><h5 id="newindex"><a href="#newindex" class="headerlink" title="__newindex"></a>__newindex</h5><figure class="highlight lua"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">local</span> t1 = {}</span><br><span class="line">t1.c = <span class="number">30</span></span><br><span class="line"><span class="keyword">local</span> t2 = {}</span><br><span class="line">t2.a = <span class="number">10</span></span><br><span class="line">t2.b = <span class="number">20</span></span><br><span class="line"><span class="built_in">setmetatable</span>(t1, {<span class="built_in">__newindex</span> = t2})</span><br><span class="line"><span class="built_in">print</span>(t1.a)</span><br><span class="line"><span class="built_in">print</span>(t2.a)</span><br><span class="line">t1.a = <span class="string">"a10"</span></span><br><span class="line"><span class="built_in">print</span>(t1.a)</span><br><span class="line"><span class="built_in">print</span>(t2.a)</span><br><span class="line"><span class="built_in">print</span>(t1.c)</span><br><span class="line">t1.c = <span class="string">"c10"</span></span><br><span class="line"><span class="built_in">print</span>(t1.c)</span><br><span class="line"><span class="built_in">print</span>(t2.c)</span><br></pre></td></tr></table></figure><blockquote><p>运行结果如下</p></blockquote><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">nil</span><br><span class="line">10</span><br><span class="line">nil</span><br><span class="line">a10</span><br><span class="line">30</span><br><span class="line">c10</span><br><span class="line">nil</span><br></pre></td></tr></table></figure><blockquote><p>在对t1中的变量进行赋值的时候,如果存在则直接进行赋值,如果不存在则触发__newindex,设置元表中对应的值</p></blockquote><h5 id="metatable"><a href="#metatable" class="headerlink" title="__metatable"></a>__metatable</h5><figure class="highlight lua"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">local</span> t1 = {}</span><br><span class="line"><span class="keyword">local</span> t = {}</span><br><span class="line"><span class="built_in">setmetatable</span>(t1, t)</span><br><span class="line"><span class="built_in">print</span>(<span class="built_in">getmetatable</span>(t1))</span><br><span class="line">t.<span class="built_in">__metatable</span> = <span class="string">"lock"</span></span><br><span class="line"><span class="built_in">print</span>(<span class="string">" metatable : "</span>, <span class="built_in">getmetatable</span>(t1))</span><br><span class="line"><span class="built_in">setmetatable</span>(t1, t)</span><br></pre></td></tr></table></figure><blockquote><p>运行结果如下</p></blockquote><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">table: 0xe7f4f0</span><br><span class="line"> metatable : lock</span><br><span class="line">lua: test.lua:11: cannot change a protected metatable</span><br></pre></td></tr></table></figure><blockquote><p>在设置完__metatable域的时候,就不能再对元表进行操作了,会报错。</p></blockquote><h5 id="call"><a href="#call" class="headerlink" title="__call"></a>__call</h5><figure class="highlight lua"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">local</span> t1 = {}</span><br><span class="line"><span class="built_in">setmetatable</span>(t1, {</span><br><span class="line"> <span class="built_in">__call</span> = <span class="function"><span class="keyword">function</span><span class="params">(t, a, b, c, ...)</span></span></span><br><span class="line"> <span class="keyword">local</span> num = a + b + c</span><br><span class="line"> <span class="built_in">print</span>(<span class="string">"__call str : "</span>, num)</span><br><span class="line"> <span class="keyword">end</span></span><br><span class="line">})</span><br><span class="line">t1(<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>)</span><br></pre></td></tr></table></figure><blockquote><p>运行结果如下</p></blockquote><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">__call str : 6</span><br></pre></td></tr></table></figure><blockquote><p>t1作为table,但是可以直接当成函数来进行调用,会查找__call元方法</p></blockquote><h5 id="rawget"><a href="#rawget" class="headerlink" title="rawget"></a>rawget</h5><figure class="highlight lua"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">local</span> t1 = {}</span><br><span class="line"><span class="keyword">local</span> t2 = {}</span><br><span class="line">t2.a = <span class="number">20</span></span><br><span class="line"><span class="built_in">setmetatable</span>(t1, {<span class="built_in">__index</span> = t2})</span><br><span class="line"><span class="built_in">print</span>(<span class="string">"t1 a : "</span>, t1.a)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">"rawget t1 a : "</span>, <span class="built_in">rawget</span>(t1,a))</span><br></pre></td></tr></table></figure><blockquote><p>运行结果如下</p></blockquote><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">t1 a : 20</span><br><span class="line">rawget t1 a : nil</span><br></pre></td></tr></table></figure><blockquote><p>设置完元表后可以取到t1中的a,从元表t2中,但是用rawget的时候会会忽略元表的存在</p></blockquote><h5 id="rawset"><a href="#rawset" class="headerlink" title="rawset"></a>rawset</h5><figure class="highlight lua"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">local</span> t1 = {}</span><br><span class="line"><span class="keyword">local</span> t2 = {}</span><br><span class="line">t2.a = <span class="number">20</span></span><br><span class="line"><span class="built_in">setmetatable</span>(t1, {<span class="built_in">__newindex</span> = t2})</span><br><span class="line">t1.b = <span class="string">"bbb"</span></span><br><span class="line"><span class="built_in">print</span>(<span class="string">"t1 b : "</span>, t1.b)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">"t2 b : "</span>, t2.b)</span><br><span class="line"><span class="built_in">rawset</span>(t1, b, <span class="string">"ccc"</span>)</span><br></pre></td></tr></table></figure><blockquote><p>运行结果如下</p></blockquote><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">t1 b : nil</span><br><span class="line">t2 b : bbb</span><br><span class="line">lua: table index is nil</span><br></pre></td></tr></table></figure><blockquote><p>正常的设置完元表并且设置__newindex域之后,对t1中的不存在的b赋值的时候会触发__newindex操作,但是如果用rawset的话就会报错,rawset(t1, b, “ccc”),会对t1中的b进行赋值,并不会触发__newindex,而t1中也没有b这个值,所以报错了。</p></blockquote><h5 id="系统代码"><a href="#系统代码" class="headerlink" title="系统代码"></a>系统代码</h5><p>以一个之前写的例子结束这篇介绍</p><figure class="highlight lua"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">--[[</span></span><br><span class="line"><span class="comment"> lua 5.1.5</span></span><br><span class="line"><span class="comment"> socket 2.0.2</span></span><br><span class="line"><span class="comment">]]</span><span class="comment">--</span></span><br><span class="line"><span class="keyword">local</span> socket = <span class="built_in">require</span>(<span class="string">"socket"</span>)</span><br><span class="line"><span class="keyword">local</span> <span class="built_in">sub</span> = <span class="built_in">string</span>.<span class="built_in">sub</span></span><br><span class="line"><span class="keyword">local</span> <span class="built_in">byte</span> = <span class="built_in">string</span>.<span class="built_in">byte</span></span><br><span class="line"><span class="keyword">local</span> <span class="built_in">concat</span> = <span class="built_in">table</span>.<span class="built_in">concat</span></span><br><span class="line"><span class="keyword">local</span> <span class="built_in">tonumber</span> = <span class="built_in">tonumber</span></span><br><span class="line"><span class="keyword">local</span> <span class="built_in">tostring</span> = <span class="built_in">tostring</span></span><br><span class="line"><span class="keyword">local</span> _M = {</span><br><span class="line"> <span class="built_in">_VERSION</span> = <span class="string">"0.1"</span>,</span><br><span class="line">}</span><br><span class="line"><span class="keyword">local</span> mt = { <span class="built_in">__index</span> = _M }</span><br><span class="line"><span class="function"><span class="keyword">function</span> _M.new<span class="params">(self)</span></span></span><br><span class="line"> <span class="keyword">local</span> sock, err = socket.tcp()</span><br><span class="line"> <span class="keyword">if</span> <span class="keyword">not</span> sock <span class="keyword">then</span></span><br><span class="line"> <span class="keyword">return</span> <span class="literal">nil</span>, err</span><br><span class="line"> <span class="keyword">end</span></span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">setmetatable</span>({_sock = sock, _subscribed = <span class="literal">false</span> }, mt)</span><br><span class="line"><span class="keyword">end</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> _M.connect<span class="params">(self, ...)</span></span></span><br><span class="line"> <span class="keyword">local</span> args = {...}</span><br><span class="line"> <span class="keyword">local</span> sock = <span class="built_in">rawget</span>(self, <span class="string">"_sock"</span>)</span><br><span class="line"> <span class="keyword">if</span> <span class="keyword">not</span> sock <span class="keyword">then</span></span><br><span class="line"> <span class="keyword">return</span> <span class="literal">nil</span>, <span class="string">"not initialized"</span></span><br><span class="line"> <span class="keyword">end</span></span><br><span class="line"> self._subscribed = <span class="literal">false</span></span><br><span class="line"> <span class="keyword">return</span> sock:connect(...)</span><br><span class="line"><span class="keyword">end</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> _M.close<span class="params">(self)</span></span></span><br><span class="line"> <span class="keyword">local</span> sock = <span class="built_in">rawget</span>(self, <span class="string">"_sock"</span>)</span><br><span class="line"> <span class="keyword">if</span> <span class="keyword">not</span> sock <span class="keyword">then</span></span><br><span class="line"> <span class="keyword">return</span> <span class="literal">nil</span>, <span class="string">"not initialized"</span></span><br><span class="line"> <span class="keyword">end</span></span><br><span class="line"> <span class="keyword">return</span> sock:<span class="built_in">close</span>()</span><br><span class="line"><span class="keyword">end</span></span><br><span class="line"><span class="keyword">local</span> <span class="function"><span class="keyword">function</span> _gen_req<span class="params">(args)</span></span></span><br><span class="line"> <span class="keyword">local</span> nargs = #args</span><br><span class="line"> <span class="keyword">local</span> req = <span class="string">""</span></span><br><span class="line"> req = req .. <span class="string">"*"</span> .. nargs .. <span class="string">"\r\n"</span></span><br><span class="line"> <span class="keyword">for</span> i = <span class="number">1</span>, nargs <span class="keyword">do</span></span><br><span class="line"> <span class="keyword">local</span> <span class="built_in">arg</span> = args[i]</span><br><span class="line"> <span class="keyword">if</span> <span class="built_in">type</span>(<span class="built_in">arg</span>) ~= <span class="string">"string"</span> <span class="keyword">then</span> <span class="built_in">arg</span> = <span class="built_in">tostring</span>(<span class="built_in">arg</span>) <span class="keyword">end</span></span><br><span class="line"> req = req .. <span class="string">"$"</span></span><br><span class="line"> req = req .. #<span class="built_in">arg</span></span><br><span class="line"> req = req .. <span class="string">"\r\n"</span></span><br><span class="line"> req = req .. <span class="built_in">arg</span></span><br><span class="line"> req = req .. <span class="string">"\r\n"</span></span><br><span class="line"> <span class="keyword">end</span></span><br><span class="line"><span class="comment">-- print("req : ", req)</span></span><br><span class="line"> <span class="keyword">return</span> req</span><br><span class="line"><span class="keyword">end</span></span><br><span class="line"><span class="keyword">local</span> <span class="function"><span class="keyword">function</span> _read_reply<span class="params">(self, sock)</span></span></span><br><span class="line"> <span class="keyword">local</span> line, err = sock:receive()</span><br><span class="line"> <span class="keyword">if</span> <span class="keyword">not</span> line <span class="keyword">then</span></span><br><span class="line"> <span class="keyword">if</span> err == <span class="string">"timeout"</span> <span class="keyword">then</span></span><br><span class="line"> sock:<span class="built_in">close</span>()</span><br><span class="line"> <span class="keyword">end</span></span><br><span class="line"> <span class="keyword">return</span> <span class="literal">nil</span>, err</span><br><span class="line"> <span class="keyword">end</span></span><br><span class="line"> <span class="keyword">local</span> prefix = <span class="built_in">byte</span>(line)</span><br><span class="line"> <span class="keyword">if</span> prefix == <span class="number">42</span> <span class="keyword">then</span> <span class="comment">-- char "*"</span></span><br><span class="line"> <span class="keyword">local</span> n = <span class="built_in">tonumber</span>(<span class="built_in">sub</span>(line, <span class="number">2</span>))</span><br><span class="line"> <span class="keyword">if</span> n < <span class="number">0</span> <span class="keyword">then</span> <span class="keyword">return</span> <span class="literal">nil</span> <span class="keyword">end</span></span><br><span class="line"> <span class="keyword">local</span> vals = {}</span><br><span class="line"> <span class="keyword">local</span> ind = <span class="number">1</span></span><br><span class="line"> <span class="keyword">for</span> i = <span class="number">1</span>, n <span class="keyword">do</span></span><br><span class="line"> <span class="keyword">local</span> res, err = _read_reply(self, sock)</span><br><span class="line"> <span class="keyword">if</span> res <span class="keyword">then</span></span><br><span class="line"> vals[ind] = res</span><br><span class="line"> ind = ind + <span class="number">1</span></span><br><span class="line"> <span class="keyword">elseif</span> <span class="keyword">not</span> res <span class="keyword">then</span></span><br><span class="line"> <span class="keyword">return</span> <span class="literal">nil</span>, err</span><br><span class="line"> <span class="keyword">end</span></span><br><span class="line"> <span class="keyword">end</span></span><br><span class="line"> <span class="keyword">return</span> vals</span><br><span class="line"> <span class="keyword">elseif</span> prefix == <span class="number">36</span> <span class="keyword">then</span> <span class="comment">-- char "$"</span></span><br><span class="line"> <span class="keyword">local</span> size = <span class="built_in">tonumber</span>(<span class="built_in">sub</span>(line, <span class="number">2</span>))</span><br><span class="line"> <span class="keyword">if</span> size < <span class="number">0</span> <span class="keyword">then</span> <span class="keyword">return</span> <span class="literal">nil</span>, <span class="built_in">sub</span>(line, <span class="number">2</span>) <span class="keyword">end</span></span><br><span class="line"> <span class="keyword">local</span> data, err = sock:receive(size)</span><br><span class="line"> <span class="keyword">if</span> <span class="keyword">not</span> data <span class="keyword">then</span></span><br><span class="line"> <span class="keyword">if</span> err == <span class="string">"timeout"</span> <span class="keyword">then</span></span><br><span class="line"> sock:<span class="built_in">close</span>()</span><br><span class="line"> <span class="keyword">end</span></span><br><span class="line"> <span class="keyword">return</span> <span class="literal">nil</span>, err</span><br><span class="line"> <span class="keyword">end</span></span><br><span class="line"> <span class="keyword">local</span> crlf, err = sock:receive(<span class="number">2</span>)</span><br><span class="line"> <span class="keyword">if</span> <span class="keyword">not</span> crlf <span class="keyword">then</span> <span class="keyword">return</span> <span class="literal">nil</span>, err <span class="keyword">end</span></span><br><span class="line"> <span class="keyword">return</span> data</span><br><span class="line"> <span class="keyword">elseif</span> prefix == <span class="number">45</span> <span class="keyword">then</span> <span class="comment">-- char "-"</span></span><br><span class="line"> <span class="keyword">return</span> <span class="literal">nil</span>, <span class="built_in">sub</span>(line, <span class="number">2</span>)</span><br><span class="line"> <span class="keyword">elseif</span> prefix == <span class="number">43</span> <span class="keyword">then</span> <span class="comment">-- char "+"</span></span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">sub</span>(line, <span class="number">2</span>)</span><br><span class="line"> <span class="keyword">elseif</span> prefix == <span class="number">58</span> <span class="keyword">then</span> <span class="comment">-- char ":"</span></span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">tonumber</span>(<span class="built_in">sub</span>(line, <span class="number">2</span>))</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> <span class="keyword">return</span> <span class="literal">nil</span>, <span class="string">"unknow prefix : \""</span> .. <span class="built_in">tostring</span>(prefix) .. <span class="string">"\""</span></span><br><span class="line"> <span class="keyword">end</span></span><br><span class="line"><span class="keyword">end</span></span><br><span class="line"><span class="keyword">local</span> <span class="function"><span class="keyword">function</span> _do_cmd<span class="params">(self, ...)</span></span></span><br><span class="line"> <span class="keyword">local</span> args = {...}</span><br><span class="line"> <span class="keyword">local</span> sock = <span class="built_in">rawget</span>(self, <span class="string">"_sock"</span>)</span><br><span class="line"> <span class="keyword">if</span> <span class="keyword">not</span> sock <span class="keyword">then</span></span><br><span class="line"> <span class="keyword">return</span> <span class="literal">nil</span>, <span class="string">"not initialized"</span></span><br><span class="line"> <span class="keyword">end</span></span><br><span class="line"> <span class="keyword">local</span> req = _gen_req(args)</span><br><span class="line"> <span class="keyword">local</span> bytes, err = sock:send(req)</span><br><span class="line"> <span class="keyword">if</span> <span class="keyword">not</span> bytes <span class="keyword">then</span></span><br><span class="line"> <span class="keyword">return</span> <span class="literal">nil</span>, err</span><br><span class="line"> <span class="keyword">end</span></span><br><span class="line"> <span class="keyword">return</span> _read_reply(self, sock)</span><br><span class="line"><span class="keyword">end</span></span><br><span class="line"><span class="built_in">setmetatable</span>( _M, { <span class="built_in">__index</span> = <span class="function"><span class="keyword">function</span><span class="params">(self, cmd)</span></span></span><br><span class="line"> <span class="keyword">local</span> method = <span class="function"><span class="keyword">function</span> <span class="params">(self, ...)</span></span></span><br><span class="line"> <span class="keyword">return</span> _do_cmd(self, cmd, ...)</span><br><span class="line"> <span class="keyword">end</span></span><br><span class="line"> _M[cmd] = method</span><br><span class="line"> <span class="keyword">return</span> method</span><br><span class="line"><span class="keyword">end</span>})</span><br><span class="line"><span class="keyword">return</span> _M</span><br></pre></td></tr></table></figure><blockquote><p>这是仿照lua-resty-redis,用luasocket实现的一个简单的lua redis客户端。<br>每次用的时候需要 require这个文件,并且调用new,设置相应元表,之后就可以进行简单的redis操作了。</p></blockquote><h3 id="后记"><a href="#后记" class="headerlink" title="后记"></a>后记</h3><blockquote><ul><li>本文代码部分比较多,尽可能的用代码来解释lua中元表和元方法的一些用法,如果理解起来还是不清楚可以查看lua官方文档,也可以联系我。</li></ul></blockquote><hr><p><strong>* 如有疑问欢迎批评指正,谢谢! *</strong></p>]]></content>
<summary type="html">
<p>学习lua也有大概一年了,对lua的一些基本的语法很熟练了,也做了一些简单的业务,但是对于lua的高级特性还是不是很熟,最近有时间得以系统的学习学习。本文主要讲述的是lua高级特性之一的元表和元方法。</p>
<h3 id="文字简述"><a href="#文字简述" class="headerlink" title="文字简述"></a>文字简述</h3><ul>
<li><p>metatable(元表) 本质上来讲元表也是一个表,不过这个表是用来定义对lua的值进行自定义运算行为的地方。</p>
</li>
<li><p>metamethod(元方法) 本质上来讲就是一个lua函数,不过这个函数是用来绑定lua中特定的值,这些特定的值可以称为事件。这个函数我们可以进行我们一些自定义的操作。</p>
<blockquote>
<p>元表之中的事件其实是一些定义的值,这些值后面会讲到;<br>实际上我们只能对lua中table类型的值进行修改元表和元方法的操作,其它的一些例如number, string等都已经有自己内置的元表和元方法,且不可改变。</p>
</blockquote>
</li>
<li><p>通过元表和元方法,我们可以实现lua的面向对象编程。</p>
</li>
</ul>
</summary>
<category term="lua" scheme="https://ytlm.github.io/categories/lua/"/>
<category term="lua" scheme="https://ytlm.github.io/tags/lua/"/>
</entry>
<entry>
<title>tcp建立连接为什么需要三次握手</title>
<link href="https://ytlm.github.io/2017/05/tcp%E5%BB%BA%E7%AB%8B%E8%BF%9E%E6%8E%A5%E4%B8%BA%E4%BB%80%E4%B9%88%E9%9C%80%E8%A6%81%E4%B8%89%E6%AC%A1%E6%8F%A1%E6%89%8B/"/>
<id>https://ytlm.github.io/2017/05/tcp建立连接为什么需要三次握手/</id>
<published>2017-05-03T01:22:40.000Z</published>
<updated>2019-07-04T10:25:44.054Z</updated>
<content type="html"><![CDATA[<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><ul><li>众所周知tcp传输层协议在建立连接的时候需要三次才能建立起一个真正的可靠连接,可是为什么是三次呢,不可以是两次,四次等等呢,可以自己思考一番,带着疑问可以看下文。</li></ul><h2 id="三次握手"><a href="#三次握手" class="headerlink" title="三次握手"></a>三次握手</h2><ul><li>在《计算机网络》一书中其中有提到,三次握手的目的是“为了防止已经失效的连接请求报文段突然又传到服务端,因而产生错误”,这种情况是:一端(client)A发出去的第一个连接请求报文并没有丢失,而是因为某些未知的原因在某个网络节点上发生滞留,导致延迟到连接释放以后的某个时间才到达另一端(server)B。本来这是一个早已失效的报文段,但是B收到此失效的报文之后,会误认为是A再次发出的一个新的连接请求,于是B端就向A又发出确认报文,表示同意建立连接。如果不采用“三次握手”,那么只要B端发出确认报文就会认为新的连接已经建立了,但是A端并没有发出建立连接的请求,因此不会去向B端发送数据,B端没有收到数据就会一直等待,这样B端就会白白浪费掉很多资源。如果采用“三次握手”的话就不会出现这种情况,B端收到一个过时失效的报文段之后,向A端发出确认,此时A并没有要求建立连接,所以就不会向B端发送确认,这个时候B端也能够知道连接没有建立。</li></ul><a id="more"></a><ul><li><p>问题的本质是,信道是不可靠的,但是我们要建立可靠的连接发送可靠的数据,也就是数据传输是需要可靠的。在这个时候三次握手是一个理论上的最小值,并不是说是tcp协议要求的,而是为了满足在不可靠的信道上传输可靠的数据所要求的。</p></li><li><p>我们再来考虑,如果不是三次握手会出现什么情况呢:</p><blockquote><p>假设有A和B两端要进行通信,<br>1, 第一次:首先A发送一个(SYN)到B,意思是A要和B建立连接进行通信;</p><blockquote><p>如果是只有一次握手的话,这样肯定是不行的,A压根都不知道B是不是收到了这个请求。</p></blockquote><p>2, 第二次:B收到A要建立连接的请求之后,发送一个确认(SYN+ACK)给A,意思是收到A的消息了,B这里也是通的,表示可以建立连接;</p><blockquote><p>如果只有两次通信的话,这时候B不确定A是否收到了确认消息,有可能这个确认消息由于某些原因丢了。</p></blockquote><p>3, 第三次:A如果收到了B的确认消息之后,再发出一个确认(ACK)消息,意思是告诉B,这边是通的,然后A和B就可以建立连接相互通信了;</p><blockquote><p>这个时候经过了三次握手,A和B双方确认了两边都是通的,可以相互通信了,已经可以建立一个可靠的连接,并且可以相互发送数据。<br>4, 第四次:这个时候已经不需要B再发送一个确认消息了,两边已经通过前三次建立了一个可靠的连接,如果再发送第四次确认消息的话,就浪费资源了。</p></blockquote><blockquote><p>如果第二个报文段B发出的(SYN+ACK)分别发送的话,也是可以理解为四次,但是被优化了,一起发送了。</p></blockquote></blockquote></li><li><p>超时重传机制,</p><blockquote><p>(1) 如果第一个包,A发送给B请求建立连接的报文(SYN)如果丢掉了,A会周期性的超时重传,直到B发出确认(SYN+ACK);<br>(2) 如果第二个包,B发送给A的确认报文(SYN+ACK)如果丢掉了,B会周期性的超时重传,直到A发出确认(ACK);<br>(3) 如果第三个包,A发送给B的确认报文(ACK)如果丢掉了,</p><blockquote><ul><li>A在发送完确认报文之后,单方面会进入ESTABLISHED的状态,B还是SYN_RCVD状态</li><li>如果此时双方都没有数据需要发送,B会周期性的超时发送(SYN+ACK),直到收到A的确认报文(ACK),此时B也进入ESTABLISHED状态,双方可以发送数据;</li><li>如果A有数据发送,A发送的是(ACK+DATA),B会在收到这个数据包的时候自动切换到ESTABLISHED状态,并接受数据(DATA);</li><li>如果这个时候B要发送数据,B是发送不了数据的,会周期性的超时重传(SYN+ACK)直到收到A的确认(ACK)B才能发送数据。</li></ul></blockquote></blockquote></li><li><p>三次握手牵扯到的状态转换</p><blockquote><ul><li>** LISTEN ** 表示socket已经处于listen状态了,可以建立连接;</li><li>** SYN_SENT ** 表示socket在发出connect连接的时候,会首先发送SYN报文,然后等待另一端发送的确认报文(ACK),表示这端已经发送完SYN报文了;</li><li>** SYN_RCVD ** 表示一端已经接收到SYN报文了;</li><li>** ESTABLISHED ** 表示已经建立连接了,可以发送数据了。</li></ul></blockquote><p> <img src="https://drive.google.com/uc?export=view&id=1Nozi6I30L5bS8b-ebQia7HOPjuAqdLPU" alt="三次握手状态装换图解"></p></li></ul><h2 id="四次挥手"><a href="#四次挥手" class="headerlink" title="四次挥手"></a>四次挥手</h2><ul><li><p>说完TCP建立连接的时候为什么是三次,相对的就会想到为什么断开连接的时候是需要四次呢,而不是三次,五次等等呢;</p></li><li><p>本质的原因是tcp是全双公的,要实现可靠的连接关闭,A发出结束报文FIN,收到B确认后A知道自己没有数据需要发送了,B知道A不再发送数据了,自己也不会接收数据了,但是此时A还是可以接收数据,B也可以发送数据;当B发出FIN报文的时候此时两边才会真正的断开连接,读写分开。</p></li><li><p>四次挥手牵扯到的状态装换</p><blockquote><ul><li>** FIN_WAIT_1 ** 表示在等待另一方的FIN报文,和FIN_WAIT_2的区别是,FIN_WAIT_1表示socket现在要主动关闭连接,在发送完FIN报文后socket进入FIN_WAIT_1状态,当收到另一方发送FIN的ACK之后立即进入FIN_WAIT_2状态;</li><li>** FIN_WAIT_2 ** 同上,此时需要做的事情是可能还会接收数据,然后等待另一方的FIN;</li><li>** TIME_WAIT ** 存在主动关闭的一方,表示收到了对方的FIN报文,并发送出了ACK报文,就等2MSL(Max Segment Lifetime))后即可回到CLOSED可用状态了,需要等一段时间时原因是网络是不可靠的,不能保证这个ACK发送成功了,如果失败了,对端会超时重传FIN;</li><li>** CLOSING ** 表示在发送FIN之后,没有收到对方的ACK,而是收到了对方的FIN,这中情况很少见,只有在两端几乎同时关闭同一个socket的时候才会出现CLOSING状态;</li><li>** CLOSE_WAIT ** 表示收到对方的FIN之后,回给对方ACK,此时处于CLOSE_WAIT状态,等待关闭,要看自己是否还有数据要发送;</li><li>** LAST_ACK ** 表示收到对方的FIN之后,回给对方ACK,然后自己也要关闭发送FIN,等待另一方的ACK时候的状态;</li><li>** CLOSED ** 这个状态表示连接已经断开。</li></ul></blockquote><p> <img src="https://drive.google.com/uc?export=view&id=1U31A0a2cdh531BHzpprbh72XDJpchy_j" alt="四次挥手状态装换图解"></p></li><li><p>最后放一张状态转换图<br> <img src="https://drive.google.com/uc?export=view&id=1PzEZ4PpUy5U6w9Uor6dbL1XdFFYZvxV2" alt="三次握手和四次挥手状态转换图"></p></li></ul><h2 id="后记"><a href="#后记" class="headerlink" title="后记"></a>后记</h2><ul><li>在状态转换图中省略了数据的发送;</li><li>对于tcp/ip的学习还需要努力,可能文中有些表达不够严谨,还望海涵。</li></ul><hr><p><strong>* 如有疑问欢迎批评指正,谢谢! *</strong></p>]]></content>
<summary type="html">
<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><ul>
<li>众所周知tcp传输层协议在建立连接的时候需要三次才能建立起一个真正的可靠连接,可是为什么是三次呢,不可以是两次,四次等等呢,可以自己思考一番,带着疑问可以看下文。</li>
</ul>
<h2 id="三次握手"><a href="#三次握手" class="headerlink" title="三次握手"></a>三次握手</h2><ul>
<li>在《计算机网络》一书中其中有提到,三次握手的目的是“为了防止已经失效的连接请求报文段突然又传到服务端,因而产生错误”,这种情况是:一端(client)A发出去的第一个连接请求报文并没有丢失,而是因为某些未知的原因在某个网络节点上发生滞留,导致延迟到连接释放以后的某个时间才到达另一端(server)B。本来这是一个早已失效的报文段,但是B收到此失效的报文之后,会误认为是A再次发出的一个新的连接请求,于是B端就向A又发出确认报文,表示同意建立连接。如果不采用“三次握手”,那么只要B端发出确认报文就会认为新的连接已经建立了,但是A端并没有发出建立连接的请求,因此不会去向B端发送数据,B端没有收到数据就会一直等待,这样B端就会白白浪费掉很多资源。如果采用“三次握手”的话就不会出现这种情况,B端收到一个过时失效的报文段之后,向A端发出确认,此时A并没有要求建立连接,所以就不会向B端发送确认,这个时候B端也能够知道连接没有建立。</li>
</ul>
</summary>
<category term="学习" scheme="https://ytlm.github.io/categories/%E5%AD%A6%E4%B9%A0/"/>
<category term="网络协议" scheme="https://ytlm.github.io/tags/%E7%BD%91%E7%BB%9C%E5%8D%8F%E8%AE%AE/"/>
</entry>
<entry>
<title>安装systemmap生成openresty的火焰图</title>
<link href="https://ytlm.github.io/2017/04/%E5%AE%89%E8%A3%85systemtap%E7%94%9F%E6%88%90openresty%E7%9A%84%E7%81%AB%E7%84%B0%E5%9B%BE/"/>
<id>https://ytlm.github.io/2017/04/安装systemtap生成openresty的火焰图/</id>
<published>2017-04-27T10:50:32.000Z</published>
<updated>2019-07-04T10:25:44.054Z</updated>
<content type="html"><![CDATA[<h2 id="SystemTap"><a href="#SystemTap" class="headerlink" title="SystemTap"></a>SystemTap</h2><h3 id="简单介绍"><a href="#简单介绍" class="headerlink" title="简单介绍"></a>简单介绍</h3><ul><li><a href="https://sourceware.org/systemtap/" target="_blank" rel="noopener">systemtap</a>是一个诊断linux系统性能和功能问题的开源软件,并且允许开发人员编写和重用简单的脚本深入探查linux系统的活动,可以快速安全的提取过滤总结数据,以便能够诊断复杂的性能或功能问题。</li><li>基本思想是name events(命名事件),并给它们处理程序。每当事件发生的时候,linux内核运行处理程序,就像一个子程序一样,之后恢复。处理程序是一系列的脚本语言,用于指定事件完成时要完成的工作,这种工作通常包括是提取数据,打印结果等。</li><li>systemtap通过将脚本装换成C,运行系统的时候创建一个内核模块,当模块加在的时候,它通过挂载到内核的钩子来激活所有的探测事件。最后,这次事件结束的时候,挂载的钩子断开连接,移除模块。</li></ul><a id="more"></a><blockquote><p>systemtap工具功能很强大,目前刚接触,在此仅仅通过<a href="https://sourceware.org/systemtap/tutorial/Introduction.html" target="_blank" rel="noopener">官网</a>做一些简单的介绍。</p></blockquote><h3 id="安装"><a href="#安装" class="headerlink" title="安装"></a>安装</h3><ul><li>环境 centos 7,直接用<code>yum install systemtap systemtap-runtime</code>安装,如果遇到依赖包的问题,安装所需要的依赖就好了;</li><li>另外需要注意一个重要的问题是需要安装kernel-debuginfo和kernel-debuginfo-common;可以直接用yum安装也可以<a href="http://debuginfo.centos.org/" target="_blank" rel="noopener">下载rpm</a>包安装;但是 ** 必须要和kernel版本一样 **</li><li>安装完成后可以用<code>stap -v -e 'probe vfs.read {printf("read performed\n"); exit()}'</code>测试,如果不出意外的话会正常输出的</li></ul><blockquote><p>表示在这里被坑了好久,全部安装好后运行的时候一直报错,累。。。</p></blockquote><h2 id="Openresty"><a href="#Openresty" class="headerlink" title="Openresty"></a>Openresty</h2><h3 id="介绍"><a href="#介绍" class="headerlink" title="介绍"></a>介绍</h3><ul><li><a href="http://openresty.org/" target="_blank" rel="noopener">OpenResty</a>是一个动态的基于nginx和lua的网络平台。把nginx和lua集成在一起,可以通过lua完成一些复杂的需求,而不用再去开发C层面的module了,同时性能也很理想。</li></ul><blockquote><ul><li>目前应该直接集成<a href="http://luajit.org/" target="_blank" rel="noopener">LuaJIT</a>了,简单来说LuaJIT是lua的一个更高性能的版本。</li></ul></blockquote><h3 id="安装-1"><a href="#安装-1" class="headerlink" title="安装"></a>安装</h3><ul><li>直接到官网下载源码进行编译安装就行了,如果遇到一些依赖,就直接安装依赖就行了。</li></ul><blockquote><p>目前在做nginx的相关工作,所以对openresty了解的比较多一点,如有兴趣,欢迎共同交流。</p></blockquote><h2 id="火焰图"><a href="#火焰图" class="headerlink" title="火焰图"></a>火焰图</h2><h3 id="介绍-1"><a href="#介绍-1" class="headerlink" title="介绍"></a>介绍</h3><ul><li><a href="https://github.com/brendangregg/FlameGraph" target="_blank" rel="noopener">火焰图(Flame Graphs)</a>是一个通过可视话堆栈的方法,可以直观的看出每个函数占用cpu的时间,内存,off-cpu等等,对于我们排查软件问题很有帮助。</li><li>显示的是,Y轴是堆栈的深度,X轴是样本数量。每个样本(函数)是一个矩形。鼠标点击可以看到一些详细的信息。通过这些可以看出那些需要调整优化。</li></ul><blockquote><p>对于火焰图也是最近才了解到的,有些解释可能很牵强,误怪,后面会慢慢的了解学习的。</p></blockquote><h3 id="生成"><a href="#生成" class="headerlink" title="生成"></a>生成</h3><ul><li>openresty提供了一套完整的<a href="https://github.com/openresty/openresty-systemtap-toolkit" target="_blank" rel="noopener">工具</a>用于探测运行的状况。可以直接下载并根据介绍运行。</li><li>然后下载<a href="https://github.com/brendangregg/FlameGraph" target="_blank" rel="noopener">FlameGraph</a>火焰图生成工具,用于把前面采样到的信息绘制成火焰图。</li><li>然后在浏览器中打开进行观察分析。</li></ul><blockquote><p>在采样信息的时候需要让nginx在压力很大的情况下,这样得出的结果才会有更大的参考性。</p></blockquote><h3 id="分析火焰图"><a href="#分析火焰图" class="headerlink" title="分析火焰图"></a>分析火焰图</h3><ul><li>采样C层面的信息进行分析</li></ul><blockquote><ol><li>sudo ./sample-bt -p 15507 -t 60 -u -a ‘-DMAXACTION=100000’ > /tmp/nginx.bt<blockquote><p>-p 表示nginx的worker的pid<br>-t 表示采样时间<br>-u 表示在用户空间<br>-a 传递一些参数,因为我自己的机器的原因所以需要传递这个参数,要不然会报错的</p></blockquote></li><li>sudo ./stackcollapse-stap.pl /tmp/nginx.bt > /tmp/nginx.cbt</li><li>sudo ./flamegraph.pl /tmp/nginx.cbt > /tmp/nginx.svg</li><li>用浏览器打开/tmp/nginx.svg</li></ol></blockquote><p><img src="https://drive.google.com/uc?export=view&id=1WxAEn4a10UGygSMhyc8sSQHgt4nwWg6c" alt="openresty C层面的火焰图"></p><blockquote><p>我用wrk给nginx的压力还不是很大大概CPU才20%左右,所以这个不是很准确的;但是也可以看出一些问题,比如看出在发送数据的时候还是有问题的,都在body_filter阶段,可能因为我用了很多的buffer的原因</p></blockquote><ul><li>采样lua层面的信息进行分析,在编译luaJIT的时候需要添加<code>CCDEBUG=-g</code>参数</li></ul><blockquote><ol><li>sudo ./ngx-sample-lua-bt -a ‘-DMAXACTION=100000’ -p 4790 –luajit20 -t 60 > /tmp/lua.bt<blockquote><p>各个参数的意思和上面的一样。</p></blockquote></li><li>sudo ./fix-lua-bt /tmp/lua.bt > /tmp/lua-fix.bt</li><li>sudo ./stackcollapse-stap.pl /tmp/lua-fix.bt > /tmp/lua-fix.cbt</li><li>sudo ./flamegraph.pl /tmp/lua-fix.cbt > /tmp/lua-fix.svg</li><li>浏览器打开/tmp/lua-fix.svg<br>图的话在这里就不再贴出来了</li></ol></blockquote><h2 id="后记"><a href="#后记" class="headerlink" title="后记"></a>后记</h2><ul><li>上面用<code>sample-bt</code>生成的是on-cpu的相关数据,也可以用<code>sample-bt-off-cpu</code>生成off-cpu的相关分析数据,具体的区别可以到相关网站进行详细的了解;</li><li>首先呢,这个火焰图是一个很好的分析工具,相信可以为我们再排查问题的时候提供很大的帮助,目前我也是刚接触这个工具,还在慢慢摸索学习当中;</li><li>另外一个就是在安装遇到过很多的坑,也相当无语,但是都通过google慢慢的一个一个解决了,要有一颗永不放弃的心不是吗;</li></ul><hr><p><strong>* 如有疑问欢迎批评指正,谢谢! *</strong></p>]]></content>
<summary type="html">
<h2 id="SystemTap"><a href="#SystemTap" class="headerlink" title="SystemTap"></a>SystemTap</h2><h3 id="简单介绍"><a href="#简单介绍" class="headerlink" title="简单介绍"></a>简单介绍</h3><ul>
<li><a href="https://sourceware.org/systemtap/" target="_blank" rel="noopener">systemtap</a>是一个诊断linux系统性能和功能问题的开源软件,并且允许开发人员编写和重用简单的脚本深入探查linux系统的活动,可以快速安全的提取过滤总结数据,以便能够诊断复杂的性能或功能问题。</li>
<li>基本思想是name events(命名事件),并给它们处理程序。每当事件发生的时候,linux内核运行处理程序,就像一个子程序一样,之后恢复。处理程序是一系列的脚本语言,用于指定事件完成时要完成的工作,这种工作通常包括是提取数据,打印结果等。</li>
<li>systemtap通过将脚本装换成C,运行系统的时候创建一个内核模块,当模块加在的时候,它通过挂载到内核的钩子来激活所有的探测事件。最后,这次事件结束的时候,挂载的钩子断开连接,移除模块。</li>
</ul>
</summary>
<category term="nginx" scheme="https://ytlm.github.io/categories/nginx/"/>
<category term="nginx" scheme="https://ytlm.github.io/tags/nginx/"/>
<category term="openresty" scheme="https://ytlm.github.io/tags/openresty/"/>
<category term="systemmap" scheme="https://ytlm.github.io/tags/systemmap/"/>
<category term="linux" scheme="https://ytlm.github.io/tags/linux/"/>
</entry>
<entry>
<title>关于nginx缓存配置指令用法详解</title>
<link href="https://ytlm.github.io/2017/04/%E5%85%B3%E4%BA%8Enginx%E7%BC%93%E5%AD%98%E9%85%8D%E7%BD%AE%E6%8C%87%E4%BB%A4%E7%94%A8%E6%B3%95%E8%AF%A6%E8%A7%A3/"/>
<id>https://ytlm.github.io/2017/04/关于nginx缓存配置指令用法详解/</id>
<published>2017-04-18T02:53:11.000Z</published>
<updated>2019-07-04T10:25:44.054Z</updated>
<content type="html"><![CDATA[<h2 id="nginx简介"><a href="#nginx简介" class="headerlink" title="nginx简介"></a>nginx简介</h2><p>众所周知nginx近些年在服务器领域占据着很重要的作用,目前我主要接触的关于nginx是作为代理服务器来用的,至于再详细的,有兴趣的可以查阅相关文档<a href="http://nginx.org/" target="_blank" rel="noopener">nginx</a>,就不在这里赘述。本文主要讲述的是把nginx配置成一个缓存服务器组件来用,尽可能详细的把nginx关于缓存的指令解释清楚。</p><a id="more"></a><h2 id="配置指令详解"><a href="#配置指令详解" class="headerlink" title="配置指令详解"></a>配置指令详解</h2><ul><li><p><strong>* proxy_buffering *</strong> on | off</p><blockquote><ul><li>控制着缓存的总开关,如果设置off缓存就不会生效;设置on缓存相关的配置才会生效;</li><li>缓存的开关也可以通过设置”X-Accel-Bufferinf”这个header为”yes” | “no”来控制;</li><li>“X-Accel-Buffering”这个header可以被proxy_ingore_headers指令忽略;</li></ul></blockquote></li><li><p><strong>* proxy_cache *</strong> <em>zone</em> | off</p><blockquote><ul><li>定义一个共享内存用于缓存,其中主要存一些缓存文件的主要信息,用于检索;</li><li>同一个共享内存可以被用于不同的地方,* zone *可以支持配置变量;</li><li>off 的意思是禁用从上层继承的缓存配置;</li></ul></blockquote></li><li><p><strong>* proxy_cache_background_update *</strong> on | off</p><blockquote><ul><li>允许在后台发送子请求来更新过期的缓存文件;</li><li>这个一般都不常用,一般一个请求过来判断一下缓存时间,如果 过期了再从后端取就行了;</li></ul></blockquote></li><li><p><strong>* proxy_cache_bypass *</strong> string …</p><blockquote><ul><li>如果配置的字符串传中有一个不为空并且不等于”0”,这时候这个请求的相应就不会从缓存中取,应该到后端去取数据;</li></ul></blockquote></li><li><p><strong>* proxy_no_cache *</strong> string …</p><blockquote><ul><li>如果响应的数据中有任何一个满足让字符串中的值至少有一个不为空并且不等于”0”,那么这个响应就不会被缓存下来;</li></ul></blockquote></li><li><p><strong>* proxy_cache_key *</strong> string</p><blockquote><ul><li>配置缓存的key,缓存相关的内容都是根据这个key来进行查找的;</li><li>key的配置很有灵活性,不同的配置可以达到不同的效果;</li></ul></blockquote></li><li><p><strong>* proxy_cache_lock *</strong> on | off</p><blockquote><ul><li>设置为on的时候,表示在同一时间如果请求同一个cache key的多个请求在没有缓存的情况下只有一个请求会通过后端取数据,其它的请求直接取上个请求的缓存,或者等到超时,直接也去后端去取数据;</li></ul></blockquote></li><li><p><strong>* proxy_cache_lock_timeout *</strong> time</p><blockquote><ul><li>这个超时时间就是上面的超时时间,如果proxy_cache_lock打开的时候,同一时间同一资源只有一个请求会到后端取数据,其它的请求如果达到这个超时时间之后也会直接到后端取数据;</li><li>过了超时时间之后去到后端取下来数据不会缓存下来;</li></ul></blockquote></li><li><p><strong>* proxy_cache_lock_age *</strong> time</p><blockquote><ul><li>这个的意思是在time时间内一个请求还没有将数据完全从后端取下来并且缓存,那么下一个请求就会被发送到后端,并且这时候也要把数据缓存下来;</li><li>这个lock age和上个lock timeout一直没有搞清楚根本的区别,这里只是简单的解释一下,我好像用的也不多,如果谁能够解释一下还望不吝赐教,谢谢0.0;</li></ul></blockquote></li><li><p><strong>* proxy_cache_methods *</strong> GET | HEAD | POST …</p><blockquote><ul><li>如果客户端请求的方法在这个配置的方法列表中,这个请求才有可能被缓存,缓存还受其它的条件制约;</li></ul></blockquote></li><li><p><strong>* proxy_cache_path *</strong> path [一堆的可选参数]</p><blockquote><ul><li>proxy_cache_path /data/nginx/cachet levels=1:2 use_temp_path=off keys_zone=data:60m inactive=365d max_size=10m;</li><li>上面是一个典型的配置,下面来解释一下每个的含义 :<blockquote><ul><li>/data/nginx/cachet : 这个表示缓存文件实际的存储路径;</li><li>levels=1:2 : 这个表示缓存文件的分级存储,如果不这样设置的话所有的文件都在同一个文件夹下面,看着比较乱,如果配成这样,缓存文件在实际上大概像这样 <strong>* /data/nginx/cache/c/29/b7f54b2df7773722d382f4809d65029c *</strong>;</li><li>ues_temp_path=off : 禁用缓存响应到临时目录,直接缓存到缓存目录;</li><li>keys_zone=data:60m : 设置一个共享内存和大小,里面存储的是缓存文件的一些key信息,在测试的时候发现1m的共享内存大概能够存8k左右个key;</li><li>inactive=365d : 设置缓存时间,这个也受其它的条件限制,比如说响应头有Cache-Control: max-age=10,这样只能缓存10s;</li><li>max_size=10m; 设置这个缓存目录的总大小,大小要根据配置的共享内存进行合理的配置;如果超过这个大小会通过LRU算法进行淘汰;</li></ul></blockquote></li></ul></blockquote></li><li><p><strong>* proxy_cache_valid *</strong> [code … ] time</p><blockquote><ul><li>设置特定的响应状态码缓存特定的时间;</li></ul></blockquote></li></ul><h2 id="后记"><a href="#后记" class="headerlink" title="后记"></a>后记</h2><ul><li>上面就是我平常用到的关于nginx缓存的配置,组合起来还是能够达到很多需求的;</li><li>这里只是介绍我平常接触到很多的指令,还可能有一些我没有接触过的关于缓存的配置指令,欢迎补充;</li><li>另外在配置缓存目录的时候通过proxy_cache_path和proxy_cahce配置多个来达到把不同的缓存存储到不同的目录,这个时候就涉及到负载均衡了,要不然不同的目录缓存的大小不一样;</li></ul><h2 id="参考链接"><a href="#参考链接" class="headerlink" title="参考链接"></a>参考链接</h2><blockquote><p><a href="http://nginx.org/en/docs/http/ngx_http_proxy_module.html" target="_blank" rel="noopener">http://nginx.org/en/docs/http/ngx_http_proxy_module.html</a></p></blockquote><hr><p><strong>* 如有疑问欢迎批评指正,谢谢! *</strong></p>]]></content>
<summary type="html">
<h2 id="nginx简介"><a href="#nginx简介" class="headerlink" title="nginx简介"></a>nginx简介</h2><p>众所周知nginx近些年在服务器领域占据着很重要的作用,目前我主要接触的关于nginx是作为代理服务器来用的,至于再详细的,有兴趣的可以查阅相关文档<a href="http://nginx.org/" target="_blank" rel="noopener">nginx</a>,就不在这里赘述。本文主要讲述的是把nginx配置成一个缓存服务器组件来用,尽可能详细的把nginx关于缓存的指令解释清楚。</p>
</summary>
<category term="nginx" scheme="https://ytlm.github.io/categories/nginx/"/>
<category term="nginx" scheme="https://ytlm.github.io/tags/nginx/"/>
<category term="cache" scheme="https://ytlm.github.io/tags/cache/"/>
</entry>
<entry>
<title>ISO的OSI七层网络协议模型</title>
<link href="https://ytlm.github.io/2017/04/ISO%E7%9A%84OSI%E4%B8%83%E5%B1%82%E7%BD%91%E7%BB%9C%E5%8D%8F%E8%AE%AE%E6%A8%A1%E5%9E%8B/"/>
<id>https://ytlm.github.io/2017/04/ISO的OSI七层网络协议模型/</id>
<published>2017-04-10T01:01:17.000Z</published>
<updated>2019-07-04T10:25:44.054Z</updated>
<content type="html"><![CDATA[<p>在网络的大环境中扮演者重要的角色的是网络协议,在这里简单的介绍一下关于ISO七层网络协议模型,当然还有TCP/IP四层网络协议,这里不再赘述。</p><a id="more"></a><h2 id="目的"><a href="#目的" class="headerlink" title="目的"></a>目的</h2><p>在互联网中有千千万万的主机,也有千千万万应用程序,如果不同的主机不同的应用程序不遵守一个规则,就没法交流,那么也就不能称之为互联网了,这时候网络协议的重要性就体现出来了,我们都遵循同样的协议,这样主机和应用程序之间的交流就没有问题了。</p><h2 id="实现"><a href="#实现" class="headerlink" title="实现"></a>实现</h2><p>在网络协议实现的过程中将不同的功能抽象出来,单独实现,只需要提供接口为其它的功能提供服务,具体实现是对其它的服务透明的;这样的好处是每一个服务实现起来只完成特定的功能,实现起来简单;另外在维护的过程中如果出错也更容易定位并发现问题,所以ISO在定制网络协议的时候定义了OSI(Open System Interconnection)协议模型,该模型共分七层,从下至上一次是: 1,物理层; 2,数据链路层; 3,网络层; 4,传输层; 5,会话层; 6,表示层; 7,应用层。下面简单的介绍每层完成的功能。</p><h3 id="1,物理层-Physical-Layer"><a href="#1,物理层-Physical-Layer" class="headerlink" title="1,物理层(Physical Layer)"></a>1,物理层(Physical Layer)</h3><p>为数据链路层提供了一个数据传输的物理媒体,在其上传送比特流,该层数据的单位是比特(bit)。另外该层规定了激活,维持,关闭通信端点之间的机械特性,电气特性,功能特性以及过程特性。</p><h3 id="2,数据链路层-Data-Link-Layer"><a href="#2,数据链路层-Data-Link-Layer" class="headerlink" title="2,数据链路层(Data Link Layer)"></a>2,数据链路层(Data Link Layer)</h3><p>该层在不可靠的物理介质上提供可靠的传输,负责在网络节点之间的线路上通过检测,流量控制和重发等手段,无差错的传送数据,该层数据的单位是帧(frame),所以每一帧数据必须同时带有同步,地址,差错控制以及流量控制等控制信息;总结起来是: 物理寻址,数据成帧,流量控制,数据检错,重发等。</p><h3 id="3,网络层-Network-Layer"><a href="#3,网络层-Network-Layer" class="headerlink" title="3,网络层(Network Layer)"></a>3,网络层(Network Layer)</h3><p>为了将数据从源端系统发送到目的端系统,网络层的主要任务是完成网络寻址,对子网间的数据包进行路由选择,使得分组数据包,该层数据的单位是数据包(packet), 能够准确无误的按照地址找到目的地,并将数据交付给上层协议;另外还可以实现拥塞控制,网际互连等功能。</p><h3 id="4,传输层-Transport-Layer"><a href="#4,传输层-Transport-Layer" class="headerlink" title="4,传输层(Transport Layer)"></a>4,传输层(Transport Layer)</h3><p>该层是端到端的一个层次,主要负责将上层数据分段并提供端到端的,可靠的或不可靠的传输,传输的单位是报文(segment),该层是网络协议分层中最关键的一层,还要处理端到端的差错控制和流量控制问题。</p><h3 id="5,会话层-Session-Layer"><a href="#5,会话层-Session-Layer" class="headerlink" title="5,会话层(Session Layer)"></a>5,会话层(Session Layer)</h3><p>该层主要对传输的报文提供同步管理的服务,在两个不同的主机的互相通信的应用进程之间进行会话的管理,例如确定是半双工还是全双工等;此外还利用在数据中添加校验点来实现数据的同步。</p><h3 id="6,表示层-Presentation-Layer"><a href="#6,表示层-Presentation-Layer" class="headerlink" title="6,表示层(Presentation Layer)"></a>6,表示层(Presentation Layer)</h3><p>该层主要的作用是把数据进行转换,保证一个主机的应用程序数据可以被另一个主机的一个应用程序所理解,即把不同计算机中内部的不同表示形式转换成网络通信协议中的标准形式。主要包括数据的加密(解密),压缩(还原),格式转换等。</p><h3 id="7,应用层-Application-Layer"><a href="#7,应用层-Application-Layer" class="headerlink" title="7,应用层(Application Layer)"></a>7,应用层(Application Layer)</h3><p>该层直接面向用户,主要任务是为操作系统和用户之间提供应用接口。</p><h2 id="数据传输过程"><a href="#数据传输过程" class="headerlink" title="数据传输过程"></a>数据传输过程</h2><h3 id="发送数据"><a href="#发送数据" class="headerlink" title="发送数据"></a>发送数据</h3><ul><li>在OSI参考模型中,当一台主机需要传送数据(DATA)时,数据首先通过应用层的接口进入应用层,在应用层数据被加上应用层报头(Application Header, AH),形成应用层协议数据单元(Protocol Data Unit, PDU),然后提交到下一层,表示层;</li><li>表示层并不关心上层(应用层)的数据格式,而是把整个应用层提交的过来的数据进行整体的封装,添加报文头部(Presentation Header, PH),然后提交到下一层,会话层;</li><li>同样的,会话层,传输层,网络层,数据链路层都分别把上层提交过来的数据加上自己的报头,分别是: 会话层报头(Session Header, SH),传输层报头(Transport Header, TH), 网络层报头(Network Header, NH),数据链路层报头(Data link Header, DH), 然后提交到下一层。<blockquote><p>其中数据链路层还会加上数据链路层报尾(Data link Termination, DT)最终形成一帧数据,在物理层上进行传送。</p></blockquote></li></ul><h3 id="接收数据"><a href="#接收数据" class="headerlink" title="接收数据"></a>接收数据</h3><ul><li>当一帧数据通过物理层传送到目标主机的物理层上时,该主机的物理层把它递交给上层, 数据链路层。数据链路层负责去掉数据的帧头部(DH)和尾部(DT), 同时进行数据校验,如果需要的话会发送反馈给源端主机,如果校验没有出错,则递交到上层,网络层。</li><li>同样的,网络层,传输层,会话层,表示层,应用层也要做相应的动作,并执行对应层的功能,最终原始数据递交到目标主机的具体的应用程序中。</li></ul><h2 id="后记"><a href="#后记" class="headerlink" title="后记"></a>后记</h2><p>当然对于不同的设备,它工作在不同的协议层面上,比如路由器是工作在网络层,交换机是工作在数据链路层,集线器是工作在物理层等等。同时在数据的传输过程中不像这里说的那么简单,这里只是简答的介绍,实际上远比这里介绍的复杂,有兴趣的可以查阅相关资料进行详细的了解,相信会有很大的收获的。</p><hr><p><strong>* 如有疑问欢迎批评指正,谢谢! *</strong></p>]]></content>
<summary type="html">
<p>在网络的大环境中扮演者重要的角色的是网络协议,在这里简单的介绍一下关于ISO七层网络协议模型,当然还有TCP/IP四层网络协议,这里不再赘述。</p>
</summary>
<category term="学习" scheme="https://ytlm.github.io/categories/%E5%AD%A6%E4%B9%A0/"/>
<category term="网络协议" scheme="https://ytlm.github.io/tags/%E7%BD%91%E7%BB%9C%E5%8D%8F%E8%AE%AE/"/>
</entry>
<entry>
<title>nginx基于tcp的转发,适用于HTTPS</title>
<link href="https://ytlm.github.io/2017/04/nginx%E5%9F%BA%E4%BA%8Etcp%E7%9A%84%E8%BD%AC%E5%8F%91-%E9%80%82%E7%94%A8%E4%BA%8EHTTPS/"/>
<id>https://ytlm.github.io/2017/04/nginx基于tcp的转发-适用于HTTPS/</id>
<published>2017-04-05T01:52:22.000Z</published>
<updated>2019-07-04T10:25:44.054Z</updated>
<content type="html"><![CDATA[<h2 id="nginx的主要功能"><a href="#nginx的主要功能" class="headerlink" title="nginx的主要功能"></a>nginx的主要功能</h2><p>1,正向代理<br>2,反向代理<br>3,负载均衡<br>4,WEB服务器</p><blockquote><p>通常用nginx主要做反向代理,负载均衡配合反向代理可以做到很多事情;<br>nginx做WEB服务器可以实现动静文件分离;<br>nginx有很多可选的模块,可以对nginx的功能进行扩展;<br>openresty是一个基于nginx与lua的高性能平台,用lua进行扩展;</p></blockquote><a id="more"></a><h2 id="ssl简单介绍"><a href="#ssl简单介绍" class="headerlink" title="ssl简单介绍"></a>ssl简单介绍</h2><p>1,主要的作用是为了互联网安全;<br>2,SSL是介于HTTP和TCP之间的一个可选层,对于TCP/IP协议来说;<br>3,SSL与TLS之间的关系是TLS(Transport Layer Security)继承并增强了SSL(Secure Socket Layer)协议;</p><blockquote><p>具体的协议交互过程就不再这里展开了,详见参考连接;<br>这里主要说下客户端在SSL协商初期发送的Client Hello请求,其中有个扩展选项,里面有个server name这个可用于转发。</p></blockquote><h2 id="配置nginx转发tcp"><a href="#配置nginx转发tcp" class="headerlink" title="配置nginx转发tcp"></a>配置nginx转发tcp</h2><p>1,版本,nginx version: nginx/1.11.12;我测试用的是这个版本。<br>2,编译,配置<code>./configure --with-stream --with-stream_ssl_preread_module --with-stream_ssl_module</code>最主要的使用这几个模块,有需要可以添加其它的模块;然后编译安装make && make install。<br>3,配置,具体配置命令参考<a href="https://nginx.org/en/docs/stream/ngx_stream_ssl_preread_module.html" target="_blank" rel="noopener">pread module</a>和<a href="https://nginx.org/en/docs/stream/ngx_stream_core_module.html" target="_blank" rel="noopener">stream module</a>,启动的时候指定下面的配置文件</p><figure class="highlight nginx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="attribute">user</span> root;</span><br><span class="line"><span class="attribute">worker_processes</span> auto;</span><br><span class="line"><span class="attribute">error_log</span> logs/error.log;</span><br><span class="line"><span class="attribute">pid</span> logs/nginx.pid;</span><br><span class="line"><span class="attribute">worker_rlimit_core</span> <span class="number">2G</span>;</span><br><span class="line"><span class="attribute">worker_rlimit_nofile</span> <span class="number">65535</span>;</span><br><span class="line"><span class="section">events</span> {</span><br><span class="line"> <span class="attribute">worker_connections</span> <span class="number">81920</span>;</span><br><span class="line">}</span><br><span class="line"><span class="section">stream</span> {</span><br><span class="line"> <span class="attribute">log_format</span> main <span class="string">'<span class="variable">$remote_addr</span> - [<span class="variable">$time_local</span>] <span class="variable">$connection</span> '</span></span><br><span class="line"> <span class="string">'<span class="variable">$status</span> <span class="variable">$proxy_protocol_addr</span> <span class="variable">$server_addr</span> '</span>;</span><br><span class="line"> <span class="attribute">access_log</span> logs/access.log main;</span><br><span class="line"> <span class="attribute">resolver</span> <span class="number">114.114.114.114</span>;</span><br><span class="line"> <span class="attribute">resolver_timeout</span> <span class="number">60s</span>;</span><br><span class="line"> <span class="attribute">variables_hash_bucket_size</span> <span class="number">512</span>;</span><br><span class="line"> <span class="section">server</span> {</span><br><span class="line"> <span class="attribute">listen</span> <span class="number">443</span>;</span><br><span class="line"> <span class="attribute">ssl_preread</span> <span class="literal">on</span>;</span><br><span class="line"> <span class="attribute">proxy_pass</span> <span class="variable">$ssl_preread_server_name</span>:<span class="number">443</span>;</span><br><span class="line"> <span class="comment">#大致看了一下源码,这里为什么需要配置端口也没有研究明白,求解释?</span></span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>4,目前测试基本上都是可以的,在日志中会有一些错误,不会影响正常服务,还再研究中。</p><h2 id="参考连接"><a href="#参考连接" class="headerlink" title="参考连接"></a>参考连接</h2><blockquote><p><a href="https://nginx.org/en/docs/" target="_blank" rel="noopener">https://nginx.org/en/docs/</a><br><a href="https://github.com/openresty/lua-nginx-module" target="_blank" rel="noopener">https://github.com/openresty/lua-nginx-module</a><br><a href="http://www.ruanyifeng.com/blog/2014/02/ssl_tls.html" target="_blank" rel="noopener">http://www.ruanyifeng.com/blog/2014/02/ssl_tls.html</a><br><a href="http://www.wosign.com/faq/faq2016-0309-04.htm" target="_blank" rel="noopener">http://www.wosign.com/faq/faq2016-0309-04.htm</a><br><a href="https://segmentfault.com/a/1190000002554673" target="_blank" rel="noopener">https://segmentfault.com/a/1190000002554673</a></p></blockquote><hr><p><strong>* 如有疑问欢迎批评指正,谢谢! *</strong></p>]]></content>
<summary type="html">
<h2 id="nginx的主要功能"><a href="#nginx的主要功能" class="headerlink" title="nginx的主要功能"></a>nginx的主要功能</h2><p>1,正向代理<br>2,反向代理<br>3,负载均衡<br>4,WEB服务器</p>
<blockquote>
<p>通常用nginx主要做反向代理,负载均衡配合反向代理可以做到很多事情;<br>nginx做WEB服务器可以实现动静文件分离;<br>nginx有很多可选的模块,可以对nginx的功能进行扩展;<br>openresty是一个基于nginx与lua的高性能平台,用lua进行扩展;</p>
</blockquote>
</summary>
<category term="nginx" scheme="https://ytlm.github.io/categories/nginx/"/>
<category term="nginx" scheme="https://ytlm.github.io/tags/nginx/"/>
<category term="https" scheme="https://ytlm.github.io/tags/https/"/>
</entry>
<entry>
<title>hexo travis github</title>
<link href="https://ytlm.github.io/2017/03/hexo-travis-github/"/>
<id>https://ytlm.github.io/2017/03/hexo-travis-github/</id>
<published>2017-03-25T14:16:48.000Z</published>
<updated>2019-07-04T10:25:44.054Z</updated>
<content type="html"><![CDATA[<p>利用hexo, travis, github联合的方式进行博客的创建并且自动发布.</p><p>1,首先是在github创建对应的github pages, 网上有很多教程,这里就不再赘述.<br>2,安装hexo环境用于生成静态博客,这里简单的列举下自己遇到的坑:</p><blockquote><p>(1). yml格式的配置冒号(:)后必须要有一个空格.<br>(2). hexo generate不生效的时候要用hexo clean清空缓存.<br>(3). hexo deploy失败的时候注意git公私钥的配置和_config.yml中deploy的配置.<br>(4). 选择hexo的主题next,对于next主题的配置可以根据官网说经进行合理的配置.</p></blockquote><p>3,travis的使用</p><blockquote><p>(1). 在(yourself).github.io的git上建立一个hexo分支,<br> master分支用于页面的显示,<br> hexo分支用于hexo生成博客和配置,便于同步.<br>(2). travis ci的登陆通过github帐号登陆,然后开启(yourself).github.io的travis;<br> 然后在hexo的分支上创建并提交.travis.yml文件,注意github token的生成和使用<br>(3). 最后就是在hexo的分支上进行写博客和提交到hexo分支上,剩下的发布到master上通过travis自动发布.</p></blockquote><a id="more"></a><p><a href="http://lotabout.me/2016/Hexo-Auto-Deploy-to-Github/" target="_blank" rel="noopener">参考这里</a><br><a href="https://zespia.tw/blog/2015/01/21/continuous-deployment-to-github-with-travis/" target="_blank" rel="noopener">还有这里</a></p><hr><p><strong>* 如有疑问欢迎批评指正,谢谢! *</strong></p>]]></content>
<summary type="html">
<p>利用hexo, travis, github联合的方式进行博客的创建并且自动发布.</p>
<p>1,首先是在github创建对应的github pages, 网上有很多教程,这里就不再赘述.<br>2,安装hexo环境用于生成静态博客,这里简单的列举下自己遇到的坑:</p>
<blockquote>
<p>(1). yml格式的配置冒号(:)后必须要有一个空格.<br>(2). hexo generate不生效的时候要用hexo clean清空缓存.<br>(3). hexo deploy失败的时候注意git公私钥的配置和_config.yml中deploy的配置.<br>(4). 选择hexo的主题next,对于next主题的配置可以根据官网说经进行合理的配置.</p>
</blockquote>
<p>3,travis的使用</p>
<blockquote>
<p>(1). 在(yourself).github.io的git上建立一个hexo分支,<br> master分支用于页面的显示,<br> hexo分支用于hexo生成博客和配置,便于同步.<br>(2). travis ci的登陆通过github帐号登陆,然后开启(yourself).github.io的travis;<br> 然后在hexo的分支上创建并提交.travis.yml文件,注意github token的生成和使用<br>(3). 最后就是在hexo的分支上进行写博客和提交到hexo分支上,剩下的发布到master上通过travis自动发布.</p>
</blockquote>
</summary>
<category term="总结" scheme="https://ytlm.github.io/categories/%E6%80%BB%E7%BB%93/"/>
<category term="github" scheme="https://ytlm.github.io/tags/github/"/>
<category term="hexo" scheme="https://ytlm.github.io/tags/hexo/"/>
<category term="travis" scheme="https://ytlm.github.io/tags/travis/"/>
</entry>
<entry>
<title>git 命令学习</title>
<link href="https://ytlm.github.io/2016/07/git-%E5%91%BD%E4%BB%A4%E5%AD%A6%E4%B9%A0/"/>
<id>https://ytlm.github.io/2016/07/git-命令学习/</id>
<published>2016-07-24T06:52:07.000Z</published>
<updated>2019-07-04T10:25:44.054Z</updated>
<content type="html"><![CDATA[<p>下面是一些在平时学习git时经常需要用的一些命令</p><a id="more"></a><ol><li><p>git stash</p><blockquote><p>把当前未提交的改动「复制」到另一个地方暂存起来,待要恢复的时候执行 git stash pop</p></blockquote></li><li><p>git commit –amend</p><blockquote><p>提交之后发现漏掉了某些文件,选择重新add后提交再次提交是不合理的,应该先add后执行git commit –amend</p></blockquote></li><li><p>git reset <strong>filename</strong></p><blockquote><p>意外地把一个不需要的文件也 add 了,git reset <strong>filename</strong> 把这个文件重staging area位置移除出来,并且不会丢失任何数据</p></blockquote></li><li><p>git checkout <strong>filename</strong></p><blockquote><p>快速扔掉该文件所有的变更,回到没有修改之前的状态</p></blockquote></li><li><p>git checkout -b xxx</p><blockquote><p>创建并且checkout到一个新的分支上</p></blockquote></li><li><p>忽略一个目录</p><blockquote><p>git rm -r –cached <strong>dir</strong> //首先删除已经跟踪并添加过的目录<br>echo <strong>dir/</strong> >> .gitignore //添加忽略文件,并向忽略文件中添加需要忽略的目录<br>git add .gitignore //让git跟踪忽略文件<br>git commit -m ‘ignore <strong>dir</strong> forever’ //提交忽略文件</p></blockquote></li><li><p>git diff <strong>a</strong> <strong>b</strong> <a href="http://www.cnblogs.com/wish123/p/3963224.html" title="原文链接" target="_blank" rel="noopener">原文链接</a></p><blockquote><p>(1). git diff (不加任何参数)</p><blockquote><p>此命令比较的是工作目录(Working tree)和暂存区域快照(index)之间的差异<br>也就是修改之后还没有暂存起来的变化内容。<br>(2). git diff SHA1 SHA2<br>比较两个历史版本之间的差异</p></blockquote></blockquote></li></ol><p><strong><em>未完待续,后续使用到 git 其他相关都会慢慢积累到这里</em></strong></p><hr><p><strong>* 如有疑问欢迎批评指正,谢谢! *</strong></p>]]></content>
<summary type="html">
<p>下面是一些在平时学习git时经常需要用的一些命令</p>
</summary>
<category term="学习" scheme="https://ytlm.github.io/categories/%E5%AD%A6%E4%B9%A0/"/>
<category term="git" scheme="https://ytlm.github.io/tags/git/"/>
</entry>
<entry>
<title>static和extern,定义和声明</title>
<link href="https://ytlm.github.io/2016/07/static%E5%92%8Cextern%EF%BC%8C%E5%AE%9A%E4%B9%89%E5%92%8C%E5%A3%B0%E6%98%8E/"/>
<id>https://ytlm.github.io/2016/07/static和extern,定义和声明/</id>
<published>2016-07-23T15:04:48.000Z</published>
<updated>2019-07-04T10:25:44.054Z</updated>
<content type="html"><![CDATA[<p>总结一下关于声明和定义的区别,以及static和extern的异同</p><a id="more"></a><p><strong><em>声明和定义</em></strong></p><blockquote><p>1,广义角度声明包含定义,定义是声明的一个特例。<br>2,定义是会简历存储空间的,而声明则不会,int a;声明a的同时,也定义了a,建立了存储空间;extern b;只是声明了b,并不是定义b,表示b是在其它文件中定义的。</p></blockquote><p><strong><em>static和extern</em></strong><br><strong><em>static</em></strong></p><table><thead><tr><th>名称</th><th align="center">存储位置</th><th align="right">作用范围</th><th align="right">赋值</th></tr></thead><tbody><tr><td>全局变量</td><td align="center">静态存储区</td><td align="right">从定义位置到文件结束,<br>且能够被其它文件引用。</td><td align="right">若被赋值则为赋值<br>若没有则为0或空</td></tr><tr><td>静态全局变量</td><td align="center">静态存储区</td><td align="right">从定义位置到文件结束,<br>且不能够被其它文件引用,<br>限定于定义的文件内。</td><td align="right">若被赋值则为赋值<br>若没有则为0或空</td></tr><tr><td>局部变量</td><td align="center">非静态存储区</td><td align="right">从定义位置到函数执行结束。</td><td align="right">若被赋值则为赋值<br>若没有则为随机数</td></tr><tr><td>静态局部变量</td><td align="center">静态存储区</td><td align="right">从定义位置到文件结束。</td><td align="right">若被赋值则为赋值<br>若没有则为0或空<br>且只被赋值一次,以后再用到还是上次的值</td></tr><tr><td>静态函数</td><td align="center">栈区</td><td align="right">定义所在文件内。</td><td align="right">-</td></tr><tr><td>非静态函数</td><td align="center">栈区</td><td align="right">可以被出定义所在文件外的<br>其它文件调用。</td><td align="right">-</td></tr></tbody></table><p><strong><em>extern</em></strong><br>extern 只在头文件中声明<br>static 只在源文件中定义</p><hr><p><strong>* 如有疑问欢迎批评指正,谢谢! *</strong></p>]]></content>
<summary type="html">
<p>总结一下关于声明和定义的区别,以及static和extern的异同</p>
</summary>
<category term="学习" scheme="https://ytlm.github.io/categories/%E5%AD%A6%E4%B9%A0/"/>
<category term="C" scheme="https://ytlm.github.io/tags/C/"/>
</entry>
<entry>
<title>C语言编译过程</title>
<link href="https://ytlm.github.io/2016/07/C%E8%AF%AD%E8%A8%80%E7%BC%96%E8%AF%91%E8%BF%87%E7%A8%8B/"/>
<id>https://ytlm.github.io/2016/07/C语言编译过程/</id>
<published>2016-07-23T14:20:38.000Z</published>
<updated>2019-07-04T10:25:44.054Z</updated>
<content type="html"><![CDATA[<p>大致分为如下几个过程,编译预处理阶段,编译阶段, 汇编阶段, 链接。<br>详细过程如下</p><a id="more"></a><p>1,编译预处理(gcc -E main.c -o main.i)</p><blockquote><ul><li>文件包含复制 将源文件中一”#include”格式包含的文件复制到编译的源文件中</li><li>宏定义替换 用实际的值替换用”#define”定义的字符串<blockquote><p>__DATE__:当前源程序的创建日期。<br>__FILE__:当前源程序的文件名称(包括盘符和路径)。<br>__LINE__:当前被编译代码的行号。<br>__STDC__:返回编译器是否位标准C,若其值为1表示符合标准C,否则不是标准C.<br>__TIME__:当前源程序的创建时间。 </p></blockquote></li><li>决定编译代码 根据”#if”条件决定需要编译的实际代码</li><li>删除注释 行注释和块注释</li></ul></blockquote><p>2,编译(gcc -S main.i -o main.s)</p><blockquote><ul><li>对预处理过后的文件进行一系列的词法分析,语法分析,语义分析以及进行相关的优化,生成相应的汇编代码文件</li></ul></blockquote><p>3,汇编(gcc -c main.c -o main.o)</p><blockquote><ul><li>将编译过的汇编代码翻译成目标机器指令的过程</li></ul></blockquote><p>4,链接(ld)</p><blockquote><ul><li>将不同部分的代码和数据收集和组合成为一个单一文件的过程,将相关目标指令文件链接,使其成为一个整体可以被OS执行</li><li>连接器ld将各个目标文件组装在一起,解决符号依赖,库依赖关系,并生成可执行文件</li></ul></blockquote><hr><p><strong>* 如有疑问欢迎批评指正,谢谢! *</strong></p>]]></content>
<summary type="html">
<p>大致分为如下几个过程,编译预处理阶段,编译阶段, 汇编阶段, 链接。<br>详细过程如下</p>
</summary>
<category term="学习" scheme="https://ytlm.github.io/categories/%E5%AD%A6%E4%B9%A0/"/>
<category term="C" scheme="https://ytlm.github.io/tags/C/"/>
</entry>
<entry>
<title>FIRST</title>
<link href="https://ytlm.github.io/2016/06/FIRST/"/>
<id>https://ytlm.github.io/2016/06/FIRST/</id>
<published>2016-06-04T15:16:53.000Z</published>
<updated>2019-07-04T10:25:44.054Z</updated>
<content type="html"><![CDATA[<p> 我的第一个私人博客,之前也一直想要有一个私人的博客,想租个vps和域名,可是没有money,自己维护也很麻烦就一直搁置了。</p><p> 最近借助github平台和hexo工具实现了这个小小的愿望,终于有了一个自己的blog,哈哈哈。。。</p><p> 下面是大致的安装过程。</p><a id="more"></a><p><strong>大致过程如下</strong></p><h2 id="github"><a href="#github" class="headerlink" title="github"></a>github</h2><blockquote><ul><li>首先在github上创建自己的账号,然后创建一个以自己名字命名的仓库,可以自己搜索怎么建立。</li></ul></blockquote><h2 id="安装hexo"><a href="#安装hexo" class="headerlink" title="安装hexo"></a>安装hexo</h2><blockquote><ul><li>首先安装node.js,因为hexo是基于node.js开发的一个静态博客框架</li><li>安装hexo,安装的过程中可能需要更换npm源</li></ul></blockquote><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm install hexo -g</span><br></pre></td></tr></table></figure><h2 id="初始化自己的blog"><a href="#初始化自己的blog" class="headerlink" title="初始化自己的blog"></a>初始化自己的blog</h2><blockquote><ul><li>创建一个文件夹作为自己以后blog的根目录</li><li>进入该blog目录,进行初始化配置</li><li>配置根目录下的__config.yml文件</li></ul></blockquote><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">mkdir blog</span><br><span class="line"><span class="built_in">cd</span> blog</span><br><span class="line">hexo init</span><br><span class="line">hexo install</span><br><span class="line">hexo new <span class="string">"newAticle"</span> //创建新的文章,执行完之后会在sources/_post/目录下会有newAticle.md文件,打开进行编辑</span><br><span class="line">hexo clean //清除本地缓存</span><br><span class="line">hexo generate //生成网站</span><br><span class="line">hexo serve //开启本地服务,可以在http://localhost:4000/中进行本地预览</span><br><span class="line">hexo deploy //部署到github上</span><br></pre></td></tr></table></figure><p><strong><em>以后每次添加新文章就按照 / hexo clean / hexo new “” / hexo generate / hexo deploy / 的顺序就可以添加新文章</em></strong></p><h2 id="选择hexo主题,next"><a href="#选择hexo主题,next" class="headerlink" title="选择hexo主题,next"></a>选择hexo主题,next</h2><blockquote><ul><li>安装next主题</li><li>启用next主题,根目录下配置文件_config.yml配置theme: next</li><li>优化配置next主题,在next主题文件目录下的配置文件_config.yml</li></ul></blockquote><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git <span class="built_in">clone</span> https://github.com/iissnan/hexo-theme-next themes/next</span><br></pre></td></tr></table></figure><hr><p><strong>* 如有疑问欢迎批评指正,谢谢! *</strong></p>]]></content>
<summary type="html">
<p> 我的第一个私人博客,之前也一直想要有一个私人的博客,想租个vps和域名,可是没有money,自己维护也很麻烦就一直搁置了。</p>
<p> 最近借助github平台和hexo工具实现了这个小小的愿望,终于有了一个自己的blog,哈哈哈。。。</p>
<p> 下面是大致的安装过程。</p>
</summary>
<category term="随笔" scheme="https://ytlm.github.io/categories/%E9%9A%8F%E7%AC%94/"/>
<category term="github" scheme="https://ytlm.github.io/tags/github/"/>
<category term="hexo" scheme="https://ytlm.github.io/tags/hexo/"/>
</entry>
</feed>