-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsearch.xml
More file actions
1319 lines (1279 loc) · 176 KB
/
search.xml
File metadata and controls
1319 lines (1279 loc) · 176 KB
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
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title>正则表达式</title>
<url>/2020/03/06/01-%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F/</url>
<content><![CDATA[<h4 id="概述"><a href="#概述" class="headerlink" title="概述"></a>概述</h4><h4 id="re模块操作"><a href="#re模块操作" class="headerlink" title="re模块操作"></a>re模块操作</h4><ol>
<li>re模块的使用过程<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line"># 导入re模块</span><br><span class="line">import re</span><br><span class="line"></span><br><span class="line"># 使用match方法进行匹配操作</span><br><span class="line"># re.match(正则表达式,要匹配的字符串)</span><br><span class="line">result = re.match(r"[Hh]ello", "hello world")</span><br><span class="line"></span><br><span class="line"># 如果上一步匹配到数据的话,可以使用group方法来提取数据</span><br><span class="line">result.group()</span><br><span class="line"></span><br><span class="line">result = re.match(r"[Hh]ello", "hello world").group() # 匹配后直接提取数据</span><br></pre></td></tr></table></figure></li>
<li>re模块示例<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">#coding=utf-8</span><br><span class="line"></span><br><span class="line">import re</span><br><span class="line">result = re.match("itcast", "itcast.cn")</span><br><span class="line">result.group()</span><br></pre></td></tr></table></figure>
<h4 id="匹配单个字符"><a href="#匹配单个字符" class="headerlink" title="匹配单个字符"></a>匹配单个字符</h4>字符|功能|示例</li>
</ol>
<p>—|—|—<br>. | 匹配任意1个字符(<strong>除了\n</strong>)<br>[] | 匹配[]中列举的字符 | [1-8] 匹配1到8;[16] 匹配1或6;[1-36-8] 匹配1到3 6到8<br>\d | 匹配一位数字,即0-9<br>\D | 匹配非数字,即不是数字<br>\s | 匹配空白,即空格,tab键<br>\S | 匹配非空白<br>\w | 匹配单词字符,即a-z、A-Z、0-9、_、各类语言字符。。。<br>\W | 匹配非单词字符</p>
<h4 id="匹配多个字符"><a href="#匹配多个字符" class="headerlink" title="匹配多个字符"></a>匹配多个字符</h4><table>
<thead>
<tr>
<th>字符</th>
<th>功能</th>
</tr>
</thead>
<tbody><tr>
<td>*</td>
<td>匹配前一个字符出现0次或无限次,即可有可无</td>
</tr>
<tr>
<td>+</td>
<td>匹配前一个字符出现1次或无限次,即至少1次</td>
</tr>
<tr>
<td>?</td>
<td>匹配前一个字符出现0次或1次,即要么没有,要么有1次</td>
</tr>
<tr>
<td>{m}</td>
<td>匹配前一个字符出现m次</td>
</tr>
<tr>
<td>{m, n}</td>
<td>匹配前一个字符出现从m到n次</td>
</tr>
</tbody></table>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line"># 匹配\d 1到3次</span><br><span class="line">re.match(r"速度与激情\d{1,3}", "速度与激情3").group()</span><br><span class="line"></span><br><span class="line"># 匹配连续十一位数字</span><br><span class="line">re.match(r"\d{11}", "12345678901").group()</span><br><span class="line"></span><br><span class="line"># 匹配手机号</span><br><span class="line">re.match(r"\d{3,4}-?\d{7,8}","0310-3328839").group()</span><br><span class="line"></span><br><span class="line"># 匹配'\n'</span><br><span class="line">re.match(r".*", html_content, re.S).group()</span><br></pre></td></tr></table></figure>
<h4 id="匹配开头结尾"><a href="#匹配开头结尾" class="headerlink" title="匹配开头结尾"></a>匹配开头结尾</h4><table>
<thead>
<tr>
<th>字符</th>
<th>功能</th>
</tr>
</thead>
<tbody><tr>
<td>^</td>
<td>匹配字符串开头</td>
</tr>
<tr>
<td>$</td>
<td>匹配字符串结尾</td>
</tr>
</tbody></table>
<h4 id="匹配分组"><a href="#匹配分组" class="headerlink" title="匹配分组"></a>匹配分组</h4><table>
<thead>
<tr>
<th>字符</th>
<th>功能</th>
</tr>
</thead>
<tbody><tr>
<td></td>
<td></td>
</tr>
<tr>
<td>(ab)</td>
<td>将括号中字符作为一个分组</td>
</tr>
<tr>
<td>\num</td>
<td>引用分组num匹配到的字符串</td>
</tr>
<tr>
<td>(?P<name>)</td>
<td>分组起别名</td>
</tr>
<tr>
<td>(?P=name)</td>
<td>引用别名为name分组匹配到的字符串</td>
</tr>
<tr>
<td><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">re.match(r"([a-zA-Z0-9_]{4,20})@(163|126)\.com$","day@163.com").group(1)</span><br><span class="line">--> 'day'</span><br><span class="line">re.match(r"([a-zA-Z0-9_]{4,20})@(163|126)\.com$","day@163.com").group(2)</span><br><span class="line">--> '163'</span><br></pre></td></tr></table></figure></td>
<td></td>
</tr>
</tbody></table>
<p><strong>示例</strong></p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">re.match(r"<(\w*)>.*</\1>","<h1>hahaha</h1>").group()</span><br><span class="line"></span><br><span class="line">re.match(r"<(\w*)><(\w*)>.*</\2></\1>","<body><h1>hahaha</h1><body>").group()</span><br><span class="line"></span><br><span class="line">re.match(r"<(?P<p1>\w*)>.*</?P=p1>","<h1>hahaha</h1>").group()</span><br></pre></td></tr></table></figure>
<h4 id="re模块的高级用法"><a href="#re模块的高级用法" class="headerlink" title="re模块的高级用法"></a>re模块的高级用法</h4><p><strong>search</strong></p>
<ol>
<li>search不从头开始匹配,只要匹配到相应值就结束</li>
<li>match默认从头开始匹配<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">import re</span><br><span class="line"></span><br><span class="line">ret = re.search(r"\d+","阅读次数为9999")</span><br><span class="line">ret.group()</span><br><span class="line">--> '9999'</span><br></pre></td></tr></table></figure></li>
</ol>
<p><strong>findall</strong><br>findall从头开始匹配,提取所有符合要求的字符串<br>需求:统计出Python、C、C++相应文章阅读的次数</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">import re</span><br><span class="line"></span><br><span class="line">ret = re.findall(r"\d+","python = 9999, c = 7890, c++ = 12345")</span><br><span class="line">print(ret)</span><br><span class="line">-->['9999', '7890', '12345']</span><br></pre></td></tr></table></figure>
<p><strong>sub</strong><br>将匹配到的数据进行<strong>替换</strong><br>需求:将匹配到的阅读次数加1</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">import re</span><br><span class="line"></span><br><span class="line">def add(temp):</span><br><span class="line"> strNum = temp.group()</span><br><span class="line"> num = int(strNum) + 1</span><br><span class="line"> return str(num)</span><br><span class="line"></span><br><span class="line">ret = re.sub(r"\d+", add, 'python = 997 c++ = 900')</span><br><span class="line">print(ret)</span><br><span class="line">--> 'python = 998 c++ = 901'</span><br></pre></td></tr></table></figure>
<p><strong>split</strong><br>根据匹配进行切割字符串,并返回一个列表<br>需求:切割字符串“info:xiaoZhang 33 shandong”</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">import re</span><br><span class="line"></span><br><span class="line">ret = re.split(r":| ", "info:xiaoZhang 33 shandong")</span><br><span class="line">print(ret)</span><br><span class="line">--> ['info', 'xiaoZhang', '33', 'shandong']</span><br></pre></td></tr></table></figure>
<h4 id="贪婪和非贪婪"><a href="#贪婪和非贪婪" class="headerlink" title="贪婪和非贪婪"></a>贪婪和非贪婪</h4><h4 id="r的作用"><a href="#r的作用" class="headerlink" title="r的作用"></a>r的作用</h4>]]></content>
<tags>
<tag>regex</tag>
</tags>
</entry>
<entry>
<title>python协程</title>
<url>/2020/03/06/02-%E5%A4%9A%E4%BB%BB%E5%8A%A1-%E5%8D%8F%E7%A8%8B/</url>
<content><![CDATA[<h4 id="协程"><a href="#协程" class="headerlink" title="协程"></a>协程</h4><blockquote>
<p>生成器 迭代器 装饰器 Python三大器</p>
</blockquote>
<blockquote>
<p>迭代器 -> 生成器 -> yield -> greenlet -> gevent</p>
</blockquote>
<h4 id="迭代器"><a href="#迭代器" class="headerlink" title="迭代器"></a>迭代器</h4><p>迭代时访问集合元素的一种方式,迭代器是一个可以记住遍历的位置的对象,迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退。</p>
<ol>
<li>可迭代对象</li>
</ol>
<p>对list、tuple、str、dict、集合等类型的数据使用for…in…的循环语法从其中依次拿到数据进行使用,我们把这样的过程称为遍历,也叫<strong>迭代</strong>。</p>
<p>但是,是否所有的数据类型都可以放到for…in…的语句中,然后让for…in…每次从中取出一条数据供我们使用,即供我们迭代吗?</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">from collections import Iterable</span><br><span class="line"></span><br><span class="line">isinstance([11, 22, 33], Iterable)</span><br><span class="line">-> True</span><br><span class="line"></span><br><span class="line">isinstance((11, 22, 33), Iterable)</span><br><span class="line">-> True</span><br><span class="line"></span><br><span class="line">isinstance(100, Iterable)</span><br><span class="line">-> False</span><br></pre></td></tr></table></figure>
<h5 id="类的迭代、迭代器的实现"><a href="#类的迭代、迭代器的实现" class="headerlink" title="类的迭代、迭代器的实现"></a>类的迭代、迭代器的实现</h5><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">from collections import Iterable</span><br><span class="line">from collections import Iterator</span><br><span class="line"></span><br><span class="line">class Classmate(object):</span><br><span class="line"> def __init__(self):</span><br><span class="line"> self.names = list()</span><br><span class="line"> self.current_num = 0</span><br><span class="line"> </span><br><span class="line"> def add(self, name):</span><br><span class="line"> self.names.append(name)</span><br><span class="line"> </span><br><span class="line"> def __iter__(self):</span><br><span class="line"> '''如果想要一个对象成为一个可以迭代的对象,即可以使用for,那么必须实现__iter__方法'''</span><br><span class="line"> return self</span><br><span class="line"> </span><br><span class="line"> def __next__(self):</span><br><span class="line"> '''返回调用值'''</span><br><span class="line"> if self.current_num < len(self.names):</span><br><span class="line"> ret = self.names[self.current_num]</span><br><span class="line"> self.current_num += 1</span><br><span class="line"> return ret</span><br><span class="line"> else:</span><br><span class="line"> raise StopIteration</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">classmate = Classmate()</span><br><span class="line"></span><br><span class="line">classmate.add("张三")</span><br><span class="line">classmate.add("李四")</span><br><span class="line">classmate.add("王五")</span><br><span class="line"></span><br><span class="line"># print("判断classmate是否是可以迭代的对象:",isinstance(classmate, Iterable))</span><br><span class="line"># classmate_iterator = iter(classmate)</span><br><span class="line"># print("判断classmate_iterator是否是迭代器:",isinstance(classmate_iterator, Iterator)</span><br><span class="line"></span><br><span class="line">for name in classmate:</span><br><span class="line"> print(name)</span><br></pre></td></tr></table></figure>
<h5 id="Fibonacci的迭代器实现"><a href="#Fibonacci的迭代器实现" class="headerlink" title="Fibonacci的迭代器实现"></a>Fibonacci的迭代器实现</h5><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">class Fibonacci(object):</span><br><span class="line"> def __init__(self, all_num):</span><br><span class="line"> self.all_num = all_num</span><br><span class="line"> self.current_num = 0</span><br><span class="line"> self.a = 0</span><br><span class="line"> self.b = 1</span><br><span class="line"> </span><br><span class="line"> def __iter__(self):</span><br><span class="line"> return self</span><br><span class="line"> </span><br><span class="line"> def __next__(self):</span><br><span class="line"> if self.current_num < self.all_num:</span><br><span class="line"> ret = self.a</span><br><span class="line"> </span><br><span class="line"> self.a, self.b = self.b, self.a+self.b</span><br><span class="line"> self.current_num += 1</span><br><span class="line"> </span><br><span class="line"> return ret</span><br><span class="line"> else:</span><br><span class="line"> raise StopIteration</span><br><span class="line"></span><br><span class="line">fibo = Fibonacci(10)</span><br><span class="line"></span><br><span class="line">for num in fibo:</span><br><span class="line"> print(num)</span><br></pre></td></tr></table></figure>
<h5 id="并不是只有for循环能接受可迭代对象"><a href="#并不是只有for循环能接受可迭代对象" class="headerlink" title="并不是只有for循环能接受可迭代对象"></a>并不是只有for循环能接受可迭代对象</h5><p>除了for循环能接受可迭代对象,list、tuple等也能接受</p>
<p><strong>iter</strong>() -> <strong>next</strong>() -> return </p>
<h4 id="生成器"><a href="#生成器" class="headerlink" title="生成器"></a>生成器</h4><p>生成器是一个特殊的迭代器</p>
<h5 id="应用1"><a href="#应用1" class="headerlink" title="应用1"></a>应用1</h5><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">nums = [x*2 for x in range(10)]</span><br><span class="line">-> [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]</span><br><span class="line"></span><br><span class="line">nums = (x*2 for x in range(10))</span><br><span class="line">-> <generator object <genexpr> at 0x7f7ec7071938></span><br></pre></td></tr></table></figure>
<p>列表推导式生成一个列表<br>生成器生成一个对象,不占用内存空间,可通过for循环调用</p>
<h5 id="应用2"><a href="#应用2" class="headerlink" title="应用2"></a>应用2</h5><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">def create_num(all_num):</span><br><span class="line"> a, b = 0, 1</span><br><span class="line"> current_num = 0</span><br><span class="line"> while current_num < all_num:</span><br><span class="line"> yield a #如果一个函数中有yield语句,那么这个就不再是函数,而是一个生成器模板</span><br><span class="line"> a, b = b, a+b</span><br><span class="line"> current_num += 1</span><br><span class="line"># 如果在调用create_num的时候,发现这个函数中由yield,那么此时不是调用函数,而是创建一个生成器对象。</span><br><span class="line">obj = create_num(10)</span><br><span class="line"></span><br><span class="line">for num in obj:</span><br><span class="line"> print(num)</span><br></pre></td></tr></table></figure>
<h5 id="yield生成器获取return值"><a href="#yield生成器获取return值" class="headerlink" title="yield生成器获取return值"></a>yield生成器获取return值</h5><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">def create_num(all_num):</span><br><span class="line"> a, b = 0, 1</span><br><span class="line"> current_num = 0</span><br><span class="line"> while current_num < all_num:</span><br><span class="line"> yield a</span><br><span class="line"> a, b = b, a+b</span><br><span class="line"> current_num += 1</span><br><span class="line"> return "ok...."</span><br><span class="line"> </span><br><span class="line">obj = create_num(20)</span><br><span class="line"></span><br><span class="line">while True:</span><br><span class="line"> try:</span><br><span class="line"> ret = next(obj)</span><br><span class="line"> print(ret)</span><br><span class="line"> except Exception as ret:</span><br><span class="line"> print(ret.value)</span><br><span class="line"> break</span><br></pre></td></tr></table></figure>
<h5 id="send-传递参数"><a href="#send-传递参数" class="headerlink" title="send()传递参数"></a>send()传递参数</h5><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">def create_num(all_num):</span><br><span class="line"> a, b = 0, 1</span><br><span class="line"> current_num = 0</span><br><span class="line"> while current_num < all_num:</span><br><span class="line"> ret = yield a # 右侧语句执行暂停,传参给next()</span><br><span class="line"> # send()将参数传过来,程序从暂停处开始执行,将传过来的参数赋给ret</span><br><span class="line"> print("ret:", ret)</span><br><span class="line"> a, b = b, a+b</span><br><span class="line"> current_num += 1</span><br><span class="line"> </span><br><span class="line">obj = create_num(20)</span><br><span class="line"></span><br><span class="line">ret = next(obj) </span><br><span class="line">print(ret)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">ret = obj.send("hahaahha") #等同于next(),不同的是可以传参</span><br><span class="line"># send()一般不会放到第一次启动生成器,如果非要这么做,那么传递None</span><br><span class="line"># 再次运行到yield a,将a的值赋给ret</span><br><span class="line">print(ret)</span><br></pre></td></tr></table></figure>
<h3 id="使用yield完成多任务"><a href="#使用yield完成多任务" class="headerlink" title="使用yield完成多任务"></a>使用yield完成多任务</h3><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">import time</span><br><span class="line"></span><br><span class="line">def task_1():</span><br><span class="line"> while True:</span><br><span class="line"> print("---1---")</span><br><span class="line"> time.sleep(0.1)</span><br><span class="line"> yield</span><br><span class="line"> </span><br><span class="line">def task_2():</span><br><span class="line"> while True:</span><br><span class="line"> print("---2---")</span><br><span class="line"> time.sleep(0.1)</span><br><span class="line"> yield</span><br><span class="line"></span><br><span class="line">def main():</span><br><span class="line"> t1 = task_1()</span><br><span class="line"> t2 = task_2()</span><br><span class="line"> # 先让t1运行一会,当t1中遇到yield的时候,返回此处</span><br><span class="line"> # 执行t2,当它遇到yield的时候,再次切换到t1中</span><br><span class="line"> # 这样t1/t2/t1/t2的交替运行,最终实现了多任务...协程</span><br><span class="line"> while True:</span><br><span class="line"> next(t1)</span><br><span class="line"> next(t2)</span><br><span class="line"></span><br><span class="line">if __name__ == "__main__":</span><br><span class="line"> main()</span><br></pre></td></tr></table></figure>
<h4 id="使用greenlet、gevent完成多任务"><a href="#使用greenlet、gevent完成多任务" class="headerlink" title="使用greenlet、gevent完成多任务"></a>使用greenlet、gevent完成多任务</h4><p>核心使用yield实现</p>
<p>$ pip3 install greenlet # 安装greenlet</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">from greenlet import greenlet</span><br><span class="line">import time</span><br><span class="line"></span><br><span class="line">def test1():</span><br><span class="line"> while True:</span><br><span class="line"> print("---A---")</span><br><span class="line"> gr2.switch()</span><br><span class="line"> time.sleep(0.5)</span><br><span class="line"> </span><br><span class="line">def test2():</span><br><span class="line"> while True:</span><br><span class="line"> print("---B---")</span><br><span class="line"> gr1.switch()</span><br><span class="line"> time.sleep(0.5)</span><br><span class="line"></span><br><span class="line">gr1 = greenlet(test1)</span><br><span class="line">gr2 = greenlet(test2)</span><br><span class="line"></span><br><span class="line"># 切换到gr1中运行</span><br><span class="line">gr1.switch()</span><br></pre></td></tr></table></figure>
<p>$ pip3 install gevent</p>
<ul>
<li>依赖关系<br>协程 <- 线程<- 进程<br>遇到耗时操作进行切换</li>
</ul>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">import gevent</span><br><span class="line"></span><br><span class="line">def f1(n):</span><br><span class="line"> for i in range(n):</span><br><span class="line"> print(gevent.getcurrent(), i)</span><br><span class="line"> gevent.sleep(0.5)</span><br><span class="line"></span><br><span class="line">def f2(n):</span><br><span class="line"> for i in range(n):</span><br><span class="line"> print(gevent.getcurrent(), i)</span><br><span class="line"> gevent.sleep(0.5)</span><br><span class="line"></span><br><span class="line">def f3(n):</span><br><span class="line"> for i in range(n):</span><br><span class="line"> print(gevent.getcurrent(), i)</span><br><span class="line"> gevent.sleep(0.5)</span><br><span class="line"></span><br><span class="line">g1 = gevent.spawn(f1, 5) # 生成yield对象 f:指定函数 5:指定传参 </span><br><span class="line">g2 = gevent.spawn(f2, 5)</span><br><span class="line">g3 = gevent.spawn(f3, 5)</span><br><span class="line">g1.join() # 运行期间会耗时,自行切换到下一个对象</span><br><span class="line">g2.join()</span><br><span class="line">g3.join()</span><br></pre></td></tr></table></figure>
<h4 id="sleep补丁"><a href="#sleep补丁" class="headerlink" title="sleep补丁"></a>sleep补丁</h4><ul>
<li>协程使用代码示例<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">from gevent import monkey</span><br><span class="line">import gevent</span><br><span class="line">import random</span><br><span class="line">import time</span><br><span class="line"></span><br><span class="line"># 有耗时操作时需要</span><br><span class="line">monkey.patch_all() # 将程序中用到的耗时操作的代码,换为gevent中自己实现的模块</span><br><span class="line"></span><br><span class="line">def coroutine_work(coroutine_name):</span><br><span class="line"> for i in range(10):</span><br><span class="line"> print(coroutine_name, i)</span><br><span class="line"> time.sleep(random.random()</span><br><span class="line"></span><br><span class="line"># 将多个join连接起来用一个元组实现</span><br><span class="line"># 等待元组中所有协程都完成后结束当前进程</span><br><span class="line">gevent.joinall([</span><br><span class="line"> gevent.spawn(coroutine_work, "work1"),</span><br><span class="line"> gevent.spawn(coroutine_work, "work2")</span><br><span class="line">])</span><br></pre></td></tr></table></figure>
</li>
</ul>
<h4 id="案例-并发下载器"><a href="#案例-并发下载器" class="headerlink" title="案例-并发下载器"></a>案例-并发下载器</h4><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">from gevent import monkey</span><br><span class="line">import gevent</span><br><span class="line">import urllib.request</span><br><span class="line"></span><br><span class="line">monkey.patch_all()</span><br><span class="line"></span><br><span class="line">def downloader(img_name, img_url):</span><br><span class="line"> req = urllib.request.urlopen(img_orl)</span><br><span class="line"> </span><br><span class="line"> img_content = req.read()</span><br><span class="line"> </span><br><span class="line"> with open(img_name, "wb") as f:</span><br><span class="line"> f.write(img_content)</span><br><span class="line"> </span><br><span class="line">def main():</span><br><span class="line"> gevent.joinall([</span><br><span class="line"> gevent.spawn(downlaoder, "1.jpg", "http://url"),</span><br><span class="line"> gevent.spawn(downlaoder, "1.jpg", "http://url")</span><br><span class="line"> ])</span><br><span class="line"></span><br><span class="line">if __name__ == "__main__":</span><br><span class="line"> main()</span><br></pre></td></tr></table></figure>
<h4 id="进程、线程、协程对比"><a href="#进程、线程、协程对比" class="headerlink" title="进程、线程、协程对比"></a>进程、线程、协程对比</h4><ul>
<li>有一个老板想要开个工厂进行生产某件商品</li>
<li>他需要画一些财力物力制作一条生产线,这个生产线上有很多的器件以及材料这些所有的为了能够生产商品而准备的资源称之为:<strong>进程</strong></li>
<li>只有生产线程时不能够进行生产的,所以老板需要找个工人来进行生产,这个工人能够利用这些材料最终一步步的将商品制作出来,这个来做事情的工人称之为:<strong>线程</strong></li>
<li>这个老板为了提高生产率,想到3种方法:<ol>
<li>在这条生产线上多找些工人,一起来做商品,这样效率是成倍增长,即<strong>单进程 多线程</strong>方式</li>
<li>老板发现这条生产线上的工人不是越多越好,因为一条生产线的资源以及材料毕竟有限,所以老板又花了写财力物力购置了一条生产线,然后再招些工人,这样效率又再一步提高了,即<strong>多进程 多线程</strong>方式</li>
<li>老板发现,现在已经有了很多条生产线,并且每条生产线上已经有很多工人了(即程序是多进程的,每个进程中又有多个线程),为了再次提高效率,老板想了个损招,规定:如果某个员工在上班时,临时没事或者再等待某些条件(比如等待另一个工人生产完某道工序之后,他才能再次工作),那么这个员工就利用这个时间去做其他的事情,那么也就是说:如果一个线程等待某些条件,可以充分利用这个时间去做其他事情,其实这就是:<strong>协程</strong>方式</li>
</ol>
</li>
</ul>
<h5 id="简单总结"><a href="#简单总结" class="headerlink" title="简单总结"></a>简单总结</h5><ol>
<li>进程是资源分配的单位</li>
<li>线程是操作系统调度的单位</li>
<li>进程切换需要的资源最大,效率很低</li>
<li>线程切换需要的资源一般,效率一般(不考虑GIL的情况下)</li>
<li>协程切换任务资源很小,效率高</li>
<li>多进程、多线程根据CPU核数不一样可能是并行的,但是协程是在一个线程中,所以是并发。</li>
</ol>
]]></content>
<tags>
<tag>python</tag>
</tags>
</entry>
<entry>
<title>python线程</title>
<url>/2020/03/06/02-%E5%A4%9A%E4%BB%BB%E5%8A%A1-%E7%BA%BF%E7%A8%8B/</url>
<content><![CDATA[<h4 id="创建多线程"><a href="#创建多线程" class="headerlink" title="创建多线程"></a>创建多线程</h4><ul>
<li><p>demo1</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">import threading</span><br><span class="line">import time</span><br><span class="line"></span><br><span class="line">def saySorry():</span><br><span class="line"> print("亲爱的,我错了,我能吃饭了吗?")</span><br><span class="line"> time.sleep(1)</span><br><span class="line"></span><br><span class="line">if __name__ == "__main__"</span><br><span class="line"> for i in range(5):</span><br><span class="line"> t = threading.Thread(target=saySorry) #创建实例对象t</span><br><span class="line"> t.start() #启动线程,生成子线程,运行指定参数</span><br></pre></td></tr></table></figure>
</li>
<li><p>demo2</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">import time</span><br><span class="line">import threading</span><br><span class="line"></span><br><span class="line">def sing():</span><br><span class="line"> """唱歌 5秒钟"""</span><br><span class="line"> for i in range(5):</span><br><span class="line"> print("---正在唱:菊花茶---")</span><br><span class="line"> time.sleep(1)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">def dance():</span><br><span class="line"> """跳舞 5秒钟"""</span><br><span class="line"> for i in range(5):</span><br><span class="line"> print("---正在跳舞---")</span><br><span class="line"> time.sleep(1)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">def main():</span><br><span class="line"> t1 = threading.Thread(target=sing) #创建实例对象t1,传参sing</span><br><span class="line"> t2 = threading.Thread(target=dance) #创建实例对象t2。传参dance</span><br><span class="line"> t1.start() #生成子线程</span><br><span class="line"> t2.start() #生成子线程 </span><br><span class="line"></span><br><span class="line"></span><br><span class="line">if __name__ == "__main__":</span><br><span class="line"> main()</span><br></pre></td></tr></table></figure>
</li>
</ul>
<h4 id="查看线程数量"><a href="#查看线程数量" class="headerlink" title="查看线程数量"></a>查看线程数量</h4><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">import time</span><br><span class="line">import threading</span><br><span class="line"></span><br><span class="line">def test1():</span><br><span class="line"> for i in range(5):</span><br><span class="line"> print("---test---%d" % i) #子线程t1</span><br><span class="line"> time.sleep(1)</span><br><span class="line"> #如果创建Thread时执行的函数运行结束,那么意味着这个子线程结束了</span><br><span class="line"></span><br><span class="line">def test2():</span><br><span class="line"> for i in range(10):</span><br><span class="line"> print("---test---%d" % i) #子线程t2</span><br><span class="line"> time.sleep(1)</span><br><span class="line"></span><br><span class="line">def main():</span><br><span class="line"> t1 = threading.Thread(target=test1) #创建实例对象t1,传参test1,不创建线程</span><br><span class="line"> t2 = threading.Thread(target=test2) #创建实例对象t2,传参test2,不创建线程</span><br><span class="line"> </span><br><span class="line"> t1.start() #生成子线程t1</span><br><span class="line"> t2.start() #生成子线程t2</span><br><span class="line"> # 线程执行顺序不确定,可通过延时控制执行顺序 </span><br><span class="line"> while True:</span><br><span class="line"> print(threading.enumerate()) #获取当前程序所有线程的信息</span><br><span class="line"> if len(threading,enumerous()) <= 1:</span><br><span class="line"> break</span><br><span class="line"> time.sleep(1)</span><br><span class="line"> #主线程结束,程序就会结束,主线程结束会杀掉所有子线程。</span><br><span class="line"></span><br><span class="line">if __name__ == "__main__":</span><br><span class="line"> main()</span><br></pre></td></tr></table></figure>
<h4 id="通过继承Thread类完成创建线程"><a href="#通过继承Thread类完成创建线程" class="headerlink" title="通过继承Thread类完成创建线程"></a>通过继承Thread类完成创建线程</h4><ul>
<li>demo<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">import threading</span><br><span class="line">import time</span><br><span class="line"></span><br><span class="line">class MyThread(threading.Thread): #MyThread类继承自Thread类</span><br><span class="line"> def run(self): #方法名必须是run(),才能实现多线程</span><br><span class="line"> for i in range(3):</span><br><span class="line"> time.sleep(3)</span><br><span class="line"> msg = "I'm" + self.name + '@' + str(i) #name属性中保存的时当前线程的名字</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">i __name__ == "__main__":</span><br><span class="line"> t = MyThread() #一个实例对象只能开启一个子线程</span><br><span class="line"> t.start() #start()自动调用子类中的run()方法。</span><br></pre></td></tr></table></figure>
</li>
</ul>
<h4 id="多线程-共享全局变量"><a href="#多线程-共享全局变量" class="headerlink" title="多线程-共享全局变量"></a>多线程-共享全局变量</h4><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">import threading</span><br><span class="line">import time</span><br><span class="line"></span><br><span class="line"># 定义全局变量</span><br><span class="line">num = 100</span><br><span class="line"></span><br><span class="line">def test1():</span><br><span class="line"> global g_num # 声明该变量是全局变量</span><br><span class="line"> g_num += 1</span><br><span class="line"> print("in test1 g_num=%d" % g_num)</span><br><span class="line"></span><br><span class="line">def test2():</span><br><span class="line"> print("in test2 g_num=%d" % g_num) #不修改变量是可以不声明直接使用</span><br><span class="line"></span><br><span class="line">def main():</span><br><span class="line"> t1 = threading.Thread(target=test1)</span><br><span class="line"> t2 = threading.Thread(target=test2)</span><br><span class="line"> </span><br><span class="line"> t1.start()</span><br><span class="line"> time.sleep()</span><br><span class="line"> </span><br><span class="line"> t2.start()</span><br><span class="line"> time.sleep()</span><br><span class="line"> </span><br><span class="line">if __name__ == "__main__":</span><br><span class="line"> main()</span><br></pre></td></tr></table></figure>
<blockquote>
<p>在一个函数中,对全局变量进行修改的时候,到底是否需要使用global进行说明?</p>
</blockquote>
<p>要看是否对全局变量的执行指向进行了修改,</p>
<p>如果修改了执行,即让全局变量指向了一个新的地方,那么必须使用global,例如test1()</p>
<p>如果仅仅是修改了指向的空间中的数据,此时不需要必须使用global。例如test2()</p>
<h4 id="多线程共享全局变量-args参数"><a href="#多线程共享全局变量-args参数" class="headerlink" title="多线程共享全局变量-args参数"></a>多线程共享全局变量-args参数</h4><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">def test1(temp):</span><br><span class="line"> Null</span><br><span class="line"></span><br><span class="line"># target指定这个线程去哪个函数执行代码</span><br><span class="line"># args指定调用函数的时候传递什么数据过去</span><br><span class="line">t1 = threading.Thread(target=test1, args=(g_num,)) # args传递元组数据类型</span><br></pre></td></tr></table></figure>
<h4 id="多线程-共享全局变量问题"><a href="#多线程-共享全局变量问题" class="headerlink" title="多线程-共享全局变量问题"></a>多线程-共享全局变量问题</h4><h5 id="互斥锁"><a href="#互斥锁" class="headerlink" title="互斥锁"></a>互斥锁</h5><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line"># 创建互斥锁</span><br><span class="line">mutex = threading.Lock() # 同一把锁只能使用一次</span><br><span class="line"></span><br><span class="line"># 锁定</span><br><span class="line">mutex.acquire() # 如果上锁之前已被上锁,则此时阻塞在这里,直至所被解开。</span><br><span class="line"></span><br><span class="line"># 释放</span><br><span class="line">mutex.release()</span><br></pre></td></tr></table></figure>
<p> 银行家算法 死锁预防 超时处理</p>
<h3 id="案例-UDP聊天器"><a href="#案例-UDP聊天器" class="headerlink" title="案例-UDP聊天器"></a>案例-UDP聊天器</h3> <figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">import socket</span><br><span class="line">import threading</span><br><span class="line"></span><br><span class="line">def recv_msg(udp_socket):</span><br><span class="line"> '''接受数据并显示'''</span><br><span class="line"> </span><br><span class="line"> # 接收数据</span><br><span class="line"> while True:</span><br><span class="line"> recv_data = udp_socket.recvfrom(1024)</span><br><span class="line"> print(recv_data)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">def send_msg(udp_socket, dest_ip, dest_port):</span><br><span class="line"> '''发送数据'''</span><br><span class="line"> </span><br><span class="line"> # 发送数据</span><br><span class="line"> while True:</span><br><span class="line"> recv_data = input()</span><br><span class="line"> udp_socket.sendto(send_data.encode("utf-8"). (dest_ip, dest_port))</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">def main():</span><br><span class="line"> '''UDP聊天器的整体控制'''</span><br><span class="line"> </span><br><span class="line"> # 1. 创建套接字</span><br><span class="line"> udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)</span><br><span class="line"> </span><br><span class="line"> # 2. 绑定本地信息</span><br><span class="line"> udp_socket.bind("",7890)</span><br><span class="line"> </span><br><span class="line"> # 3. 获取对方的IP</span><br><span class="line"> dest_ip = input(“请输入对方的IP:”)</span><br><span class="line"> dest_port = int(input("请输入对方的port:"))</span><br><span class="line"> </span><br><span class="line"> # 4. 创建两个线程,执行相应的功能</span><br><span class="line"> t_recv = threading.Thread(target=recv_msg, args=(udp_socket,))</span><br><span class="line"> t_send = threading.Thread(target=send_msg, args=(udp_socket, dest_ip, dest_port))</span><br><span class="line"> </span><br><span class="line"> t_recv.start()</span><br><span class="line"> t_send.start()</span><br><span class="line"> </span><br><span class="line"> </span><br><span class="line">if __name__ == "__main__":</span><br><span class="line"> main()</span><br></pre></td></tr></table></figure>
]]></content>
<tags>
<tag>python</tag>
</tags>
</entry>
<entry>
<title>python进程</title>
<url>/2020/03/06/02-%E5%A4%9A%E4%BB%BB%E5%8A%A1-%E8%BF%9B%E7%A8%8B/</url>
<content><![CDATA[<h4 id="进程和线程的区别"><a href="#进程和线程的区别" class="headerlink" title="进程和线程的区别"></a>进程和线程的区别</h4><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">import multiprocessing</span><br><span class="line"></span><br><span class="line">def test()</span><br><span class="line"> pass</span><br><span class="line"></span><br><span class="line">p1 = multiprocessing.Process(target=test)</span><br><span class="line"></span><br><span class="line">p1.start()</span><br></pre></td></tr></table></figure>
<p><strong>进程:</strong></p>
<ol>
<li>程序运行起来就是进程 </li>
<li>是资源分配的单位</li>
<li>进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的执行效率</li>
</ol>
<p><strong>线程:</strong></p>
<ol>
<li>线程是进程中执行具体操作的个体 </li>
<li>是任务调度的单位</li>
<li>线程运行开销小,但不利于资源的管理和保护,进程正相反</li>
<li>线程不能够独立执行,必须依存在进程中</li>
<li>可以将进程理解为工厂中的一条流水线,而其中的线程就是这个流水线上的工人</li>
</ol>
<h4 id="通过队列完成进程间的通信"><a href="#通过队列完成进程间的通信" class="headerlink" title="通过队列完成进程间的通信"></a>通过队列完成进程间的通信</h4><p>队列:先进先出</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">from multiprocessing import Queue</span><br><span class="line"></span><br><span class="line"># 初始化一个Queue对象</span><br><span class="line">q=Queue(3) # 最多可几收三条put信息</span><br><span class="line"></span><br><span class="line"># 往队列中放数据</span><br><span class="line">q.put('message1') # 数据类型任意</span><br><span class="line">q.put('message2')</span><br><span class="line">q.put('message3')</span><br><span class="line">q.put('message4') # 会阻塞,因为队列满了</span><br><span class="line"></span><br><span class="line"># 判断队列状态</span><br><span class="line">q.full() # False 表示队列不满</span><br><span class="line">q.full() # True 表示队列满了</span><br><span class="line">q.empty() # False 表示队列不为空</span><br><span class="line">q.empty() # True 表示队列为空</span><br><span class="line"></span><br><span class="line"># 从队列取数据</span><br><span class="line">q.get() # 先进后出</span><br><span class="line">q.get_nowait() # 不等待取数据</span><br></pre></td></tr></table></figure>
<p><strong>作用:</strong><br>通过队列解耦合,进程A下载数据,进程B处理数据,互不影响</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">import multiprocessing</span><br><span class="line"></span><br><span class="line">def download_from_web():</span><br><span class="line"> # 模拟从网上下载数据</span><br><span class="line"> data == [11, 22, 33, 44]</span><br><span class="line"></span><br><span class="line"> # 像队列中写入数据</span><br><span class="line"> from temp in data:</span><br><span class="line"> q.put()</span><br><span class="line"> </span><br><span class="line"> print("下载器已经下载完了数据并且存入到队列中。")</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">def analysis_data():</span><br><span class="line"> '''数据处理'''</span><br><span class="line"> waitting_analysis_data = list()</span><br><span class="line"> # 从队列中取数据</span><br><span class="line"> while True:</span><br><span class="line"> data = q.get()</span><br><span class="line"> waitting_analysis_data.append(data)</span><br><span class="line"> </span><br><span class="line"> if q.empty():</span><br><span class="line"> break</span><br><span class="line"></span><br><span class="line"> # 模拟数据处理</span><br><span class="line"> print(waitting_analysis_data)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">def main()</span><br><span class="line"> # 1. 创建一个队列</span><br><span class="line"> q = multiprocessing.Queue()</span><br><span class="line"> </span><br><span class="line"> # 2. 创建多个进程,将队列的应用当作实参进行传递到里面</span><br><span class="line"> p1 = multiprocessing.Process(target=download_from_web, args=(q,))</span><br><span class="line"> p2 = multiprocessing.Process(target=analysis_data, argd=(q,))</span><br><span class="line"></span><br><span class="line"> p1.start()</span><br><span class="line"> p2.start()</span><br><span class="line"> </span><br><span class="line">if __name__ == "__main__":</span><br><span class="line"> main()</span><br></pre></td></tr></table></figure>
<h4 id="进程池Pool"><a href="#进程池Pool" class="headerlink" title="进程池Pool"></a>进程池Pool</h4><p>重复利用进程池中的进程<br>进程数过多时,采用进程池减少进程的数量</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">from multiprocessing import Pool</span><br><span class="line"></span><br><span class="line">po = Pool(3) # 定义一个进程池,最大进程数为3</span><br><span class="line">po.apply_async(worker,(1,)) #要调用的目标,(传递给目标的参数元组,))</span><br><span class="line">po.close() # 关闭进程池</span><br><span class="line">po.jion() # 等待po中所有子进程完成,必须放在close()前面</span><br></pre></td></tr></table></figure>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">from multiprocessing import Pool</span><br><span class="line">import os, time, random</span><br><span class="line"></span><br><span class="line">def worker(msg):</span><br><span class="line"> t_start = time.time()</span><br><span class="line"> print("%s开始执行,进程号为%d" % (msg,os.getpid()))</span><br><span class="line"> # random.random() 随机生成0-1之间的浮点数</span><br><span class="line"> time.sleep(random.random()*2)</span><br><span class="line"> t_stop = time.time()</span><br><span class="line"> print(msg,"执行完毕,好事%0.2f" % (t_stop-t_start))</span><br><span class="line"> </span><br><span class="line">po = Pool(3) # 定义一个进程池,最大进程数3</span><br><span class="line">for i in range(0,10):</span><br><span class="line"> # Pool().apply_async(要调用的目标,(传递给目标的参数元组,))</span><br><span class="line"> # 每次循环将会用空闲出来的子进程去调用目标</span><br><span class="line"> po.apply_async(worker,(i,))</span><br><span class="line"> </span><br><span class="line">print("----start----")</span><br><span class="line">po.close() # 关闭进程池,关闭后po不再接收新的请求</span><br><span class="line">po.join() # 等待po中所有子进程执行完成,必须放在close语句之后</span><br><span class="line">print("----end----")</span><br></pre></td></tr></table></figure>
<h4 id="案例-实现copy"><a href="#案例-实现copy" class="headerlink" title="案例 实现copy"></a>案例 实现copy</h4><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">import multiprocessing</span><br><span class="line">import os</span><br><span class="line"></span><br><span class="line">def copy_file(q, file_name, old_folder_name, new_folder_name):</span><br><span class="line"> '''完成文件的复制'''</span><br><span class="line"> old_f = open(old_folder_name + "/" + file_name, "rb")</span><br><span class="line"> content = old_f.read()</span><br><span class="line"> old_f.close()</span><br><span class="line"> </span><br><span class="line"> new_f = open(new_folder_name + "/" + file_name, "wb")</span><br><span class="line"> content = new_f.write()</span><br><span class="line"> new_f.close()</span><br><span class="line"> </span><br><span class="line"> # 如果拷贝完了文件,那么就向队列中写入一个消息表示已经完成</span><br><span class="line"> q.put(file_name)</span><br><span class="line"> </span><br><span class="line">def main():</span><br><span class="line"> # 1. 获取用户要copy的文件夹的名字</span><br><span class="line"> old_folder_name = input("请输入要copy的文件夹的名字:")</span><br><span class="line"> </span><br><span class="line"> # 2. 创建一个新的文件夹</span><br><span class="line"> try:</span><br><span class="line"> new_folder_name = old_folder_name + "[复件]"</span><br><span class="line"> os.mkdir(new_folder_name)</span><br><span class="line"> except:</span><br><span class="line"> pass</span><br><span class="line"></span><br><span class="line"> # 3. 获取文件夹的所有的待copy的文件名字 listdir()</span><br><span class="line"> file_names = os.listdir(old_folder_name)</span><br><span class="line"> # print(file_names)</span><br><span class="line"> </span><br><span class="line"> # 4. 创建进程池 主进程负责往进程池添加 进程池负责拷贝</span><br><span class="line"> po = multiprocessing.Pool(5)</span><br><span class="line"> </span><br><span class="line"> # 5. 创建一个队列</span><br><span class="line"> q = multiprocessing.Manager().Queue()</span><br><span class="line"> </span><br><span class="line"> </span><br><span class="line"> # 6. 向进程池中添加copy文件的任务</span><br><span class="line"> for file_name in file_names:</span><br><span class="line"> po.apply_async(q, copy_file,args=(file_name, old_folder_name. new_folder_name)</span><br><span class="line"> # 进程池中的进程出错时不会抛出异常。</span><br><span class="line"> po.close()</span><br><span class="line"> # po.join()</span><br><span class="line"> all_file_num = len(file_names) # 所有文件的个数</span><br><span class="line"> copy_ok_num = 0</span><br><span class="line"> while True:</span><br><span class="line"> file_name = q.get()</span><br><span class="line"> # print("已经完成copy: %s" % file_name)</span><br><span class="line"> copy_ok_num += 1</span><br><span class="line"> print("\r拷贝的进度为:%.2f%%" % (copy_on_num*100 // all_file_num),end="")</span><br><span class="line"> if copy_ok_num >= all_file_num:</span><br><span class="line"> break</span><br><span class="line"> </span><br><span class="line"> print()</span><br><span class="line"> </span><br><span class="line"> </span><br><span class="line">if __name__ == "__main__":</span><br><span class="line"> main()</span><br></pre></td></tr></table></figure>]]></content>
<tags>
<tag>python</tag>
</tags>
</entry>
<entry>
<title>简单web服务器python实现</title>
<url>/2020/03/06/03-%E7%AE%80%E5%8D%95web%E6%9C%8D%E5%8A%A1%E5%99%A8%E5%AE%9E%E7%8E%B0/</url>
<content><![CDATA[<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">import socket</span><br><span class="line">import re</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">def service_client(new_socket):</span><br><span class="line"> '''为这个客户端返回数据'''</span><br><span class="line"> </span><br><span class="line"> # 1. 接受浏览器发送过来的请求,即http请求</span><br><span class="line"> # GET / HTTP/1.1</span><br><span class="line"> # .....</span><br><span class="line"> request = new_socket.recv(1024).decode('utf-8')</span><br><span class="line"> </span><br><span class="line"> request_lines = request.splitlines()</span><br><span class="line"> print(request_lines)</span><br><span class="line"> </span><br><span class="line"> file_name = ''</span><br><span class="line"> ret = re.match(r"[^/]+(/[^ ]*)", request_lines[0])</span><br><span class="line"> if ret:</span><br><span class="line"> file_name = re.group(1)</span><br><span class="line"> if file_name == "/":</span><br><span class="line"> file_name = "/index.html"</span><br><span class="line"> </span><br><span class="line"> </span><br><span class="line"> # 2. 返回http格式的数据,给浏览器</span><br><span class="line"> </span><br><span class="line"> try:</span><br><span class="line"> f = open("./html/index.html","rb")</span><br><span class="line"> except:</span><br><span class="line"> response = 'HTTP/1.1 404 NOT FOUND\r\n'</span><br><span class="line"> response += '\r\n'</span><br><span class="line"> response += '----file not found----'</span><br><span class="line"> new_socket.send(response.encode('utf-8'))</span><br><span class="line"> else:</span><br><span class="line"> # 2.1 准备发送给浏览器的数据 ---header---</span><br><span class="line"> response = "HTTP/1.1 200 OK\r\n"</span><br><span class="line"> response += "\r\n"</span><br><span class="line"> # 2.2 准备发送给浏览器的数据 ---body---</span><br><span class="line"> html_content = f.read()</span><br><span class="line"> f.close()</span><br><span class="line"> </span><br><span class="line"> # 3. 发送数据</span><br><span class="line"> # 3.1 发送header</span><br><span class="line"> new_socket.send(response.encode("utf-8"))</span><br><span class="line"> # 3.2 发送body</span><br><span class="line"> new_socket.send(html_content)</span><br><span class="line"> </span><br><span class="line"> # 4. 关闭套接字</span><br><span class="line"> new_socket.close()</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">def main():</span><br><span class="line"> """用来完成整体的控制"""</span><br><span class="line"> # 1. 创建套接字</span><br><span class="line"> tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)</span><br><span class="line"> </span><br><span class="line"> # 2. 绑定端口</span><br><span class="line"> tcp_server_socket.bind(("", 7890))</span><br><span class="line"> </span><br><span class="line"> # 3. 变为监听套接字</span><br><span class="line"> tcp_server_socket.listen(128)</span><br><span class="line"> </span><br><span class="line"> while True:</span><br><span class="line"> # 4. 等待新客户端的链接</span><br><span class="line"> new_socket, client_addr = tcp_server_socket.accept()</span><br><span class="line"> </span><br><span class="line"> # 5. 为这个客户端服务</span><br><span class="line"> service_client(new_socket)</span><br><span class="line"> </span><br><span class="line"> # 关闭监听套接字</span><br><span class="line"> tcp_server_socket.close()</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">if __name__ == "__main__":</span><br><span class="line"> main()</span><br></pre></td></tr></table></figure>
<h4 id="TCP三次握手、四次挥手"><a href="#TCP三次握手、四次挥手" class="headerlink" title="TCP三次握手、四次挥手"></a>TCP三次握手、四次挥手</h4>]]></content>
<tags>
<tag>python</tag>
</tags>
</entry>
<entry>
<title>并发web服务器python实现</title>
<url>/2020/03/06/04-%E5%B9%B6%E5%8F%91web%E6%9C%8D%E5%8A%A1%E5%99%A8%E5%AE%9E%E7%8E%B0/</url>
<content><![CDATA[<h4 id="单进程、单线程、非阻塞实现监听多个套接字"><a href="#单进程、单线程、非阻塞实现监听多个套接字" class="headerlink" title="单进程、单线程、非阻塞实现监听多个套接字"></a>单进程、单线程、非阻塞实现监听多个套接字</h4><figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">import</span> socket</span><br><span class="line"><span class="keyword">import</span> time</span><br><span class="line"></span><br><span class="line">tcp_server_tcp = socket.socket(socket.AF_INET, socket.SOCK_STREAM) <span class="comment"># 创建套接字</span></span><br><span class="line">tcp_server_tcp.bind(<span class="string">""</span>,<span class="number">7890</span>) <span class="comment"># 绑定端口</span></span><br><span class="line">tcp_server_tcp.listen() <span class="comment"># 设为监听模式</span></span><br><span class="line">tcp_server_tcp.setblocking(<span class="literal">False</span>) <span class="comment"># 设置套接字为非堵塞</span></span><br><span class="line"></span><br><span class="line">client_socket_list = list()</span><br><span class="line"></span><br><span class="line"><span class="keyword">while</span> <span class="literal">True</span>:</span><br><span class="line"> time.sleep(<span class="number">0.5</span>)</span><br><span class="line"></span><br><span class="line"> <span class="keyword">try</span>:</span><br><span class="line"> new_socket, new_addr = tcp_server_tcp.accept()</span><br><span class="line"> <span class="keyword">except</span> Exception <span class="keyword">as</span> ret:</span><br><span class="line"> print(<span class="string">"---没有新的客户端到来---"</span>)</span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> print(<span class="string">"---只要没有产生异常,那么也就意味着 来了一个新的客户端---"</span>)</span><br><span class="line"> new_socket.setblocking(<span class="literal">False</span>) <span class="comment"># 设置套接字为非堵塞</span></span><br><span class="line"> client_socket_list.append(new_socket)</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">for</span> client_socket <span class="keyword">in</span> client_socket_list:</span><br><span class="line"> <span class="keyword">try</span>:</span><br><span class="line"> client_socket.recv(<span class="number">1024</span>) </span><br><span class="line"> <span class="keyword">except</span> Exception <span class="keyword">as</span> ret:</span><br><span class="line"> print(<span class="string">"---这个客户端没有发送过来数据---"</span>)</span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> <span class="keyword">if</span> recv_data:</span><br><span class="line"> <span class="comment"># 对方发送过来数据</span></span><br><span class="line"> print(<span class="string">"---客户端发送过来了数据---"</span>)</span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> <span class="comment"># 对方调用close recv_data返回值为空</span></span><br><span class="line"> client_socket_list.remove(client_socket)</span><br><span class="line"> client_socket.close()</span><br><span class="line"> print(<span class="string">"客户端已经关闭。"</span>)</span><br></pre></td></tr></table></figure>
<h4 id="短连接-和-长连接"><a href="#短连接-和-长连接" class="headerlink" title="短连接 和 长连接"></a>短连接 和 长连接</h4><p><strong>长连接:</strong> 一个套接字获取多次数据<br><strong>短连接:</strong> 一个套接字只能获取一次数据</p>
<p>HTTP/1.0 是短连接<br>HTTP/1.1 是长连接</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">import socket</span><br><span class="line">import re</span><br><span class="line"></span><br><span class="line">def service_client(new_socket, request):</span><br><span class="line"> '''为这个客户端返回数据'''</span><br><span class="line"> # 1. 处理浏览器发送过来的数据</span><br><span class="line"> request_lines = requests.splitlines()</span><br><span class="line"> print("")</span><br><span class="line"> print(">"*20)</span><br><span class="line"> print(request_lines)</span><br><span class="line"> </span><br><span class="line"> file_name = ""</span><br><span class="line"> ret = re.match(r"[^/]+(/[^ ]*)",request_lines[0])</span><br><span class="line"> if ret:</span><br><span class="line"> file_name = ret.group()</span><br><span class="line"> if file_name == "/":</span><br><span class="line"> file_name = "/index.html"</span><br><span class="line"> </span><br><span class="line"> # 2. 返回http格式的数据,给浏览器</span><br><span class="line"> </span><br><span class="line"> try:</span><br><span class="line"> f = open("./html" + file_name, "rb")</span><br><span class="line"> except:</span><br><span class="line"> response = 'HTTP/1.1 404 NOT FOUND\r\n' </span><br><span class="line"> response += '\r\n' </span><br><span class="line"> response += '------file not found------'</span><br><span class="line"> new_socket.send(response.encode('utf-8'))</span><br><span class="line"> else:</span><br><span class="line"> html_content = f.read()</span><br><span class="line"> f.close()</span><br><span class="line"></span><br><span class="line"> response_body = html_content</span><br><span class="line"> </span><br><span class="line"> response_header = 'HTTP/1.1 200 OK\r\n'</span><br><span class="line"> response_header += 'Content-Length:%d\r\n' % len(response_body)</span><br><span class="line"> response_header += '\r\n'</span><br><span class="line"></span><br><span class="line"> response = response_header.encode('utf-8') + response_body</span><br><span class="line"> </span><br><span class="line"> new_socket.send(response)</span><br><span class="line"></span><br><span class="line">def main():</span><br><span class="line"> '''用来完成整体的控制'''</span><br><span class="line"> # 1. 创建套接字</span><br><span class="line"> tcp_server_tcp = socket.socket(socket.AF_INET, socket.SOCK_STREAM)</span><br><span class="line"> tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)</span><br><span class="line"> </span><br><span class="line"> # 2. 绑定</span><br><span class="line"> tcp_server_socket.bind(("", 7890))</span><br><span class="line"> </span><br><span class="line"> # 3. 变为监听套接字</span><br><span class="line"> tcp_server_socket.listen(128)</span><br><span class="line"> tcp_server_socket.setblocking(False) # 设为非阻塞</span><br><span class="line"> </span><br><span class="line"> # --------------</span><br><span class="line"> # 创建一个epoll对象</span><br><span class="line"> epl = select.epoll()</span><br><span class="line"> </span><br><span class="line"> # 将监听套接字对应的文件描述符fd注册到epoll中</span><br><span class="line"> epl.register(tcp_server_socket.fileno(), select.EPOLLIN)</span><br><span class="line"> # --------------</span><br><span class="line"> client_socket_list = list()</span><br><span class="line"> while True:</span><br><span class="line"> # 4. 等待新客户端的链接</span><br><span class="line"> try:</span><br><span class="line"> new_socket, client_addr = tcp_server_socket.accept()</span><br><span class="line"> except Exception as ret:</span><br><span class="line"> pass</span><br><span class="line"> else:</span><br><span class="line"> new_socket.setblocking(False)</span><br><span class="line"> client_socket_list.append(new_socket)</span><br><span class="line"> </span><br><span class="line"> for client_socket in client_socket_list:</span><br><span class="line"> try:</span><br><span class="line"> recv_data = client_socket.recv(1024).decode('utf-8')</span><br><span class="line"> except Exception as ret:</span><br><span class="line"> pass</span><br><span class="line"> else:</span><br><span class="line"> if recv_data:</span><br><span class="line"> service_client(client_socket, recv_data)</span><br><span class="line"> else:</span><br><span class="line"> client_socket.close()</span><br><span class="line"> client_socket_list.remove(client_socket)</span><br><span class="line"> </span><br><span class="line"> # 关闭套接字</span><br><span class="line"> tcp_server_socket.close()</span><br></pre></td></tr></table></figure>
<h4 id="epoll"><a href="#epoll" class="headerlink" title="epoll"></a>epoll</h4><p>单进程单线程多任务 由应用程序采用轮询实现<br>epoll是事件通知类型,由内核实现</p>
]]></content>
<tags>
<tag>python</tag>
</tags>
</entry>
<entry>
<title>gitee折腾记录</title>
<url>/2020/03/06/gitee%E6%8A%98%E8%85%BE%E8%AE%B0%E5%BD%95/</url>
<content><![CDATA[<h1 id="gitee-com-介绍"><a href="#gitee-com-介绍" class="headerlink" title="gitee.com 介绍"></a>gitee.com 介绍</h1><p>码云(gitee.com) 代码托管·协作开发平台,开发者近 400 万,托管项目超过 600 万,汇聚几乎所有本土原创开源项目,并于 2016 年推出企业版,提供企业级代码托管服务,成为开发领域领先的 SaaS 服务提供商。</p>
<h1 id="1-注册-gitee-com-账户"><a href="#1-注册-gitee-com-账户" class="headerlink" title="1. 注册 gitee.com 账户"></a>1. 注册 gitee.com 账户</h1><blockquote>
<p>打开 <a href="https://gitee.com/" target="_blank" rel="noopener">gitee官网</a>, 注册账号并登录</p>
</blockquote>
<h1 id="2-创建仓库"><a href="#2-创建仓库" class="headerlink" title="2. 创建仓库"></a>2. 创建仓库</h1><blockquote>
<p>创建仓库 <img src="https://pic.downk.cc/item/5e60e39498271cb2b8b33976.jpg" alt=""></p>
</blockquote>
<blockquote>
<p>键入仓库信息 <img src="https://pic.downk.cc/item/5e60e41598271cb2b8b378d9.jpg" alt=""></p>
</blockquote>
<ul>
<li>仓库名称:任意</li>
<li>归属/路径:保持默认即可</li>
<li>仓库介绍:非必填</li>
<li>是否开源:<ul>
<li>私有:拉取代码需要验证用户名和密码</li>
<li>公开:任何人无需验证身份即可直接拉取代码</li>
</ul>
</li>
<li>选择语言:项目代码的语言</li>
<li>添加.gitignore: 该文件用于指定上传代码时不包含项目内的某些文件,譬如包含密码的文件、缓存、项目环境、日志等无用文件,</li>
<li><input disabled="" type="checkbox"> 使用Readme 文件初始化这个仓库:用于介绍项目的文件,建议使用</li>
<li><input disabled="" type="checkbox"> 使用Issue 模板文件初始化这个仓库:初次配置可忽略</li>
<li><input disabled="" type="checkbox"> 使用Pull Request模板文件初始化这个仓库:初次配置可忽略</li>
<li>选择分支模型:初始化仓库时默认只有一个master分支,根据需要设定</li>
</ul>
<blockquote>
<p>点击<img src="https://pic.downk.cc/item/5e60e7c098271cb2b8b5272d.jpg" alt=""></p>
</blockquote>
<blockquote>
<p>仓库首页 <img src="https://pic.downk.cc/item/5e60e98198271cb2b8b60b38.jpg" alt=""></p>
</blockquote>
<h1 id="3-创建本地仓库-拉取远程仓库"><a href="#3-创建本地仓库-拉取远程仓库" class="headerlink" title="3. 创建本地仓库/拉取远程仓库"></a>3. 创建本地仓库/拉取远程仓库</h1><h2 id="3-1-创建本地仓库"><a href="#3-1-创建本地仓库" class="headerlink" title="3.1 创建本地仓库"></a>3.1 创建本地仓库</h2><blockquote>
<p>在bash环境下操作</p>
</blockquote>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 创建目录并切换到该目录</span></span><br><span class="line">$ mkdir local_repo && <span class="built_in">cd</span> local_repo</span><br><span class="line"></span><br><span class="line"><span class="comment"># 初始化仓库</span></span><br><span class="line">$ git init</span><br></pre></td></tr></table></figure>
<h2 id="3-2-拉取远程仓库"><a href="#3-2-拉取远程仓库" class="headerlink" title="3.2 拉取远程仓库"></a>3.2 拉取远程仓库</h2><blockquote>
<p>获取远程仓库链接</p>
</blockquote>
<p><img src="https://pic.downk.cc/item/5e60ea9a98271cb2b8b6bf3b.jpg" alt=""></p>
<blockquote>
<p>拉取代码</p>
</blockquote>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 拉取远程仓库到本地目录learn_git</span></span><br><span class="line">$ git <span class="built_in">clone</span> https://gitee.com/daydaychen/learn_git.git learn_git</span><br><span class="line">Cloning into <span class="string">'learn_git'</span>...</span><br><span class="line">remote: Enumerating objects: 4, <span class="keyword">done</span>.</span><br><span class="line">remote: Counting objects: 100% (4/4), <span class="keyword">done</span>.</span><br><span class="line">remote: Compressing objects: 100% (4/4), <span class="keyword">done</span>.</span><br><span class="line">remote: Total 4 (delta 0), reused 0 (delta 0)</span><br><span class="line">Unpacking objects: 100% (4/4), <span class="keyword">done</span>.</span><br><span class="line">Checking connectivity... <span class="keyword">done</span>.</span><br></pre></td></tr></table></figure>
<h1 id="4-跟踪文件-取消跟踪"><a href="#4-跟踪文件-取消跟踪" class="headerlink" title="4. 跟踪文件/取消跟踪"></a>4. 跟踪文件/取消跟踪</h1><blockquote>
</blockquote>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 当前目录下有两个文件</span></span><br><span class="line">dayday:learn_git$ ls</span><br><span class="line">total 8.0K</span><br><span class="line">-rw-rw-rw- 1 dayday dayday 953 Mar 5 20:06 README.en.md</span><br><span class="line">-rw-rw-rw- 1 dayday dayday 1.3K Mar 5 20:06 README.md</span><br><span class="line"></span><br><span class="line"><span class="comment"># 新建文件</span></span><br><span class="line">$ <span class="built_in">echo</span> <span class="string">"hello world"</span> > day1_work.md</span><br><span class="line"></span><br><span class="line"><span class="comment"># 查看工作区状态</span></span><br><span class="line">dayday:learn_git$ git status</span><br><span class="line">On branch master</span><br><span class="line">Your branch is up-to-date with <span class="string">'origin/master'</span>.</span><br><span class="line">Untracked files: <span class="comment"># <-- 有以下文件未跟踪</span></span><br><span class="line"> (use <span class="string">"git add <file>..."</span> to include <span class="keyword">in</span> what will be committed)</span><br><span class="line"></span><br><span class="line"> day1_work.md</span><br><span class="line"></span><br><span class="line">nothing added to commit but untracked files present (use <span class="string">"git add"</span> to track)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 跟踪day1_work.md</span></span><br><span class="line">$ git add day1_work.md</span><br><span class="line">On branch master</span><br><span class="line">Your branch is up-to-date with <span class="string">'origin/master'</span>.</span><br><span class="line">Changes to be committed: <span class="comment"># <-- 有以下文件已修改未提交</span></span><br><span class="line"> (use <span class="string">"git reset HEAD <file>..."</span> to unstage)</span><br><span class="line"> new file: day1_work.md</span><br><span class="line"></span><br><span class="line"><span class="comment"># 提交修改</span></span><br><span class="line">dayday:learn_git$ git commit -m <span class="string">'first commit'</span></span><br><span class="line">[master b52affd] first commit</span><br><span class="line"> 1 file changed, 1 insertion(+)</span><br><span class="line"> create mode 100644 day1_work.md</span><br><span class="line"></span><br><span class="line"><span class="comment"># 查看工作区状态</span></span><br><span class="line">dayday:learn_git$ git status</span><br><span class="line">On branch master</span><br><span class="line">Your branch is ahead of <span class="string">'origin/master'</span> by 1 commit.</span><br><span class="line">(use <span class="string">"git push"</span> to publish your <span class="built_in">local</span> commits)</span><br><span class="line">nothing to commit, working directory clean</span><br></pre></td></tr></table></figure>
<h1 id="5-创建分支-切换分支-删除分支"><a href="#5-创建分支-切换分支-删除分支" class="headerlink" title="5. 创建分支/切换分支/删除分支"></a>5. 创建分支/切换分支/删除分支</h1><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 列出所有分支</span></span><br><span class="line">dayday:learn_git$ git branch --list</span><br><span class="line">* master</span><br><span class="line"></span><br><span class="line"><span class="comment"># 创建dev分支</span></span><br><span class="line">dayday:learn_git$ git branch dev</span><br><span class="line">dayday:learn_git$ git branch --list</span><br><span class="line">dev</span><br><span class="line">* master</span><br><span class="line"></span><br><span class="line"><span class="comment"># 切换到dev分支</span></span><br><span class="line">dayday:learn_git$ git checkout dev</span><br><span class="line">Switched to branch <span class="string">'dev'</span></span><br><span class="line">dayday:learn_git$ git branch --list</span><br><span class="line">* dev</span><br><span class="line">master</span><br><span class="line"></span><br><span class="line"><span class="comment"># 切换回master分支</span></span><br><span class="line">dayday:learn_git$ git checkout master</span><br><span class="line">Switched to branch <span class="string">'master'</span></span><br><span class="line">Your branch is ahead of <span class="string">'origin/master'</span> by 1 commit.</span><br><span class="line">(use <span class="string">"git push"</span> to publish your <span class="built_in">local</span> commits) </span><br><span class="line"></span><br><span class="line"><span class="comment"># 删除dev分支</span></span><br><span class="line">dayday:learn_git$ git branch -d dev</span><br><span class="line">Deleted branch dev (was b52affd).</span><br></pre></td></tr></table></figure>
<h1 id="8-合并分支"><a href="#8-合并分支" class="headerlink" title="8. 合并分支"></a>8. 合并分支</h1><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 创建dev分支并切换过去</span></span><br><span class="line">dayday:learn_git$ git checkout -b dev</span><br><span class="line">Switched to a new branch <span class="string">'dev'</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 新建文件</span></span><br><span class="line">dayday:learn_git$ <span class="built_in">echo</span> <span class="string">"dev branch working..."</span> > dev.md</span><br><span class="line"></span><br><span class="line"><span class="comment"># 查看dev分支工作区</span></span><br><span class="line">dayday:learn_git$ ls</span><br><span class="line">total 8.0K</span><br><span class="line">-rw-rw-rw- 1 dayday dayday 953 Mar 5 20:06 README.en.md</span><br><span class="line">-rw-rw-rw- 1 dayday dayday 1.3K Mar 5 20:06 README.md</span><br><span class="line">-rw-rw-rw- 1 dayday dayday 12 Mar 5 20:12 day1_work.md</span><br><span class="line">-rw-rw-rw- 1 dayday dayday 22 Mar 5 20:44 dev.md</span><br><span class="line"></span><br><span class="line"><span class="comment"># 跟踪dev.md</span></span><br><span class="line">dayday:learn_git$ git add .</span><br><span class="line"></span><br><span class="line"><span class="comment"># 提交更改</span></span><br><span class="line">dayday:learn_git$ git commit -m <span class="string">'add dev.md'</span></span><br><span class="line">[dev a6986a9] add dev.md</span><br><span class="line">1 file changed, 1 insertion(+)</span><br><span class="line">create mode 100644 dev.md</span><br><span class="line"></span><br><span class="line"><span class="comment"># 切换到master分支</span></span><br><span class="line">dayday:learn_git$ git checkout master</span><br><span class="line">Switched to branch <span class="string">'master'</span></span><br><span class="line">Your branch is ahead of <span class="string">'origin/master'</span> by 1 commit.</span><br><span class="line">(use <span class="string">"git push"</span> to publish your <span class="built_in">local</span> commits) </span><br><span class="line"></span><br><span class="line">dayday:learn_git$ git branch</span><br><span class="line">dev</span><br><span class="line">* master</span><br><span class="line"></span><br><span class="line"><span class="comment"># 查看master分支工作区</span></span><br><span class="line">dayday:learn_git$ ls</span><br><span class="line">total 8.0K</span><br><span class="line">-rw-rw-rw- 1 dayday dayday 953 Mar 5 20:06 README.en.md</span><br><span class="line">-rw-rw-rw- 1 dayday dayday 1.3K Mar 5 20:06 README.md</span><br><span class="line">-rw-rw-rw- 1 dayday dayday 12 Mar 5 20:12 day1_work.md</span><br><span class="line"></span><br><span class="line"><span class="comment"># 比较master分支和dev分支的区别</span></span><br><span class="line">dayday:learn_git$ git diff master dev</span><br><span class="line">diff --git a/dev.md b/dev.md</span><br><span class="line">new file mode 100644</span><br><span class="line">index 0000000..c38f76b</span><br><span class="line">--- /dev/null</span><br><span class="line">+++ b/dev.md</span><br><span class="line">@@ -0,0 +1 @@</span><br><span class="line">+dev branch working...</span><br><span class="line"></span><br><span class="line"><span class="comment"># 合并dev分支到master分支</span></span><br><span class="line">dayday:learn_git$ git merge dev</span><br><span class="line">Updating b52affd..a6986a9 Fast-forward</span><br><span class="line">dev.md | 1 + 1 file changed, 1 insertion(+)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 查看master分支工作区</span></span><br><span class="line">create mode 100644 dev.mddayday:learn_git$ ls</span><br><span class="line">total 8.0K</span><br><span class="line">-rw-rw-rw- 1 dayday dayday 953 Mar 5 20:06 README.en.md</span><br><span class="line">-rw-rw-rw- 1 dayday dayday 1.3K Mar 5 20:06 README.md</span><br><span class="line">-rw-rw-rw- 1 dayday dayday 12 Mar 5 20:12 day1_work.md</span><br><span class="line">-rw-rw-rw- 1 dayday dayday 22 Mar 5 20:53 dev.md</span><br></pre></td></tr></table></figure>
<h1 id="11-推送的远程仓库"><a href="#11-推送的远程仓库" class="headerlink" title="11. 推送的远程仓库"></a>11. 推送的远程仓库</h1><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 查看工作区状态</span></span><br><span class="line">dayday:learn_git$ git status</span><br><span class="line">On branch master</span><br><span class="line">Your branch is ahead of <span class="string">'origin/master'</span> by 2 commits.</span><br><span class="line">(use <span class="string">"git push"</span> to publish your <span class="built_in">local</span> commits)</span><br><span class="line">nothing to commit, working directory clean </span><br><span class="line"></span><br><span class="line"><span class="comment"># 推送到远程仓库</span></span><br><span class="line">dayday:learn_git$ git push origin master</span><br><span class="line">Username <span class="keyword">for</span> <span class="string">'https://gitee.com'</span>: daydaychen</span><br><span class="line">Password <span class="keyword">for</span> <span class="string">'https://daydaychen@gitee.com'</span>:</span><br><span class="line">Counting objects: 6, <span class="keyword">done</span>.</span><br><span class="line">Delta compression using up to 4 threads.</span><br><span class="line">Compressing objects: 100% (4/4), <span class="keyword">done</span>.</span><br><span class="line">Writing objects: 100% (6/6), 537 bytes | 0 bytes/s, <span class="keyword">done</span>.</span><br><span class="line">Total 6 (delta 1), reused 0 (delta 0)</span><br><span class="line">remote: Powered by GITEE.COM [GNK-3.8]</span><br><span class="line">To https://gitee.com/daydaychen/learn_git.git</span><br><span class="line">4618244..a6986a9 master -> master</span><br></pre></td></tr></table></figure>
<h1 id="12-向一个项目贡献"><a href="#12-向一个项目贡献" class="headerlink" title="12 向一个项目贡献"></a>12 向一个项目贡献</h1><blockquote>
<p>fork 仓库</p>
</blockquote>
<blockquote>
<p>拉取远程仓库到本地</p>
</blockquote>
<blockquote>
<p>提交修改并推送到远程仓库</p>
</blockquote>
<blockquote>
<p>提交Pull Request</p>
</blockquote>
<h1 id="13-仓库设置说明"><a href="#13-仓库设置说明" class="headerlink" title="13 仓库设置说明"></a>13 仓库设置说明</h1><blockquote>
<p>仓库成员管理</p>
</blockquote>
<p>添加成员,按角色分配仓库的读写权限</p>
<blockquote>
<p>部署公钥管理</p>
</blockquote>
<p>该操作通过非对称加密密钥对对仓库进行访问验证,无需每次输入用户名密码</p>
<p><img src="https://pic.downk.cc/item/5e60fefc98271cb2b8c187aa.jpg" alt=""></p>
]]></content>
<tags>
<tag>gitee</tag>
</tags>
</entry>
<entry>
<title>Hello World</title>
<url>/2020/03/06/hello-world/</url>
<content><![CDATA[<p>Welcome to <a href="https://hexo.io/" target="_blank" rel="noopener">Hexo</a>! This is your very first post. Check <a href="https://hexo.io/docs/" target="_blank" rel="noopener">documentation</a> for more info. If you get any problems when using Hexo, you can find the answer in <a href="https://hexo.io/docs/troubleshooting.html" target="_blank" rel="noopener">troubleshooting</a> or you can ask me on <a href="https://github.com/hexojs/hexo/issues" target="_blank" rel="noopener">GitHub</a>.</p>
<h2 id="Quick-Start"><a href="#Quick-Start" class="headerlink" title="Quick Start"></a>Quick Start</h2><h3 id="Create-a-new-post"><a href="#Create-a-new-post" class="headerlink" title="Create a new post"></a>Create a new post</h3><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ hexo new <span class="string">"My New Post"</span></span><br></pre></td></tr></table></figure>
<p>More info: <a href="https://hexo.io/docs/writing.html" target="_blank" rel="noopener">Writing</a></p>
<a id="more"></a>
<h3 id="Run-server"><a href="#Run-server" class="headerlink" title="Run server"></a>Run server</h3><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ hexo server</span><br></pre></td></tr></table></figure>
<p>More info: <a href="https://hexo.io/docs/server.html" target="_blank" rel="noopener">Server</a></p>
<h3 id="Generate-static-files"><a href="#Generate-static-files" class="headerlink" title="Generate static files"></a>Generate static files</h3><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ hexo generate</span><br></pre></td></tr></table></figure>
<p>More info: <a href="https://hexo.io/docs/generating.html" target="_blank" rel="noopener">Generating</a></p>
<h3 id="Deploy-to-remote-sites"><a href="#Deploy-to-remote-sites" class="headerlink" title="Deploy to remote sites"></a>Deploy to remote sites</h3><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ hexo deploy</span><br></pre></td></tr></table></figure>
<p>More info: <a href="https://hexo.io/docs/one-command-deployment.html" target="_blank" rel="noopener">Deployment</a></p>
]]></content>
</entry>
<entry>
<title>计算机网络-传输层</title>
<url>/2020/03/06/%E4%BC%A0%E8%BE%93%E5%B1%82-over/</url>
<content><![CDATA[<p>网络层只把分组发送到目的主机,但是真正通信的并不是主机而是主机中的进程。传输层提供了进程间的逻辑通信,传输层向高层用户屏蔽了下面网络层的核心细节,使应用程序看起来像是在两个传输层实体之间有一条端到端的逻辑通信信道。</p>
<h3 id="UDP-和-TCP-特点"><a href="#UDP-和-TCP-特点" class="headerlink" title="UDP 和 TCP 特点"></a>UDP 和 TCP 特点</h3><ul>
<li>用户数据报协议 UDP(User Datagram Protocol)是无连接的,尽最大可能交付,没有拥塞控制,面向报文(对于应用程序传下来的报文不合并也不拆分,只是添加 UDP 首部),支持一对一、一对多、多对一和多对多的交互通信。</li>
<li>传输控制协议 TCP(Transmission Control Protocol)是面向连接的,提供可靠交付,有流量控制,拥塞控制,提供全双工通信,面向字节流(把应用层传下来的报文看成字节流,把字节流组织成大小不等的数据块),每一条 TCP 连接只能是点对点的(一对一)。</li>
</ul>
<h3 id="UDP-首部格式"><a href="#UDP-首部格式" class="headerlink" title="UDP 首部格式"></a>UDP 首部格式</h3><p><img src="https://ae01.alicdn.com/kf/HTB1E4TPdWWs3KVjSZFxq6yWUXXaO.jpg" alt=""></p>
<p>首部字段只有 8 个字节,包括源端口、目的端口、长度、检验和。12 字节的伪首部是为了计算检验和临时添加的。</p>
<h3 id="TCP-首部格式"><a href="#TCP-首部格式" class="headerlink" title="TCP 首部格式"></a>TCP 首部格式</h3><p><img src="https://ae01.alicdn.com/kf/HTB1w_LPdW1s3KVjSZFA760_ZXXa1.png" alt=""></p>
<ul>
<li><strong>序号</strong> :用于对字节流进行编号,例如序号为 301,表示第一个字节的编号为 301,如果携带的数据长度为 100 字节,那么下一个报文段的序号应为 401。</li>
<li><strong>确认号</strong> :期望收到的下一个报文段的序号。例如 B 正确收到 A 发送来的一个报文段,序号为 501,携带的数据长度为 200 字节,因此 B 期望下一个报文段的序号为 701,B 发送给 A 的确认报文段中确认号就为 701。</li>
<li><strong>数据偏移</strong> :指的是数据部分距离报文段起始处的偏移量,实际上指的是首部的长度。</li>
<li><strong>确认 ACK</strong> :当 ACK=1 时确认号字段有效,否则无效。TCP 规定,在连接建立后所有传送的报文段都必须把 ACK 置 1。</li>
<li><strong>同步 SYN</strong> :在连接建立时用来同步序号。当 SYN=1,ACK=0 时表示这是一个连接请求报文段。若对方同意建立连接,则响应报文中 SYN=1,ACK=1。</li>
<li>*<em>终止 FIN *</em>:用来释放一个连接,当 FIN=1 时,表示此报文段的发送方的数据已发送完毕,并要求释放连接。</li>
<li><strong>窗口</strong> :窗口值作为接收方让发送方设置其发送窗口的依据。之所以要有这个限制,是因为接收方的数据缓存空间是有限的。</li>
</ul>
<h3 id="TCP-的三次握手"><a href="#TCP-的三次握手" class="headerlink" title="TCP 的三次握手"></a>TCP 的三次握手</h3><p><img src="https://ae01.alicdn.com/kf/HTB1w_LPdW1s3KVjSZFA760_ZXXa1.png" alt=""></p>
<p>假设 A 为客户端,B 为服务器端。</p>
<ul>
<li>首先 B 处于 LISTEN(监听)状态,等待客户的连接请求。</li>
<li>A 向 B 发送连接请求报文,SYN=1,ACK=0,选择一个初始的序号 x。</li>
<li>B 收到连接请求报文,如果同意建立连接,则向 A 发送连接确认报文,SYN=1,ACK=1,确认号为 x+1,同时也选择一个初始的序号 y。</li>
<li>A 收到 B 的连接确认报文后,还要向 B 发出确认,确认号为 y+1,序号为 x+1。</li>
<li>B 收到 A 的确认后,连接建立。</li>
</ul>
<h4 id="三次握手的原因"><a href="#三次握手的原因" class="headerlink" title="三次握手的原因"></a>三次握手的原因</h4><p>第三次握手是为了防止失效的连接请求到达服务器,让服务器错误打开连接。</p>
<p>客户端发送的连接请求如果在网络中滞留,那么就会隔很长一段时间才能收到服务器端发回的连接确认。客户端等待一个超时重传时间之后,就会重新请求连接。但是这个滞留的连接请求最后还是会到达服务器,如果不进行三次握手,那么服务器就会打开两个连接。如果有第三次握手,客户端会忽略服务器之后发送的对滞留连接请求的连接确认,不进行第三次握手,因此就不会再次打开连接。</p>
<h3 id="TCP-的四次挥手"><a href="#TCP-的四次挥手" class="headerlink" title="TCP 的四次挥手"></a>TCP 的四次挥手</h3><p><img src="https://ae01.alicdn.com/kf/HTB11G2Id9SD3KVjSZFK76210VXa1.png" alt=""></p>
<p>以下描述不讨论序号和确认号,因为序号和确认号的规则比较简单。并且不讨论 ACK,因为 ACK 在连接建立之后都为 1。</p>
<ul>
<li>A 发送连接释放报文,FIN=1。</li>
<li>B 收到之后发出确认,此时 TCP 属于半关闭状态,B 能向 A 发送数据但是 A 不能向 B 发送数据。当 B 不再需要连接时,发送连接释放报文,FIN=1。</li>
<li>A 收到后发出确认,进入 TIME-WAIT 状态,等待 2 MSL(最大报文存活时间)后释放连接。</li>
<li>B 收到 A 的确认后释放连接。</li>
</ul>
<h4 id="四次挥手的原因"><a href="#四次挥手的原因" class="headerlink" title="四次挥手的原因"></a>四次挥手的原因</h4><p>客户端发送了 FIN 连接释放报文之后,服务器收到了这个报文,就进入了 CLOSE-WAIT 状态。这个状态是为了让服务器端发送还未传送完毕的数据,传送完毕之后,服务器会发送 FIN 连接释放报文。</p>
<h5 id="TIME-WAIT"><a href="#TIME-WAIT" class="headerlink" title="TIME_WAIT"></a>TIME_WAIT</h5><p>客户端收到服务器端的 FIN 豹纹后进入此状态,此时并不是直接进入CLOSED状态,还需要等待一个时间计时器设置的时间2MSL。这么做有两个理由:</p>
<ul>
<li>确保最后一个确认报文能够到达。如果 B 没收到 A 发送来的确认报文, 那么就会重新发送连接释放请求报文, A 等待一段时间就是为了处理这种情况的发生。</li>
<li>等待一段时间是为了让本连接持续时间内所产生的所有报文都从网络中消失,使得下一个新的连接不会出现旧的连接请求报文。</li>
</ul>
<h3 id="TCP-可靠传输"><a href="#TCP-可靠传输" class="headerlink" title="TCP 可靠传输"></a>TCP 可靠传输</h3><p>TCP 使用超时重传来实现可靠传输:如果一个已经发送的报文段在超时时间内没有收到确认,那么就重传这个报文段。 </p>
<p>一个报文段从发送再到接收到确认所经过的时间称为往返时间 RTT,加权平均往返时间 RTTs 计算如下:</p>
<p><img src="https://ae01.alicdn.com/kf/HTB11vzRdW1s3KVjSZFA5jX_ZXXal.gif" alt=""></p>
<p>其中,0 ≤ a < 1,RTTs 随着 a 的增加更容易受到 RTT 的影响。<br>超时时间 RTO 应该略大于 RTTs,TCP 使用的超时时间计算如下:</p>
<p><img src="https://ae01.alicdn.com/kf/HTB1HSwVbfBj_uVjSZFp5jc0SXXaR.gif" alt=""></p>
<p>其中 RTTd 为偏差的加权平均值。</p>
<h3 id="TCP-滑动窗口"><a href="#TCP-滑动窗口" class="headerlink" title="TCP 滑动窗口"></a>TCP 滑动窗口</h3><p>窗口是缓存的一部分,用来暂时存放字节流。发送方和接收方各有一个窗口,接收方通过 TCP 报文段中的窗口字段告诉发送方自己的窗口大小,发送方根据这个值和其它信息设置自己的窗口大小。</p>
<p>发送窗口内的字节都允许被发送,接收窗口内的字节都允许被接收。如果发送窗口左部的字节已经发送并且收到了确认,那么就将发送窗口向右滑动一定距离,直到左部第一个字节不是已发送并且已确认的状态;接收窗口的滑动类似,接收窗口左部字节已经发送确认并交付主机,就向右滑动接收窗口。</p>
<p>接收窗口只会对窗口内最后一个按序到达的字节进行确认,例如接收窗口已经收到的字节为 {31, 34, 35},其中 {31} 按序到达,而 {34, 35} 就不是,因此只对字节 31 进行确认。发送方得到一个字节的确认之后,就知道这个字节之前的所有字节都已经被接收。</p>
<p><img src="https://ae01.alicdn.com/kf/HTB1FXrPd8Kw3KVjSZFOq6yrDVXaY.jpg" alt=""></p>
<h3 id="TCP-流量控制"><a href="#TCP-流量控制" class="headerlink" title="TCP 流量控制"></a>TCP 流量控制</h3><p>流量控制是为了控制发送方发送速率,保证接收方来得及接收。</p>
<p>接收方发送的确认报文中的窗口字段可以用来控制发送方窗口大小,从而影响发送方的发送速率。将窗口字段设置为 0 ,则发送方不能发送数据。</p>
<h3 id="TCP-拥塞控制"><a href="#TCP-拥塞控制" class="headerlink" title="TCP 拥塞控制"></a>TCP 拥塞控制</h3><p>如果网络出现拥塞,分组将会丢失,此时发送方会继续重传,从而导致网络拥塞程度更高。因此当出现拥塞时,应当控制发送方的速率。这一点和流量控制很像,但出发点不同。流量控制是为了让接收方能来得及接收,而拥塞控制是为了降低整个网络的拥塞程度。</p>
<p><img src="https://ae01.alicdn.com/kf/HTB17THJd8iE3KVjSZFMq6zQhVXax.jpg" alt=""></p>
<p>TCP 主要通过四个算法来进行拥塞控制:慢开始、拥塞避免、快重传、快恢复。</p>
<p>发送方需要维护一个叫做拥塞窗口(cwnd)的状态变量,注意拥塞窗口与发送方窗口的区别:拥塞窗口只是一个状态变量,实际决定发送方能发送多少数据的是发送方窗口。</p>
<p>为了便于讨论,做如下假设:</p>
<ul>
<li>接收方有足够大的接收缓存,因此不会发生流量控制;</li>
<li>虽然 TCP 的窗口基于字节,但是这里设窗口的大小单位为报文段。</li>
</ul>
<p><img src="https://ae01.alicdn.com/kf/HTB1i5HKd9SD3KVjSZFK76210VXa1.png" alt=""></p>
<h4 id="1-慢开始与拥塞避免"><a href="#1-慢开始与拥塞避免" class="headerlink" title="1. 慢开始与拥塞避免"></a>1. 慢开始与拥塞避免</h4><p>发送的最初执行慢开始,令 cwnd = 1,发送方只能发送 1 个报文段;当收到确认后,将 cwnd 加倍,因此之后发送方能够发送的报文段数量为:2、4、8 …</p>
<p>注意到慢开始每个轮次都将 cwnd 加倍,这样会让 cwnd 增长速度非常快,从而使得发送方发送的速度增长速度过快,网络拥塞的可能性也就更高。设置一个慢开始门限 ssthresh,当 cwnd >= ssthresh 时,进入拥塞避免,每个轮次只将 cwnd 加 1。</p>
<p>如果出现了超时,则令 ssthresh = cwnd / 2,然后重新执行慢开始。</p>
<h4 id="2-快重传与快恢复"><a href="#2-快重传与快恢复" class="headerlink" title="2. 快重传与快恢复"></a>2. 快重传与快恢复</h4><p>在接收方,要求每次接收到报文段都应该对最后一个已收到的有序报文段进行确认。例如已经接收到 M1 和 M2,此时收到 M4,应当发送对 M2 的确认。</p>
<p>在发送方,如果收到三个重复确认,那么可以知道下一个报文段丢失,此时执行快重传,立即重传下一个报文段。例如收到三个 M2,则 M3 丢失,立即重传 M3。</p>
<p>在这种情况下,只是丢失个别报文段,而不是网络拥塞。因此执行快恢复,令 ssthresh = cwnd / 2 ,cwnd = ssthresh,注意到此时直接进入拥塞避免。</p>
<p>慢开始和快恢复的快慢指的是 cwnd 的设定值,而不是 cwnd 的增长速率。慢开始 cwnd 设定为 1,而快恢复 cwnd 设定为 ssthresh。</p>
<p><img src="https://ae01.alicdn.com/kf/HTB1XVrLd21G3KVjSZFk761K4XXak.png" alt=""></p>
]]></content>
<tags>
<tag>Internet</tag>
</tags>
</entry>
<entry>
<title>使用正则处理字幕文件</title>
<url>/2020/03/06/%E4%BD%BF%E7%94%A8%E6%AD%A3%E5%88%99%E5%A4%84%E7%90%86%E5%AD%97%E5%B9%95%E6%96%87%E4%BB%B6%EF%BC%8Cpython/</url>
<content><![CDATA[<h3 id="使用python中的re模块处理YouTube字幕文件"><a href="#使用python中的re模块处理YouTube字幕文件" class="headerlink" title="使用python中的re模块处理YouTube字幕文件"></a>使用python中的re模块处理YouTube字幕文件</h3><p>状况:18个字幕文件,编码格式Window-1254,命名规律,按数字排序</p>
<p>需求:将字幕文件中的演讲词提取出来,剔除无用的字符,并合并为一个文件</p>
<h4 id="文件命名格式"><a href="#文件命名格式" class="headerlink" title="文件命名格式"></a>文件命名格式</h4><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">ls tmp/</span><br><span class="line">total 84K</span><br><span class="line">-rw-r--r-- 1 root root 3.1K Apr 22 14:50 02-Odyssey_Plans__The_Stages_of_Life.srt</span><br><span class="line">-rw-r--r-- 1 root root 4.6K Apr 22 14:51 03-Odyssey_Plans__What_is_an_Odyssey_Plan_.srt</span><br><span class="line">-rw-r--r-- 1 root root 2.5K Apr 22 14:51 04-Odyssey_Plans__What_does_an_Odyssey_Plan_Include_.srt</span><br><span class="line">-rw-r--r-- 1 root root 2.9K Apr 22 14:52 05-Odyssey_Plans__Presentation_Format.srt</span><br><span class="line">-rw-r--r-- 1 root root 1.5K Apr 22 14:52 06-Odyssey_Plans__5-Year_Timelines.srt</span><br><span class="line">-rw-r--r-- 1 root root 1.2K Apr 22 14:53 07-Odyssey_Plans__6-Word_Title.srt</span><br><span class="line">-rw-r--r-- 1 root root 2.0K Apr 22 14:53 08-Odyssey_Plans__Designing_3_Timelines.srt</span><br><span class="line">-rw-r--r-- 1 root root 1.9K Apr 22 14:54 09-Odyssey_Plans__Building_your_10-year_timeline.srt</span><br><span class="line">-rw-r--r-- 1 root root 1.3K Apr 22 14:54 10-Odyssey_Plans__Choosing_a_Symbol.srt</span><br><span class="line">-rw-r--r-- 1 root root 3.2K Apr 22 14:54 11-Odyssey_Plans__Creating_a_Dashboard.srt</span><br><span class="line">-rw-r--r-- 1 root root 1013 Apr 22 14:54 12-Odyssey_Plans__Identifying_Questions.srt</span><br><span class="line">-rw-r--r-- 1 root root 1.6K Apr 22 14:55 13-Odyssey_Plans__Writing_a_Thank-You_note.srt</span><br><span class="line">-rw-r--r-- 1 root root 2.8K Apr 22 14:55 14-Odyssey_Plans__How_to_'Prototype'_your_Odysseys.srt</span><br><span class="line">-rw-r--r-- 1 root root 4.7K Apr 22 14:55 15-Odyssey_Plans__Prototype_Conversations_and_Experiences.srt</span><br><span class="line">-rw-r--r-- 1 root root 3.7K Apr 22 14:55 16-Odyssey_Plans__How_often_to_design_an_Odyssey_plan.srt</span><br><span class="line">-rw-r--r-- 1 root root 3.8K Apr 22 14:56 17-Odyssey_Plans__Insights_and_Takeaways.srt</span><br><span class="line">-rw-r--r-- 1 root root 3.2K Apr 24 19:55 01-Odyssey_Plans__What_are_the_Odyssey_Years_.srt</span><br><span class="line">-rw-r--r-- 1 root root 5.8K Apr 24 20:05 18-Odyssey_Plans__Applying_Designers'_Mindsets.srt</span><br></pre></td></tr></table></figure>
<h4 id="文件内容格式"><a href="#文件内容格式" class="headerlink" title="文件内容格式"></a>文件内容格式</h4><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">1</span><br><span class="line">00:00:03,590 --> 00:00:04,710</span><br><span class="line">My name is Bill Burnett.</span><br><span class="line"></span><br><span class="line">2</span><br><span class="line">00:00:04,710 --> 00:00:07,460</span><br><span class="line">I'm one of the co-authors</span><br><span class="line">of Designing Your Life,</span><br><span class="line"></span><br><span class="line">3</span><br><span class="line">00:00:07,460 --> 00:00:09,410</span><br><span class="line">How to Live a</span><br><span class="line">Well-Lived Joyful Life.</span><br><span class="line"></span><br><span class="line">......</span><br></pre></td></tr></table></figure>
<h4 id="思路分析"><a href="#思路分析" class="headerlink" title="思路分析"></a>思路分析</h4><ul>
<li>获取所有文件名存入列表 <– 方便循环进行文件操作</li>
<li>然后用正则匹配演讲词并打印出来 <– 剔除无用字符</li>
<li>执行脚本并将输出重定向到一个新文件 <– 合并为一个文件</li>
</ul>
<h4 id="实现代码"><a href="#实现代码" class="headerlink" title="实现代码"></a>实现代码</h4><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line"># Script_name: merge_final.py</span><br><span class="line"></span><br><span class="line">import re</span><br><span class="line">import os</span><br><span class="line"></span><br><span class="line"># 字幕文件所在目录</span><br><span class="line">dir = "/root/tmp/"</span><br><span class="line"></span><br><span class="line">def process(filename):</span><br><span class="line"> '''对文件进行操作'''</span><br><span class="line"> print(filename)</span><br><span class="line"> </span><br><span class="line"> with open(dir+filename, 'r', encode='utf-8') as f: # 打开文件</span><br><span class="line"> lines = f.readlines() # 按行读取整个文件,存入列表</span><br><span class="line"> </span><br><span class="line"> for line in lines:</span><br><span class="line"> # 剔除无用字符</span><br><span class="line"> lrc = re.search(r'^\D.*[a-z.]', line) </span><br><span class="line"> if lrc: </span><br><span class="line"> print(lrc.group()) </span><br><span class="line"> </span><br><span class="line"> print("--------------------")</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">def main():</span><br><span class="line"> filelist = os.listdir(dir) # 获取目录下所有的文件名称</span><br><span class="line"> filelist.sort() # 按照数字排序</span><br><span class="line"> </span><br><span class="line"> for filename in filelist:</span><br><span class="line"> process(filename) # 将文件名传过去</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">if __name__ == "__main__":</span><br><span class="line"> main()</span><br></pre></td></tr></table></figure>
<h4 id="执行脚本"><a href="#执行脚本" class="headerlink" title="执行脚本"></a>执行脚本</h4><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">[root@dayday ~]# python merge_final.py > lecture.txt</span><br></pre></td></tr></table></figure>
<h4 id="知识点整理"><a href="#知识点整理" class="headerlink" title="知识点整理"></a>知识点整理</h4><p><strong>1. 编码格式问题</strong></p>
<p>在读取中文的情况下,通常会遇到一些编码的问题,但是首先需要了解目前的编码方式是什么,然后再用decode或者encode去编码和解码,下面是使用chardet库来查看编码方式的。</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">import chardet</span><br><span class="line"></span><br><span class="line">path = "E:/t.csv"</span><br><span class="line">f = open(path,'rb')</span><br><span class="line"></span><br><span class="line">data = f.read()</span><br><span class="line">print(chardet.detect(data))</span><br></pre></td></tr></table></figure>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">[root@dayday ~]# python test.py</span><br><span class="line">{'encoding': 'GB2312', 'confidence': 0.99, 'language': 'Chinese'}</span><br></pre></td></tr></table></figure>
<p>当时的字幕是从<a href="http://downsub.com/" target="_blank" rel="noopener">downsub.com</a>网站下载的,编码格式是Windows-1254格式,在Python进行文件操作时总是报错,偷懒在notepad++下手动更改编码格式为utf-8,当然也可以用Python脚本实现。</p>
<p><strong>2. 导入目录下所有文件的名称&排序问题</strong></p>
<p>这个就是知识没掌握的问题了,在此记录。os是个强大的模块!</p>
<p><strong>3. 正则语法</strong></p>
<p>好多语法格式都不熟练,一边调试一边查<a href="runoob.com">runoob.com</a>,着实耗时间,需反复练习!</p>
<p><strong>4. re.match()返回值问题</strong></p>
<p>re.match()匹配成功返回re.match()对象,可用.group()方法提取字符串;匹配失败返回None。</p>
<p>文件时是按行读取的,因此循环对行进行正则匹配,返回的结果中穿插着None和re.match对象,而None调用.group()方法会报错,所以在这简单的用if过滤掉了None。</p>
<p>在敲这篇记录时突然想起,应该可以用Python的异常处理过滤掉报错,改天试试看</p>
<p><strong>5. 养成随手记录的习惯</strong></p>
<p>在整个解决过程中,查了很多资料,但没有随时记下来,解决完问题做记录的时候有些问题都忘记了!</p>
]]></content>
</entry>
<entry>
<title>安装黑苹果记录</title>
<url>/2020/03/06/%E5%AE%89%E8%A3%85%E9%BB%91%E8%8B%B9%E6%9E%9C%E5%B0%8F%E8%AE%B0/</url>
<content><![CDATA[<h3 id="硬件平台:XiaoMi-Air12-5-m3-6y30-4G-128G"><a href="#硬件平台:XiaoMi-Air12-5-m3-6y30-4G-128G" class="headerlink" title="硬件平台:XiaoMi Air12.5 m3-6y30 4G+128G"></a>硬件平台:XiaoMi Air12.5 m3-6y30 4G+128G</h3><h4 id="完整备份win10系统"><a href="#完整备份win10系统" class="headerlink" title="完整备份win10系统"></a>完整备份win10系统</h4><p>建议使用win10系统自带备份功能。</p>
<h5 id="恢复win10系统"><a href="#恢复win10系统" class="headerlink" title="恢复win10系统"></a>恢复win10系统</h5><p>安装黑苹果会格掉整个盘,所以恢复时在U盘PE下使用系统镜像的install.wim软件左下角的恢复系统功能来进行恢复。</p>
<h4 id="准备文件"><a href="#准备文件" class="headerlink" title="准备文件"></a>准备文件</h4><ol>
<li>系统镜像 <a href="https://blog.daliansky.net/macOS-Mojave-10.14.4-18E226-official-version-with-Clover-4903-original-image.html" target="_blank" rel="noopener">mirror</a></li>
<li>刻盘软件etcher <a href="https://www.balena.io/etcher/" target="_blank" rel="noopener">etcher</a></li>
<li>专用EFI <a href="https://github.com/johnnync13/EFI-Xiaomi-Notebook-air-12-5.git" target="_blank" rel="noopener">EFI</a></li>
<li>win10备份U盘,16G以上</li>
<li>黑苹果系统U盘,8G以上</li>
</ol>
<h4 id="制作安装镜像"><a href="#制作安装镜像" class="headerlink" title="制作安装镜像"></a>制作安装镜像</h4><ol>
<li>格式化U盘</li>
<li>打开etcher软件</li>
<li>傻瓜式操作</li>
</ol>
<h4 id="替换EFI"><a href="#替换EFI" class="headerlink" title="替换EFI"></a>替换EFI</h4><p>因为镜像自带的EFI不兼容air12.5,所以我们要手动替换为专用EFI</p>
<p>win10磁盘管理工具可以进入U盘的EFI分区,将专用EFI中的EFI目录替换进U盘EFI分区中</p>
<h4 id="小米BIOS设置"><a href="#小米BIOS设置" class="headerlink" title="小米BIOS设置"></a>小米BIOS设置</h4><h5 id="升级BIOS版本至A05"><a href="#升级BIOS版本至A05" class="headerlink" title="升级BIOS版本至A05"></a>升级BIOS版本至A05</h5><p>A04版本的BIOS有关机不断掉的Bug,所以我们需要更新BIOS至A05</p>
<p>下载链接: <a href="http://bbs.xiaomi.cn/t-13100333" target="_blank" rel="noopener">BIOS-A05</a></p>
<p>按照帖子描述一键刷入即可。</p>
<h5 id="设置BIOS"><a href="#设置BIOS" class="headerlink" title="设置BIOS"></a>设置BIOS</h5><p>关闭Secure Boot模式,不然无法引导至macOS。</p>
<ol>
<li>开机按F2进BIOS</li>
<li>Security -> Set Supervisor Password -> Installed # 不设置密码不能关闭</li>
<li>Securt Boot Mode -> Disabled</li>
</ol>
<blockquote>
<p>开机按F12进入Boot Manager,设置从U盘启动。</p>
</blockquote>
<h4 id="安装黑苹果"><a href="#安装黑苹果" class="headerlink" title="安装黑苹果"></a>安装黑苹果</h4><p>首先进入Clover界面,Clover是一个黑苹果引导工具,因为macOS不支持非苹果机运行,所以我们要通过第三方工具来修正一系列底层参数,以正确的在非苹果机上引导macOS,该程序就是Clover</p>
<ol>
<li>屏幕亮起,进入Clover</li>
<li>选择 Boot OS X Install from XiaoMi</li>
<li>拷贝镜像到磁盘。。。。。。。。。</li>
</ol>
<p>进入macOS恢复模式,开始安装</p>
<ol>
<li>选择语言</li>
</ol>
<p>抹掉硬盘,确保你已经将所有的重要数据正确的备份到其他存储介质上。</p>
<ol>
<li>选中macOS实用工具 -> 磁盘工具 -> 左上角选项-显示所有设备</li>
<li>选择本地磁盘SSD Media -> 上方功能栏-抹掉</li>
<li>选择默认的Mac OS扩展(日志型) rename–>Macintosh HD -> 抹掉</li>
<li>退出磁盘工具</li>
</ol>
<p>真正开始安装macOS</p>
<ol>
<li>安装macOS</li>
<li>进入安装界面</li>
<li>开始安装</li>
</ol>
<h4 id="安装第二阶段"><a href="#安装第二阶段" class="headerlink" title="安装第二阶段"></a>安装第二阶段</h4><p>等。。。。。。</p>
<h4 id="设置向导"><a href="#设置向导" class="headerlink" title="设置向导"></a>设置向导</h4><p>略</p>
<h4 id="替换EFI-1"><a href="#替换EFI-1" class="headerlink" title="替换EFI"></a>替换EFI</h4><p>因为EFI分区此时还在U盘上,所以我们需要将EFI文件拷贝到本地磁盘的EFI分区上</p>
<p>1.挂载EFI分区</p>
<p>打开终端,输入以下命令</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">$ diskutil list # 查看磁盘分区表</span><br><span class="line">$ diskutil mount disk0s1 # 挂载磁盘FEI分区</span><br><span class="line">$ diskutil mount disk1s1 # 挂载U盘EFI分区</span><br><span class="line">$ find . # 打开Finder,进行替换操作</span><br></pre></td></tr></table></figure>
<ol start="2">
<li>合并EFI</li>
</ol>
<p>纯净安装macOS,没有Win10系统的EFI,不需要合并,此步省略</p>
<ol start="3">
<li>替换EFI</li>
</ol>
<p>将U盘EFI分区下的EFI目录复制到磁盘EFI分区下</p>
<h4 id="完善网卡驱动"><a href="#完善网卡驱动" class="headerlink" title="完善网卡驱动"></a>完善网卡驱动</h4><p>Mac本身不支持小米自带的网卡型号,无解,扩展槽无法添加WIFI无线网卡,只能选择外置USB网卡。</p>
<p>或者使用USB网络共享暂时上网 <a href="https://github.com/jwise/HoRNDIS/releases" target="_blank" rel="noopener">HoRNDIS</a>,下载安装即可。</p>
<p>USB连接手机,手机上打开热点,即可上网。</p>
<h4 id="开启HiDPI"><a href="#开启HiDPI" class="headerlink" title="开启HiDPI"></a>开启HiDPI</h4><p>1080P分辨率在12寸的屏幕上显示的字体特别小,所以有了开启HiDPI的需求</p>
<p>教程链接 <a href="https://zhih.me/one-key-hidpi/" target="_blank" rel="noopener">开启HiDPI</a><br>脚本下载链接 <a href="https://github.com/xzhih/one-key-hidpi.git" target="_blank" rel="noopener">下载HiDPI</a></p>
<h4 id="GitHub访问加速"><a href="#GitHub访问加速" class="headerlink" title="GitHub访问加速"></a>GitHub访问加速</h4><p>域名的IP地址在 <a href="https://www.ipaddress.com" target="_blank" rel="noopener">https://www.ipaddress.com</a> 查询</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">$ sudo vim /etc/hosts</span><br><span class="line"># github</span><br><span class="line">192.30.253.112 GitHub.com</span><br><span class="line">185.199.108.153 assets-cdn.github.com</span><br><span class="line">151.101.185.194 github.global.ssl.fastly.net</span><br></pre></td></tr></table></figure>
<p>感谢提供专用EFI的作者<a href="https://github.com/johnnync13/" target="_blank" rel="noopener">johnnync13</a><br>感谢提供思路的<a href="http://bbs.xiaomi.cn/t-36526099" target="_blank" rel="noopener">etrock</a><br>感谢提供镜像的作者<a href="https://blog.daliansky.net" target="_blank" rel="noopener">黑果小兵</a></p>
]]></content>
<tags>
<tag>hackintosh</tag>
</tags>
</entry>
<entry>
<title>计算机网络-应用层</title>
<url>/2020/03/06/%E5%BA%94%E7%94%A8%E5%B1%82-over/</url>
<content><![CDATA[<h3 id="域名系统DNS"><a href="#域名系统DNS" class="headerlink" title="域名系统DNS"></a>域名系统DNS</h3><p>DNS(Domain Name Protocol)<br>DNS 是一个分布式数据库,提供了主机名和 IP 地址之间相互转换的服务。这里的分布式数据库是指,每个站点只保留它自己的那部分数据。</p>
<p>域名具有层次结构,从上到下以此为:根域名、顶级域名、二级域名。</p>
<h4 id="域名服务器"><a href="#域名服务器" class="headerlink" title="域名服务器"></a>域名服务器</h4><p>根据其功能分为:根域名服务器、顶级域名服务器、权限域名服务器、本地域名服务器。<br>前三者用于提供DNS解析<strong>数据</strong>,本地域名服务器用于提供DNS解析<strong>服务</strong>。</p>
<p>主机向本地域名服务器查询一般采用<strong>递归查询</strong>,<br>本地域名服务器向根域名服务器的查询一般采用<strong>迭代查询</strong>。</p>
<p><img src="https://ae01.alicdn.com/kf/HTB1xaNxeliE3KVjSZFMq6zQhVXau.jpg" alt=""></p>
<p>DNS 可以使用 UDP 或 TCP 进行传输,使用的端口号都为 53。大多数情况下 DNS 使用UDP 进行传输,这就要求域名解析器和域名服务器都必须自己处理超时和重传从而保证可靠性。在两种情况下会使用 TCP 进行传输:</p>
<ul>
<li>如果返回的响应超过的 512 字节(UDP最大支持512字节的数据)</li>
<li>区域传送(区域传送是主域服务器向辅助域名服务器传送变化的那部分数据)</li>
</ul>
<h3 id="文件传送协议FTP"><a href="#文件传送协议FTP" class="headerlink" title="文件传送协议FTP"></a>文件传送协议FTP</h3><p>FTP(File Transfer Protocol)</p>
<p>FTP 使用的 TCP 进行连接,它需要两个连接来传送一个文件:</p>
<ul>
<li>控制连接:服务器打开端口号 21 等待客户端的连接,客户端主动建立连接后,使用这个连接将客户端的命令传送给服务器,并传送服务器的应答。</li>
<li>数据连接:用来传送一个文件数据。</li>
</ul>
<p>根据数据连接是否是服务器端主动建立,FTP 有主动和被动两种模式:</p>
<ul>
<li>主动模式:服务器端主动建立数据连接,其中服务器端的端口号为 20,客户端的端口号随机,但是必须大于 1024,因为 0~1023 是熟知端口号。</li>
</ul>
<p><img src="https://ae01.alicdn.com/kf/HTB1g8NDelKw3KVjSZFOq6yrDVXaP.jpg" alt=""></p>
<ul>
<li>被动模式:客户端主动建立数据连接,其中客户端的端口号由客户端自己指定,服务器端的端口号随机。</li>
</ul>
<p><img src="https://ae01.alicdn.com/kf/HTB149Vyel1D3KVjSZFyq6zuFpXa5.jpg" alt=""></p>
<p>主动模式要求客户端开放端口号给服务器端,需要去配置客户端的防火墙。被动模式只需要服务器端开放端口号即可,无需客户端配置防火墙。但是被动模式会导致服务器端的安全性减弱,因为开放了过多的端口号。</p>
<h3 id="简单文件传送协议TFTP"><a href="#简单文件传送协议TFTP" class="headerlink" title="简单文件传送协议TFTP"></a>简单文件传送协议TFTP</h3><p>TFTP(Trivial File Transfer Protocol)</p>
<p>主要用于手机端,使用客户服务器方式,但使用 UDP 协议进行通信,TFTP 只支持文件传输而不支持交互。<br>TFTP 没有庞大的命令集,没有列目录功能,也不能对用户进行身份鉴别。</p>
<h4 id="TFTP的主要优点:"><a href="#TFTP的主要优点:" class="headerlink" title="TFTP的主要优点:"></a>TFTP的主要优点:</h4><ol>
<li>TFTP 可用于 UDP 环境。</li>
<li>TFTP 代码所占的内存较小。</li>
<li>每次传送的数据报文中有 512 个字节数据,最后一次可不足 512 字节</li>
<li>数据报文按序编号,从 1 开始。</li>
<li>支持 ASCII 码或二进制传送。</li>
<li>可对文件进行读写。</li>
<li>很用很简单的首部。</li>
</ol>
<h3 id="动态主机配置协议DHCP"><a href="#动态主机配置协议DHCP" class="headerlink" title="动态主机配置协议DHCP"></a>动态主机配置协议DHCP</h3><p>DHCP(Dynamic Host Configuration Protocol)提供了即插即用的连网方式,用户不再需要手动配置 IP 地址等信息。</p>
<p>DHCP 配置的内容不仅是 IP 地址,还包括子网掩码、网关 IP 地址。</p>
<p>DHCP 工作过程:</p>
<ol>
<li>客户端发送 Discover 报文,该报文的目的地址为 255.255.255.255:67,源地址为 0.0.0.0:68,被放入 UDP 中,该报文被广播到同一个子网的所有主机上。如果客户端和 DHCP 服务器不在同一个子网,就需要使用中继代理。</li>
<li>DHCP 服务器收到 Discover 报文之后,发送 Offer 报文给客户端,该报文包含了客户端所需要的信息。因为客户端可能收到多个 DHCP 服务器提供的信息,因此客户端需要进行选择。</li>
<li>如果客户端选择了某个 DHCP 服务器提供的信息,那么就发送 Request 报文给该 DHCP 服务器。</li>
<li>DHCP 服务器发送 Ack 报文,表示客户端此时可以使用提供给它的信息。</li>
</ol>
<p><img src="https://ae01.alicdn.com/kf/HTB1ysVxegaH3KVjSZFjq6AFWpXai.jpg" alt=""></p>
<h3 id="远程登录协议TELNET"><a href="#远程登录协议TELNET" class="headerlink" title="远程登录协议TELNET"></a>远程登录协议TELNET</h3><p>又称<strong>终端仿真协议</strong>。</p>
<p>TELNET 用于登陆到远程主机上,并且远程主机上的输出也会返回。</p>
<p>TELNET 可以适应许多计算机和操作系统的差异,例如不同操作系统的换行符定义。即所谓的<strong>网络虚拟终端NVT</strong>(Network Virtual Terminal)</p>
<h3 id="电子邮件协议"><a href="#电子邮件协议" class="headerlink" title="电子邮件协议"></a>电子邮件协议</h3><p>一个电子邮件系统由三部分组成:用户代理、邮件服务器、邮件协议。</p>
<p>邮件协议包含发送协议和读取协议,发送协议常用 SMTP,读取协议常用 POP3 和 IMAP。</p>
<p><img src="https://ae01.alicdn.com/kf/HTB1H.pHebus3KVjSZKb760qkFXaR.png" alt=""></p>
<h4 id="1-SMTP"><a href="#1-SMTP" class="headerlink" title="1.SMTP"></a>1.SMTP</h4><p>SMTP(Simple Mail Transfer Protocol)简单邮件传送协议</p>
<p>SMTP 只能发送 ASCII 码,而互联网邮件扩充 MIME 可以发送二进制文件。</p>
<p>MIME 并没有改动或者取代 SMTP,而是增加邮件主体的结构,定义了非 ASCII 码的编码规则。</p>
<p><img src="https://ae01.alicdn.com/kf/HTB1glCLbvBj_uVjSZFp7630SXXam.png" alt=""></p>
<h4 id="2-POP3"><a href="#2-POP3" class="headerlink" title="2. POP3"></a>2. POP3</h4><p>POP3(Post Office Protocol)邮局协议</p>
<p>POP3 的特点是只要用户从服务器上读取了邮件,就把该邮件删除。</p>
<h4 id="3-IMAP"><a href="#3-IMAP" class="headerlink" title="3. IMAP"></a>3. IMAP</h4><p>IMAP(Internet Message Access Protocol)网际报文存取协议</p>
<p>IAMP 协议中客户端和服务器上的邮件保持同步,如果不手动删除邮件,那么服务器上的邮件也不会被删除。IMAP 这种做法可以上用户随时随地去访问服务器上的邮件。</p>
<h4 id="电子邮件的地址格式"><a href="#电子邮件的地址格式" class="headerlink" title="电子邮件的地址格式"></a>电子邮件的地址格式</h4><p>用户名 @ 邮件服务器的域名<br>示例:<a href="mailto:xyz@abc.com">xyz@abc.com</a><br>xyz为用户名,abc.com为邮件服务器域名</p>
<h4 id="电子邮件的信息格式"><a href="#电子邮件的信息格式" class="headerlink" title="电子邮件的信息格式"></a>电子邮件的信息格式</h4><p>一个电子邮件分为<strong>信封</strong>和<strong>内容</strong>两大部分。</p>
<p>首部关键字:</p>
<ul>
<li>To:后跟一个或多个收件人邮件地址</li>
<li>Subject:邮件主题</li>
<li>Cc:抄送,收件人可以看到抄送人</li>
<li>Bcc:暗送,收件人不知情</li>
<li>From:发件人的电邮地址</li>
<li>Date:发新日期</li>
<li>Reply-To:对方回信地址</li>
</ul>
<h3 id="常用端口"><a href="#常用端口" class="headerlink" title="常用端口"></a>常用端口</h3><table>
<thead>
<tr>
<th>应用</th>
<th>应用层协议</th>
<th>端口号</th>
<th>传输层协议</th>
<th>备注</th>
</tr>
</thead>
<tbody><tr>
<td>域名解析</td>
<td>DNS</td>
<td>53</td>
<td>UDP/TCP</td>
<td>长度超过 512 字节时使用 TCP</td>
</tr>
<tr>
<td>动态主机配置协议</td>
<td>DHCP</td>
<td>67/68</td>
<td>UDP</td>
<td></td>
</tr>
<tr>
<td>简单网络管理协议</td>
<td>SNMP</td>
<td>161/162</td>
<td>UDP</td>
<td></td>
</tr>
<tr>
<td>文件传送协议</td>
<td>FTP</td>
<td>20/21</td>
<td>TCP</td>
<td>控制连接 21,数据连接 20</td>
</tr>
<tr>
<td>远程终端协议</td>
<td>TELNET</td>
<td>23</td>
<td>TCP</td>
<td></td>
</tr>
<tr>
<td>超文本传送协议</td>
<td>HTTP</td>
<td>80</td>
<td>TCP</td>
<td></td>
</tr>
<tr>
<td>简单邮件传送协议</td>
<td>SMTP</td>
<td>25</td>
<td>TCP</td>
<td></td>
</tr>
<tr>
<td>邮件读取协议</td>
<td>POP3</td>
<td>110</td>
<td>TCP</td>
<td></td>
</tr>
<tr>
<td>网际报文存取协议</td>
<td>IMAP</td>
<td>143</td>
<td>TCP</td>
<td></td>
</tr>
</tbody></table>
<h3 id="万维网WWW"><a href="#万维网WWW" class="headerlink" title="万维网WWW"></a>万维网WWW</h3><p>WWW(World Wide Web),英文简称Web。<br>万维网是一个大规模、联机式的信息储藏所。<br>万维网以客户服务器方式工作。 </p>
<h4 id="统一资源定位符URL"><a href="#统一资源定位符URL" class="headerlink" title="统一资源定位符URL"></a>统一资源定位符URL</h4><p>URL(Uniform Resource Locator)</p>
<p>格式:<协议>://<主机>:<端口>/<路径></p>
<h3 id="Web-页面请求过程"><a href="#Web-页面请求过程" class="headerlink" title="Web 页面请求过程"></a>Web 页面请求过程</h3><h4 id="1-DHCP-配置主机信息"><a href="#1-DHCP-配置主机信息" class="headerlink" title="1. DHCP 配置主机信息"></a>1. DHCP 配置主机信息</h4><ul>
<li><p>假设主机最开始没有 IP 地址以及其它信息,那么就需要先使用 DHCP 来获取。</p>
</li>
<li><p>主机生成一个 DHCP 请求报文,并将这个报文放入具有目的端口 67 和源端口 68 的 UDP 报文段中。</p>
</li>
<li><p>该报文段则被放入在一个具有广播 IP 目的地址(255.255.255.255) 和源 IP 地址(0.0.0.0)的 IP 数据报中。</p>
</li>
<li><p>该数据报被放置在 MAC 帧中,该帧具有目的地址 FF:FF:FF:FF:FF:FF,将广播到与交换机连接的所有设备。</p>
</li>
<li><p>连接在交换机的 DHCP 服务器收到广播帧之后,不断地向上分解得到 IP 数据报、UDP 报文段、DHCP 请求报文,之后生成 DHCP ACK 报文,该报文包含以下信息:IP 地址、DNS 服务器的 IP 地址、默认网关路由器的 IP 地址和子网掩码。该报文被放入 UDP 报文段中,UDP 报文段有被放入 IP 数据报中,最后放入 MAC 帧中。</p>
</li>
<li><p>该帧的目的地址是请求主机的 MAC 地址,因为交换机具有自学习能力,之前主机发送了广播帧之后就记录了 MAC 地址到其转发接口的交换表项,因此现在交换机就可以直接知道应该向哪个接口发送该帧。</p>
</li>
<li><p>主机收到该帧后,不断分解得到 DHCP 报文。之后就配置它的 IP 地址、子网掩码和 DNS 服务器的 IP 地址,并在其 IP 转发表中安装默认网关。</p>
</li>
</ul>
<h4 id="2-ARP-解析-MAC-地址"><a href="#2-ARP-解析-MAC-地址" class="headerlink" title="2. ARP 解析 MAC 地址"></a>2. ARP 解析 MAC 地址</h4><ul>
<li><p>主机通过浏览器生成一个 TCP 套接字,套接字向 HTTP 服务器发送 HTTP 请求。为了生成该套接字,主机需要知道网站的域名对应的 IP 地址。</p>
</li>
<li><p>主机生成一个 DNS 查询报文,该报文具有 53 号端口,因为 DNS 服务器的端口号是 53。</p>
</li>
<li><p>该 DNS 查询报文被放入目的地址为 DNS 服务器 IP 地址的 IP 数据报中。</p>
</li>
<li><p>该 IP 数据报被放入一个以太网帧中,该帧将发送到网关路由器。</p>
</li>
<li><p>DHCP 过程只知道网关路由器的 IP 地址,为了获取网关路由器的 MAC 地址,需要使用 ARP 协议。</p>
</li>
<li><p>主机生成一个包含目的地址为网关路由器 IP 地址的 ARP 查询报文,将该 ARP 查询报文放入一个具有广播目的地址(FF:FF:FF:FF:FF:FF)的以太网帧中,并向交换机发送该以太网帧,交换机将该帧转发给所有的连接设备,包括网关路由器。</p>
</li>
<li><p>网关路由器接收到该帧后,不断向上分解得到 ARP 报文,发现其中的 IP 地址与其接口的 IP 地址匹配,因此就发送一个 ARP 回答报文,包含了它的 MAC 地址,发回给主机</p>
</li>
</ul>
<h4 id="3-DNS-解析域名"><a href="#3-DNS-解析域名" class="headerlink" title="3. DNS 解析域名"></a>3. DNS 解析域名</h4><ul>
<li><p>知道了网关路由器的 MAC 地址之后,就可以继续 DNS 的解析过程了。</p>
</li>
<li><p>网关路由器接收到包含 DNS 查询报文的以太网帧后,抽取出 IP 数据报,并根据转发表决定该 IP 数据报应该转发的路由器。</p>
</li>
<li><p>因为路由器具有内部网关协议(RIP、OSPF)和外部网关协议(BGP)这两种路由选择协议,因此路由表中已经配置了网关路由器到达 DNS 服务器的路由表项。</p>
</li>
<li><p>到达 DNS 服务器之后,DNS 服务器抽取出 DNS 查询报文,并在 DNS 数据库中查找待解析的域名。</p>
</li>
<li><p>找到 DNS 记录之后,发送 DNS 回答报文,将该回答报文放入 UDP 报文段中,然后放入 IP 数据报中,通过路由器反向转发回网关路由器,并经过以太网交换机到达主机。</p>
</li>
</ul>
<h4 id="4-HTTP-请求页面"><a href="#4-HTTP-请求页面" class="headerlink" title="4. HTTP 请求页面"></a>4. HTTP 请求页面</h4><ul>
<li><p>有了 HTTP 服务器的 IP 地址之后,主机就能够生成 TCP 套接字,该套接字将用于向 Web 服务器发送 HTTP GET 报文。</p>
</li>
<li><p>在生成 TCP 套接字之前,必须先与 HTTP 服务器进行三次握手来建立连接。生成一个具有目的端口 80 的 TCP SYN 报文段,并向 HTTP 服务器发送该报文段。</p>
</li>
<li><p>HTTP 服务器收到该报文段之后,生成 TCP SYN ACK 报文段,发回给主机。</p>
</li>
<li><p>连接建立之后,浏览器生成 HTTP GET 报文,并交付给 HTTP 服务器。</p>
</li>
<li><p>HTTP 服务器从 TCP 套接字读取 HTTP GET 报文,生成一个 HTTP 响应报文,将 Web 页面内容放入报文主体中,发回给主机。</p>
</li>
<li><p>浏览器收到 HTTP 响应报文后,抽取出 Web 页面内容,之后进行渲染,显示 Web 页面。</p>
</li>
</ul>
]]></content>
<tags>
<tag>Internet</tag>
</tags>
</entry>
<entry>
<title>计算机网络-数据链路层</title>
<url>/2020/03/06/%E6%95%B0%E6%8D%AE%E9%93%BE%E8%B7%AF%E5%B1%82-over/</url>
<content><![CDATA[<h3 id="基本问题"><a href="#基本问题" class="headerlink" title="基本问题"></a>基本问题</h3><h4 id="1-封装成帧"><a href="#1-封装成帧" class="headerlink" title="1. 封装成帧"></a>1. 封装成帧</h4><p>将网络层传下来的分组添加首部和尾部,用于标记帧的开始和结束。<br><img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/29a14735-e154-4f60-9a04-c9628e5d09f4.png" alt="image"></p>
<h4 id="2-透明传输"><a href="#2-透明传输" class="headerlink" title="2. 透明传输"></a>2. 透明传输</h4><p>透明表示一个实际存在的事物看起来好像不存在一样。</p>
<p>帧使用首部和尾部进行定界,如果帧的数据部分含有和首尾部相同的内容,那么帧的开始和结束位置就会被错误的判定。因此需要在数据部分出现首尾部相同的内容前面插入转义字符。如果数据部分出现转义字符,那么就在转义字符前面再加个转义字符。在接收端进行处理之后可以还原出原始数据。这个过程透明传输的内容是转义字符,用户察觉不到转义字符的存在。</p>
<p><img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/e738a3d2-f42e-4755-ae13-ca23497e7a97.png" alt="image"></p>
<h4 id="3-差错检测"><a href="#3-差错检测" class="headerlink" title="3. 差错检测"></a>3. 差错检测</h4><p>目前数据链路层广泛使用来循环冗余校验(CRC)来检查比特差错。</p>
<h3 id="信道分类"><a href="#信道分类" class="headerlink" title="信道分类"></a>信道分类</h3><ul>
<li>点对点信道:一对一通信,因为不会发生碰撞,因此也比较简单,使用PPP协议进行控制。</li>
<li>广播信道:一对多通信,一个节点发送的数据能够倍广播信道上所有的节点接收到。<ul>
<li>所有的节点都在同一个广播信道上发送数据,因此需要有专门的控制方法进行协调,避免发生冲突(冲突也叫碰撞)。</li>
<li>主要有两种控制方法进行协调,一个是信道复用技术,另一个是CSMA/CD协议。</li>
</ul>
</li>
</ul>
<h4 id="点对点信道的相关概念"><a href="#点对点信道的相关概念" class="headerlink" title="点对点信道的相关概念"></a>点对点信道的相关概念</h4><ul>
<li>链路:从一个结点到相邻结点的一段物理线路(有线或无线),而中间没有任何其他的交换结点。</li>
<li>数据链路:当需要在一条线路上传送数据时,除了必须有一条物理线路外,还必须有一些必要的通信协议来控制这些数据的传输。若把实现这些协议的硬件和软件加到链路上,就构成来数据链路。<ul>
<li>现在最常用的方法是使用网络适配器来实现这些协议。</li>
</ul>
</li>
</ul>
<h3 id="PPP协议"><a href="#PPP协议" class="headerlink" title="PPP协议"></a>PPP协议</h3><p>PPP(Point to Point Protocol)点对点协议</p>
<p>互联网用户通常需要连接到某个ISP之后才能接入到互联网,PPP协议是用户计算机和ISP进行通信时所使用的数据链路层协议。<br><img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/e1ab9f28-cb15-4178-84b2-98aad87f9bc8.jpg" alt="image"></p>
<p>PPP的帧格式:</p>
<ul>
<li>F 字段为帧的定界符 1字节</li>
<li>A 和 C 字段暂时没有意义 1字节</li>
<li>FCS 字段是使用CRC的检验序列 2字节</li>
<li>信息部分的长度不超过1500字节</li>
<li>协议字段:信息字段 2字节<ul>
<li>0x0021 : IP数据报</li>
<li>0xC021 : 链路控制协议LCP的数据</li>
<li>0x8021 : 网络层的控制数据</li>
</ul>
</li>
</ul>
<p><img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/759013d7-61d8-4509-897a-d75af598a236.png" alt="image"></p>
<h4 id="CRC校验手动计算示例"><a href="#CRC校验手动计算示例" class="headerlink" title="CRC校验手动计算示例"></a>CRC校验手动计算示例</h4><p>生成多项式:G(x)=x^4+x^3+1,要求出二进制序列10110011的CRC校验码。</p>
<ul>
<li><ol>
<li>G(x)=x^4+x^3+1,二进制比特串为11001;(有X的几次方,对应的2的几次方的位就是1)</li>
</ol>
</li>
<li><ol start="2">
<li>因为校验码4位,所以10110011后面再加4个0,得到101100110000,用“模2除法”(其实就是亦或^)即可得出结果;</li>
</ol>
</li>
<li><ol start="3">
<li>CRC^101100110000得到101100110100。发送到接收端;</li>
</ol>
</li>
<li><ol start="4">
<li>接收端收到101100110100后除以11001(以“模2除法”方式去除),余数为0则无差错;</li>
</ol>
</li>
</ul>
<p><img src="https://ae01.alicdn.com/kf/HTB1XMQkdG1s3KVjSZFAq6x_ZXXaw.jpg" alt="image"></p>
<h4 id="字节填充、零比特填充"><a href="#字节填充、零比特填充" class="headerlink" title="字节填充、零比特填充"></a>字节填充、零比特填充</h4><ul>
<li>字节填充:在发送端,当发现信息字段中出现与定界符相同的字符时,插入转义符,当信息字段中出现转义符时,在转义符前插入转义符。</li>
<li>零比特填充:在发送端,扫描整个信息字段,只要发现有5个连续的1,则立即填入一个0,确保信息字段不会出现6个连续1.</li>
</ul>
<h3 id="CSMA-CD协议"><a href="#CSMA-CD协议" class="headerlink" title="CSMA/CD协议"></a>CSMA/CD协议</h3><p>CSMA/CD(Carrier Sense Multiple Access with Collision Detection) 表示载波监听多点接入/碰撞检测</p>
<ul>
<li>多点接入:说明这是总线型网络,许多主机以多点的方式连接到总线上</li>
<li>载波监听:每个主机都必须不停地监听信道。在发送前,如果监听到信道正在使用,就必须等待。</li>
<li>碰撞检测:在发送中,如果检测到信道已有其他主机正在发送数据,就表示发生了碰撞。虽然每个主机在发送数据之前都已经监听到信道为空闲,但是由于电磁波的传播时延的存在,还是有可能会发生碰撞。</li>
</ul>
<blockquote>
<p>总结:先听后发、边听边发、冲突停发、随机重发。<br>显然使用CSMA/CD协议,不可能同时进行发送和接收(但必须边发送边监听信道),因此使用CSMA/CD协议的以太网只能进行半双工通信。</p>
</blockquote>
<p>记端到端的传播时延为τ,最先发送的站点最多经过2τ就可以知道是否发生了碰撞,称2τ为<strong>争用期</strong>。只有经过争用期之后还没有检测到碰撞,才能肯定这次发送不会发生碰撞。</p>
<p>当发生碰撞时,站点要停止发送,等待一段时间再发送。这个时间采用<strong>截断二进制指数退避算法</strong>来确定。从离散的整数集合{0,1,…,(2^k-1)}中随机取出一个数,记作r,然后取r倍的争用期作为重传等待时间。</p>
<p>整数集合中的参数k按下面的公式计算:k = Min[重传次数, 10]</p>
<p>当重传16次仍不能成功时,表明网络堵塞,则丢弃该帧,并向高层报告。</p>
<p><img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/19d423e9-74f7-4c2b-9b97-55890e0d5193.png" alt=""></p>
<h3 id="MAC地址"><a href="#MAC地址" class="headerlink" title="MAC地址"></a>MAC地址</h3><p>MAC地址是链路层地址,长度为6字节(48位),用于唯一标识网络适配器(网卡)。</p>
<p>一台主机拥有多少个网络适配器就有多少个MAC地址。例如笔记本电脑普遍存在无线网络适配器和有线网络适配器,因此就有两个MAC地址。</p>
<h3 id="局域网"><a href="#局域网" class="headerlink" title="局域网"></a>局域网</h3><p>局域网是一种典型的广播信道。 </p>
<h4 id="局域网的特点:"><a href="#局域网的特点:" class="headerlink" title="局域网的特点:"></a>局域网的特点:</h4><ul>
<li>网络为一个单位所拥有,且地理范围和站点数目均有限。</li>
<li>具有广播功能,局域网上的主机可共享连接在局域网上的各种硬件和软件资源。</li>
<li>便于系统的扩展和逐渐演变,各设备的位置可灵活调整和改变。</li>
<li>提高了系统的可靠性、可用性和生存性。</li>
</ul>
<h4 id="局域网的分类:"><a href="#局域网的分类:" class="headerlink" title="局域网的分类:"></a>局域网的分类:</h4><p>可按照网络拓扑进行分类:</p>
<p><img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/807f4258-dba8-4c54-9c3c-a707c7ccffa2.jpg" alt=""></p>
<h3 id="以太网"><a href="#以太网" class="headerlink" title="以太网"></a>以太网</h3><p>以太网是一种星型拓扑结构局域网。</p>
<h4 id="以太网的两个标准"><a href="#以太网的两个标准" class="headerlink" title="以太网的两个标准"></a>以太网的两个标准</h4><ol>
<li>DEC公司、Intel公司、Xerox公司联合提出的DIX Ethernet V2标准,数据率10Mbit/s,使用曼彻斯特编码。</li>
<li>IEEE 802委员会提出的IEEE 802.3标准,数据率:10Mbit/s,使用差分曼彻斯特编码。</li>
</ol>
<p>IEEE 802委员会把局域网的数据链路层拆分成了<strong>逻辑链路控制LLC</strong>、<strong>媒体接入控制MAC</strong>两个子层。<br>因为TCP/IP协议经常使用的局域网协议是DIX Ethernet V2标准,因此802.3的LLC的作用已经消失了,之后厂商生产的适配器就仅装有MAC协议而没有LLC协议。</p>
<h4 id="以太网帧格式:"><a href="#以太网帧格式:" class="headerlink" title="以太网帧格式:"></a>以太网帧格式:</h4><ul>
<li>类型:标记上层使用的协议;</li>
<li>数据:长度在46-1500之间,如果太小则需要填充;</li>
<li>FCS:帧检验序列,使用的是CRC检验方法;</li>
</ul>
<p><img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/164944d3-bbd2-4bb2-924b-e62199c51b90.png" alt=""></p>
<h3 id="交换机Switch"><a href="#交换机Switch" class="headerlink" title="交换机Switch"></a>交换机Switch</h3><p>交换机具有自学习能力,学习的是交换表的内容,交换表中存储这MAC地址到接口的映射。</p>
<p>正是由于这种自学习能力,因此交换机是一种即插即用设备,不需要网络管理员手动配置交换表内容。</p>
<p>下图中,交换机有4个接口,主机A向主机B发送数据帧时,交换机把主机A到接口1的映射写入交换表中。为了发送数据帧到B,先查交换表,此时没有主机B的表项,那么主机A就发送广播帧,主机C和主机D会丢弃该帧,主机B回应该帧向主机A发送数据包时,交换机查找交换表得到主机A映射的接口为1,就发送数据帧到接口1,同时交换机添加主机B到接口2的映射。</p>
<p><img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/a4444545-0d68-4015-9a3d-19209dc436b3.png" alt=""></p>
<h3 id="虚拟局域网VLAN"><a href="#虚拟局域网VLAN" class="headerlink" title="虚拟局域网VLAN"></a>虚拟局域网VLAN</h3><p>虚拟局域网只是给局域网用户提供的一种服务,而不是一种新型局域网。</p>
<p>虚拟局域网可以建立与物理位置无关的逻辑组,只有在同一个虚拟局域网中的成员才会收到链路层广播信息。</p>
<p>例如下图中 (A1, A2, A3, A4) 属于一个虚拟局域网,A1 发送的广播会被 A2、A3、A4 收到,而其它站点收不到。</p>
<p>使用 VLAN 干线连接来建立虚拟局域网,每台交换机上的一个特殊接口被设置为干线接口,以互连 VLAN 交换机。IEEE 定义了一种扩展的以太网帧格式 802.1Q,它在标准以太网帧上加进了 4 字节首部 VLAN 标签,用于表示该帧属于哪一个虚拟局域网。</p>
<p><img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/e98e9d20-206b-4533-bacf-3448d0096f38.png" alt=""></p>
]]></content>
<tags>
<tag>Internet</tag>
</tags>
</entry>
<entry>
<title>计算机网络-概述</title>
<url>/2020/03/06/%E6%A6%82%E8%BF%B0-over/</url>
<content><![CDATA[<h3 id="计算机网络在信息时代的作用"><a href="#计算机网络在信息时代的作用" class="headerlink" title="计算机网络在信息时代的作用"></a>计算机网络在信息时代的作用</h3><ul>
<li><p>数字化、网络化、信息化,一个以网络为核心的信息时代</p>
</li>
<li><p>三大类网络:电信网路、有线电视网络、计算机网路,核心是计算机网络</p>
</li>
</ul>
<h3 id="互联网概述"><a href="#互联网概述" class="headerlink" title="互联网概述"></a>互联网概述</h3><ul>
<li><p>网络和互联网</p>
<ul>
<li><p>网络:由若干<strong>结点</strong>(node)和连接这些结点的<strong>链路</strong>(link)组成。</p>
</li>
<li><p>互联网:网络之间通过路由器互联起来,这就构成一个覆盖范围更大的计算机网路。这样的网络称为<strong>互联网</strong></p>
</li>
<li><p>互联网是“网络的网络”</p>
<p><img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/network-of-networks.gif" alt=""></p>
</li>
</ul>
</li>
<li><p>Internet是从单个网络<strong>ARPANET</strong>发展过来的</p>
</li>
<li><p>ARPANET是美国国防部在1969创建的第一个分组交换网</p>
</li>
<li><p>1983年TCP/IP协议成为ARPANET上的标准协议</p>
</li>
</ul>
<h3 id="互联网的组成"><a href="#互联网的组成" class="headerlink" title="互联网的组成"></a>互联网的组成</h3><ul>
<li><p>资源子网、通信子网</p>
</li>
<li><p>端系统之间的通信方式:客户-服务器方式(C/S方式)、对等方式(P2P方式)</p>
</li>
<li><p>交换方式</p>
<ul>
<li><strong>电路交换</strong>:整个报文的比特流连续地从源点直达终点,好像在一个管道中传送<ul>
<li>若要连续传送大量的数据,且其传送时间远大于连接建立时间,则电路交换的传输速率较快。 </li>
<li>在通话的全部时间内,通话的两个用户始终占用端到端的通信</li>
</ul>
</li>
<li><strong>报文交换</strong>:整个报文先传送到相邻结点,全部存储下来后查找转发表,转发到下一个结点。</li>
<li><strong>分组交换</strong>:单个分组(整个报文的一部分)传送到相邻结点,存储下来后查找转发表,转发到下一个结点。<ul>
<li>报文交换和分组交换不需要预分配传输带宽,在传输突发数据时可提高整个网络的信道利用率。</li>
<li>由于分组的长度往往远小于整个报文的长度,因此分组交换比报文交换的时延小。</li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="计算机网络的类别"><a href="#计算机网络的类别" class="headerlink" title="计算机网络的类别"></a>计算机网络的类别</h3><ul>
<li><p>按照网络的作用范围进行分类</p>
<ul>
<li>广域网(WAN)</li>
<li>城域网(MAN)</li>
<li>局域网(LAN)</li>
<li>个人局域网(PAN)</li>
<li>无限个人局域网(WPAN)</li>
</ul>
</li>
<li><p>按照网络的使用者进行分类</p>
<ul>
<li>公用网(Public Network)</li>
<li>专用网(Private Network)</li>
</ul>
</li>
</ul>
<h3 id="计算机网络的性能指标"><a href="#计算机网络的性能指标" class="headerlink" title="计算机网络的性能指标"></a>计算机网络的性能指标</h3><ul>
<li><p>速率:数据的传送速率,也成数据率。单位:bit/s</p>
</li>
<li><p>带宽:单位时间内网络中的某信道所能通过的“最高数据率”。单位:bit/s</p>
</li>
<li><p>吞吐量:单位时间内通过某个网络的实际的数据量。有时吞吐量可用每秒传送的字节数或帧数来表示。</p>
</li>
<li><p>时延:指数据从网络的一端传送到另一端所需的时间。</p>
<ul>
<li><strong>总时延</strong>=发送时延+传播时延+处理时延+排队时延<br><img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/4b2ae78c-e254-44df-9e37-578e2f2bef52.jpg" alt=""><ul>
<li>发送时延:数据帧长度(bit)/发送速率(bit/s)</li>
<li>传播时延:信道长度(m)/电磁波在信道上的传播速率(m/s)</li>
<li>处理时延:从收到的分组中提取数据部分、进行差错检验或查找合适路由等需要花费一定的时间</li>
<li>排队时延:当某一时刻收到的分组数量大于路由器的处理速度,分组在进入路由器输入队列后排队等待所消耗的时间</li>
</ul>
</li>
</ul>
</li>
<li><p>时延带宽积=传播时延 X 带宽</p>
</li>
<li><p>往返时间RTT=发送时间+接收时间</p>
<ul>
<li>发送时间=接收时间=数据长度/发送速率。计算时需要统一单位</li>
<li>有效数据率=数据长度/(发送时间+RTT)</li>