-
Notifications
You must be signed in to change notification settings - Fork 0
/
search.xml
4848 lines (4441 loc) · 729 KB
/
search.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
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>UNIX下信号与进程关系学习</title>
<url>/2019/10/06/UNIX%E4%B8%8B%E4%BF%A1%E5%8F%B7%E4%B8%8E%E8%BF%9B%E7%A8%8B%E5%85%B3%E7%B3%BB%E5%AD%A6%E4%B9%A0/</url>
<content><![CDATA[<hr>
<span id="more"></span>
<h1 id="进程关系"><a href="#进程关系" class="headerlink" title="进程关系"></a>进程关系</h1><h3 id="终端登录"><a href="#终端登录" class="headerlink" title="终端登录"></a>终端登录</h3><p>在早期的UNIX系统中,是采用硬链接(哑终端)即本地连接或远程调制解调器登录的。</p>
<p>而如今,终端又有了基于字符的终端、图形终端、仿真基于字符终端的图形终端</p>
<p><img src="/images/20191007=0.png"><br><img src="/images/20191007=1.png"></p>
<p>为了使同一个软件既能处理终端登录,又能处理网络登录,系统使用了一种称为<strong>伪终端</strong>的软件驱动程序,它仿真串行终端的运行行为,并将终端操作映射为网络操作</p>
<p><img src="/images/20191007=2.png"></p>
<ul>
<li>inetd为一个因特网服务守护进程,它等待大多数网络连接</li>
</ul>
<p><img src="/images/20191007=3.png"></p>
<h3 id="进程组"><a href="#进程组" class="headerlink" title="进程组"></a>进程组</h3><p>进程组是一个或多个进程的集合。通常,它们是同一个作业里结合起来的,同一进程组中的的进程接受来自同一终端的各种信号</p>
<figure class="highlight sqf"><table><tr><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">"unistd.h"</span></span></span><br><span class="line"></span><br><span class="line"><span class="variable">__pid_t</span> getpgrp()</span><br><span class="line"></span><br><span class="line">返回进程的进程组id</span><br></pre></td></tr></table></figure>
<ul>
<li>每一个进程组都有一个组长进程,组长进程id等于进程组id</li>
<li>进程组的是否终止与其组长进程的终止无关,只要有一个进程存在即进程组存在</li>
<li>从进程组创建开始到最后一个进程结束的时间区间被称为其生命周期</li>
</ul>
<figure class="highlight sqf"><table><tr><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">"unistd.h"</span></span></span><br><span class="line"></span><br><span class="line">int setpgid(<span class="variable">__pid_t</span> <span class="variable">__pid</span>, <span class="variable">__pid_t</span> <span class="variable">__pgid</span>)</span><br><span class="line"></span><br><span class="line">成功返回<span class="number">0</span>,失败返回-<span class="number">1</span></span><br></pre></td></tr></table></figure>
<ul>
<li>将pid进程的进程组id设为pgid</li>
</ul>
<table>
<thead>
<tr>
<th align="center">pid = pgid</th>
<th align="center">则由pid指定的进程称为进程组组长</th>
</tr>
</thead>
<tbody><tr>
<td align="center">pid = 0</td>
<td align="center">则使用调用者id</td>
</tr>
<tr>
<td align="center">pgid = 0</td>
<td align="center">则由pid指定id作为进程组id</td>
</tr>
</tbody></table>
<h3 id="会话"><a href="#会话" class="headerlink" title="会话"></a>会话</h3><p>会话是一个或多个进程组的集合,通常是由shell是管道将其编为一组</p>
<figure class="highlight objectivec"><table><tr><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">"unistd.h"</span></span></span><br><span class="line"></span><br><span class="line">__pid_t setsid(<span class="type">void</span>)</span><br><span class="line"></span><br><span class="line">成功返回进程组<span class="type">id</span>,失败返回<span class="number">-1</span></span><br></pre></td></tr></table></figure>
<ul>
<li><p>若调用该函数的进程是一个进程组组长,则报错</p>
</li>
<li><p>若不是进程组组长,则会创建一个新会话</p>
<ol>
<li>该进程成为为该会话的会话首进程,此时是唯一的一个进程</li>
<li>该进程成为新进程组组长,新进程组id等于调用该函数进程id</li>
<li>该进程没有控制终端,若之前有会被切断</li>
</ol>
</li>
</ul>
<h3 id="控制终端"><a href="#控制终端" class="headerlink" title="控制终端"></a>控制终端</h3><ul>
<li>一个会话可以有一个控制终端。通常是终端设备或伪终端设备</li>
<li>建立和控制终端连接的会话首进程被称为控制进程</li>
<li>会话中的进程组可被分为前台和后台进程组</li>
<li>终端输入和产生的信号被送至前台进程组</li>
<li>终端接口检测到调制解调或网络断开,则将挂断信号发往控制进程(会话首进程))</li>
</ul>
<p><img src="/images/20191007=4.png"></p>
<h3 id="作业控制"><a href="#作业控制" class="headerlink" title="作业控制"></a>作业控制</h3><p>作业(进程组)控制它允许在一个终端启动多个作业,它控制那些哪些作业可以访问终端以及那些作<br>业可以在后台运行</p>
<p>作业控制需要以下支持:</p>
<ol>
<li>shell</li>
<li>终端驱动</li>
<li>内核</li>
</ol>
<p><img src="/images/20191007=5.png"></p>
<p>(SIGINT,SIGQUIT,SIGTST)分别对应字符c-c、c-/、c-d,具体由终端驱动程序决定</p>
<p>shell任务调度命令</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="built_in">bg</span></span><br><span class="line">将一个在后台暂停的命令,变成继续执行</span><br><span class="line"></span><br><span class="line"><span class="built_in">fg</span></span><br><span class="line">将后台中的命令调至前台继续运行</span><br><span class="line"></span><br><span class="line"><span class="built_in">jobs</span></span><br><span class="line">查看当前有多少在后台运行的命令</span><br><span class="line"></span><br><span class="line">ctrl + z</span><br><span class="line">可以将一个正在前台执行的命令放到后台,并且暂停</span><br><span class="line"></span><br><span class="line"><span class="built_in">nohup</span> 命令</span><br><span class="line"></span><br><span class="line">用途:不挂断地运行命令。</span><br><span class="line"></span><br><span class="line">语法:<span class="built_in">nohup</span> Command [ Arg … ] [ & ]</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<hr>
<h1 id="信号"><a href="#信号" class="headerlink" title="信号"></a>信号</h1><p>信号是软件中断</p>
<blockquote>
<p><a href="https://zh.wikipedia.org/wiki/%E4%B8%AD%E6%96%B7">中断</a>是用以提高计算机工作效率、增强计算机功能的一项重要技术。最初引入硬件中断,只是出于性能上的考量。如果计算机系统没有中断,则处理器与外部设备通信时,它必须在向该设备发出指令后进行忙等待(Busy waiting),反复轮询该设备是否完成了动作并返回结果。这就造成了大量处理器周期被浪费。引入中断以后,当处理器发出设备请求后就可以立即返回以处理其他任务,而当设备完成动作后,发送中断信号给处理器,后者就可以再回过头获取处理结果。这样,在设备进行处理的周期内,处理器可以执行其他一些有意义的工作,而只付出一些很小的切换所引发的时间代价。后来被用于CPU外部与内部紧急事件的处理、机器故障的处理、时间控制等多个方面,并产生通过软件方式进入中断处理(软中断)的概念。</p>
</blockquote>
<p>对于一个完整的信号生命周期(从信号发送到相应的处理函数执行完毕)来说,可以分为三个阶段:</p>
<ol>
<li><p>信号诞生</p>
</li>
<li><p>信号在进程中注册</p>
</li>
<li><p>信号的执行和注销</p>
</li>
</ol>
<h3 id="关于信号"><a href="#关于信号" class="headerlink" title="关于信号"></a>关于信号</h3><p>每一个信号都有名字,以SIG开头,在<**signal.h**>中,信号被定义为正整数常量(信号编号)</p>
<p>信息编号为0的被称为空信号</p>
<p>主要有以下几种来源:</p>
<ol>
<li><p>程序错误:除零,非法内存访问…</p>
</li>
<li><p>外部信号:终端Ctrl-C产生SGINT信号,定时器到期产生SIGALRM…</p>
</li>
<li><p>显式请求:kill函数允许进程发送任何信号给其他进程或进程组。</p>
</li>
</ol>
<p>一般情况下一个进程接受到信号后,会有如下的行为:</p>
<ol>
<li><p>忽略信号:大部分信号可被忽略,除SIGSTOP和SIGKILL信号外(这是超级用户杀掉或停掉任意进程的手段)。</p>
</li>
<li><p>捕获信号:注册信号处理函数,它对产生的特定信号做处理。</p>
</li>
<li><p>让信号默认动作起作用:unix内核定义的默认动作,有5种情况:<br> a) 流产abort:终止进程并产生core文件。</p>
</li>
</ol>
<p> b) 终止stop:终止进程但不生成core文件。</p>
<p> c) 忽略:忽略信号。</p>
<p> d) 挂起suspend:挂起进程。</p>
<p> e) 继续continue:若进程是挂起的,则resume进程,否则忽略此信号。</p>
<ul>
<li>目前Linux支持64种信号。信号分为非实时信号(不可靠信号)和实时信号(可靠信号)两种类型,对应于 Linux 的信号值为 1-31 和 34-64。信号是异步的,一个进程不必通过任何操作来等待信号的到达,事实上,进程也不知道信号到底什么时候到达</li>
</ul>
<h3 id="signal"><a href="#signal" class="headerlink" title="signal()"></a>signal()</h3><figure class="highlight sqf"><table><tr><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">"signal.h"</span></span></span><br><span class="line"></span><br><span class="line"><span class="variable">__sighandler_t</span> signal(int <span class="variable">__sig</span>, <span class="variable">__sighandler_t</span> <span class="variable">__handler</span>)</span><br><span class="line"></span><br><span class="line">成功返回之前的信号处理配置,失败返回SIG_ERR</span><br></pre></td></tr></table></figure>
<ul>
<li>第一个参数为信号编号,第二个参数为信号处理函数指针</li>
</ul>
<figure class="highlight cpp"><table><tr><td class="code"><pre><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">typedef</span> <span class="title">void</span> <span class="params">(*<span class="type">__sighandler_t</span>)</span> <span class="params">(<span class="type">int</span>)</span></span>; </span><br><span class="line"><span class="comment">/* 为一个参数为int名字为__sighandler_t的指针函数 且返回值为void */</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> SIG_ERR ((__sighandler_t) -1) <span class="comment">/* Error return. */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> SIG_DFL ((__sighandler_t) 0) <span class="comment">/* Default action. */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> SIG_IGN ((__sighandler_t) 1) <span class="comment">/* Ignore signal. */</span></span></span><br><span class="line"></span><br></pre></td></tr></table></figure>
<ul>
<li><p>当一个程序启动时,所有的信号状态都是默认或忽略</p>
</li>
<li><p>当一个进程调用fork(),子进程默认继承父进程处理方式</p>
</li>
</ul>
<h3 id="系统调用的中断"><a href="#系统调用的中断" class="headerlink" title="系统调用的中断"></a>系统调用的中断</h3><p>捕捉到信号的时候,中断的是系统调用而不是函数(因为函数调用的是系统调用)</p>
<p>系统调用分成两类:低速系统调用和其他系统调用。低速系统调用是可能会使进程永远阻塞的一类系统调用:</p>
<ol>
<li>在读某些类型的文件(管道,终端设备以及网络设备)时,如果数据并不存在则可能会使调用者永远阻塞。</li>
<li>在写这些类型的文件时,如果不能立即接受这些数据,则会使调用者永远阻塞。</li>
<li>打开某些类型的文件,在某些条件发生之前也可能会使调用者阻塞(例如,打开终端设备,它要等待直到所连接的调制解调器应答了电话)</li>
<li>pause函数和wait函数</li>
<li>某些ioctl函数</li>
<li>某些进程间通信函数。</li>
</ol>
<p>与被中断的系统调用相关的问题是必须显式地处理出错返回。典型的代码如下:</p>
<figure class="highlight scss"><table><tr><td class="code"><pre><span class="line">again:</span><br><span class="line">if((n=read(fd,buf,BUFFSIZE))<<span class="number">0</span>){</span><br><span class="line"> <span class="built_in">if</span>(errno == EINTR)</span><br><span class="line"> goto again;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h3 id="可靠信号术语及语义"><a href="#可靠信号术语及语义" class="headerlink" title="可靠信号术语及语义"></a>可靠信号术语及语义</h3><p>当一个信号产生时,内核会在进程表中以某种方式设置一个标志,当对信号采取了这种动作时,我们说向进程递送了一个信号。</p>
<p>在信号产生(generation)和递送(delivery)之间的时间间隔,称信号是未决的(pending)。</p>
<p>进程可以选用信号递送阻塞。如果为进程产生了一个选择为阻塞的信号,而且对该信号的动作是系统默认动作或捕捉该信号,则为该进程将此信号保持为未决状态,直到该进程(a)对此信号解除了阻塞,或者(b)将对此信号的动作更改为忽略。内核在递送一个原来被阻塞(现在解除了阻塞)的信号给进程时(而不是在产生该信号时),才决定对它的处理方式。于是进程在信号递送给它之前仍可改变对该信号的动作。进程调用sigpending函数来判定哪些信号是设置为阻塞并处于未决状态的。</p>
<p>在进程结束对某个信号的堵塞前,系统递送这种信号多次,可称这些信号进行了排队</p>
<p>每个进程都有一个信号屏蔽字(signal mask),它规定了当前要阻塞递送到该进程的信号集。对于每种可能的信号,该屏蔽字中都有一位与之对应。对于某种信号,若其对应位已设置,则它当前是被阻塞的。进程可以调用sigprocmask来检测和更改其当前信号屏蔽字。</p>
<h3 id="kill-x2F-raise"><a href="#kill-x2F-raise" class="headerlink" title="kill()/raise()"></a>kill()/raise()</h3><p>kill将信号发给进程或进程组,raise可将信号发给自己</p>
<figure class="highlight autoit"><table><tr><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">"signal.h"</span></span></span><br><span class="line"></span><br><span class="line"><span class="built_in">int</span> kill(pit_t pit,<span class="built_in">int</span> __sig)</span><br><span class="line"></span><br><span class="line"><span class="built_in">int</span> raise(<span class="built_in">int</span> __sig)</span><br><span class="line"></span><br><span class="line">成功返回<span class="number">0</span>,失败返回<span class="number">-1</span></span><br></pre></td></tr></table></figure>
<table>
<thead>
<tr>
<th align="center">pid</th>
<th align="center">含义</th>
</tr>
</thead>
<tbody><tr>
<td align="center">pid > 0</td>
<td align="center">将信号发给pid进程</td>
</tr>
<tr>
<td align="center">pid ==0</td>
<td align="center">将信号发给同一个进程组的进程(前提是该进程有权限发送信号给进程组)</td>
</tr>
<tr>
<td align="center">pid <0</td>
<td align="center">将信号发给pid的绝对值的进程和所有有权限发送的进程</td>
</tr>
<tr>
<td align="center">pid ==-1</td>
<td align="center">将信号发给所有有权限发送的进程</td>
</tr>
</tbody></table>
<p><img src="/images/20191007=6.png"></p>
<p>权限的基本判别方法为:</p>
<ul>
<li>发送者有效id或实际id等于接受者有效id或实际id</li>
</ul>
<h3 id="alarm-、pause"><a href="#alarm-、pause" class="headerlink" title="alarm()、pause()"></a>alarm()、pause()</h3><p>alarm()可设置一个定时器,当定时器超时时会产生一个SIGALRM信号,但不捕捉或忽略它时,默认结束该进程</p>
<figure class="highlight objectivec"><table><tr><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">"unistd.h"</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">unsigned</span> <span class="type">int</span> alarm(<span class="type">unsigned</span> <span class="type">int</span> __seconds)</span><br><span class="line"></span><br><span class="line">返回<span class="number">0</span>或以前设置的时间</span><br></pre></td></tr></table></figure>
<ul>
<li>当信号产生时,由于进程调度的延迟,进程并不能及时得到控制及处理信号</li>
<li>每个进程只能有一个闹钟时间。若之前有一个时间,则返回之前时间的余值,且用新值代替旧值</li>
<li>若之前注册了一个时间且没有超时,而调用时seconds为0,则取消以前的闹钟时间,余值作为返回值</li>
</ul>
<p>使调用进程挂起直至捕捉到一个信号</p>
<figure class="highlight objectivec"><table><tr><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">"unistd.h"</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">int</span> pause(<span class="type">void</span>)</span><br><span class="line"></span><br><span class="line">返回值为<span class="number">-1</span>,errno为EINTR</span><br></pre></td></tr></table></figure>
<ul>
<li>当执行完信号处理函数才返回</li>
</ul>
<h3 id="abort"><a href="#abort" class="headerlink" title="abort()"></a>abort()</h3><figure class="highlight cpp"><table><tr><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><stdlib.h></span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">abort</span><span class="params">(<span class="type">void</span>)</span></span>;</span><br><span class="line"></span><br><span class="line">无返回值</span><br></pre></td></tr></table></figure>
<ul>
<li>向进程发送SIGABORT信号,默认情况下进程会异常退出,当然可定义自己的信号处理函数。即使SIGABORT被进程设置为阻塞信号,调用abort()后,SIGABORT仍然能被进程接收。</li>
</ul>
<h3 id="sigqueue()"><a href="#sigqueue()" class="headerlink" title="sigqueue()"></a>sigqueue()</h3><figure class="highlight objectivec"><table><tr><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><sys/types.h></span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><signal.h></span></span></span><br><span class="line"></span><br><span class="line"><span class="type">int</span> sigqueue(pid_t pid, <span class="type">int</span> sig, <span class="keyword">const</span> <span class="keyword">union</span> sigval val)</span><br><span class="line"></span><br><span class="line">调用成功返回 <span class="number">0</span>;否则,返回 <span class="number">-1</span>。</span><br></pre></td></tr></table></figure>
<ul>
<li><p>sigqueue()是比较新的发送信号系统调用,主要是针对实时信号提出的(当然也支持前32种),支持信号带有参数,与函数sigaction()配合使用。</p>
</li>
<li><p>sigqueue的第一个参数是指定接收信号的进程ID,第二个参数确定即将发送的信号,第三个参数是一个联合数据结构union sigval,指定了信号传递的参数,即通常所说的4字节值。</p>
<figure class="highlight cpp"><table><tr><td class="code"><pre><span class="line"><span class="keyword">typedef</span> <span class="keyword">union</span> <span class="title class_">sigval</span> {</span><br><span class="line"></span><br><span class="line"> <span class="type">int</span> sival_int;</span><br><span class="line"></span><br><span class="line"> <span class="type">void</span> *sival_ptr;</span><br><span class="line"></span><br><span class="line">}<span class="type">sigval_t</span>;</span><br><span class="line"></span><br></pre></td></tr></table></figure>
</li>
<li><p>sigqueue()比kill()传递了更多的附加信息,但sigqueue()只能向一个进程发送信号,而不能发送信号给一个进程组。如果signo=0,将会执行错误检查,但实际上不发送任何信号,0值信号可用于检查pid的有效性以及当前进程是否有权限向目标进程发送信号。</p>
</li>
<li><p>在调用sigqueue时,sigval_t指定的信息会拷贝到对应sig 注册的3参数信号处理函数的siginfo_t结构中,这样信号处理函数就可以处理这些信息了。由于sigqueue系统调用支持发送带参数信号,所以比kill()系统调用的功能要灵活和强大得多。</p>
</li>
</ul>
<h3 id="sigaction"><a href="#sigaction" class="headerlink" title="sigaction()"></a>sigaction()</h3><p><a href="https://blog.csdn.net/return_cc/article/details/78845346">完善版signal()</a></p>
<p>新可靠信号<br><img src="/images/20191007=7.png"></p>
<h3 id="信号集"><a href="#信号集" class="headerlink" title="信号集"></a>信号集</h3><p>信号集被定义为一种数据类型,</p>
<figure class="highlight cpp"><table><tr><td class="code"><pre><span class="line"><span class="keyword">typedef</span> <span class="keyword">struct</span> {</span><br><span class="line"></span><br><span class="line"> <span class="type">unsigned</span> <span class="type">long</span> sig[_NSIG_WORDS];</span><br><span class="line"></span><br><span class="line">} <span class="type">sigset_t</span></span><br></pre></td></tr></table></figure>
<p>信号集用来描述信号的集合,每个信号占用一位。Linux所支持的所有信号可以全部或部分的出现在信号集中</p>
<h3 id="linux下的信号应用常见三步法"><a href="#linux下的信号应用常见三步法" class="headerlink" title="linux下的信号应用常见三步法"></a>linux下的信号应用常见三步法</h3><ol>
<li><p>安装信号(推荐使用sigaction()) [signal()]</p>
</li>
<li><p>实现三参数信号处理函数,handler(int signal,struct siginfo *info, void *);</p>
</li>
<li><p>发送信号,推荐使用sigqueue() [kill()\raise()]</p>
</li>
</ol>
<p>实际上,对有些信号来说,只要安装信号就足够了(信号处理方式采用缺省或忽略)。其他可能要做的无非是与信号集相关的几种操作。</p>
<hr>
<p><a href="http://m.elecfans.com/article/579913.html">参考资料</a><br><a href="https://blog.csdn.net/return_cc/article/details/78845346">完善版signal</a></p>
]]></content>
<tags>
<tag>c</tag>
<tag>linux</tag>
</tags>
</entry>
<entry>
<title>LVS学习</title>
<url>/2020/05/10/LVS%E5%AD%A6%E4%B9%A0/</url>
<content><![CDATA[<hr>
<span id="more"></span>
<p>记录的非常详细,值得学习–> <a href="http://superproxy.github.io/docs/lvs/index.html">LVS介绍</a></p>
]]></content>
<tags>
<tag>linux</tag>
<tag>LVS</tag>
</tags>
</entry>
<entry>
<title>UNIX下套接字学习</title>
<url>/2020/01/15/UNIX%E4%B8%8B%E5%A5%97%E6%8E%A5%E5%AD%97%E5%AD%A6%E4%B9%A0/</url>
<content><![CDATA[<hr>
<span id="more"></span>
<p>socket 是进程间通信方法中的一种,其他的还有管道,命名管道,信号量,信号,共享内存,消息队列</p>
<p>总体来说,建立一个socket连接分为以下几步<br><img src="/images/20200115=0.png"></p>
<table>
<thead>
<tr>
<th align="center">server</th>
<th align="center">client</th>
</tr>
</thead>
<tbody><tr>
<td align="center">socket()</td>
<td align="center">socket()</td>
</tr>
<tr>
<td align="center">bind()</td>
<td align="center"></td>
</tr>
<tr>
<td align="center">listen()</td>
<td align="center"></td>
</tr>
<tr>
<td align="center">accpet()</td>
<td align="center"></td>
</tr>
</tbody></table>
<pre><code> |connect()
</code></pre>
<p>send() | recv()<br>close() | close()</p>
<h1 id="socket"><a href="#socket" class="headerlink" title="socket()"></a>socket()</h1><p>用于新建一个套接字文件描述符,对于服务器将在这个描述符上监听端口,对于客户端将在这个描述符上建立连接</p>
<figure class="highlight autoit"><table><tr><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><sys/socket.h></span></span></span><br><span class="line"></span><br><span class="line"><span class="built_in">int</span> socket(<span class="built_in">int</span> doamin, <span class="built_in">int</span> type , <span class="built_in">int</span> protocol)</span><br><span class="line"></span><br><span class="line">成功返回文件描述符,失败返回<span class="number">-1</span></span><br></pre></td></tr></table></figure>
<p>常见domain </p>
<ul>
<li>AF_INET</li>
<li>AF_INET6</li>
<li>AF_UNIX (本地通讯)</li>
</ul>
<p>常见type</p>
<ul>
<li>SOCK_STREAM 提供基于连接可靠的、有顺序的、双工的字节流 (运输层采用的是TCP)</li>
<li>SOCK_DGRAM 提供了无连接的数据报支持 (采用UDP)</li>
<li>SOCK_RAW 提供了原始网络接口访问 (用于底层操作)</li>
</ul>
<h1 id="相关数据结构及转换函数"><a href="#相关数据结构及转换函数" class="headerlink" title="相关数据结构及转换函数"></a>相关数据结构及转换函数</h1><figure class="highlight cpp"><table><tr><td class="code"><pre><span class="line"><span class="keyword">struct</span> <span class="title class_">sockaddr</span> {</span><br><span class="line"><span class="type">unsigned</span> <span class="type">short</span> sa_family;</span><br><span class="line"><span class="comment">/* address族, AF_xxx */</span></span><br><span class="line"><span class="type">char</span> sa_data[<span class="number">14</span>];</span><br><span class="line"><span class="comment">/* 14 bytes 的协议地址 */</span></span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="comment">//in指的是 internet</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">struct</span> <span class="title class_">sockaddr_in</span>{</span><br><span class="line"> <span class="type">short</span> <span class="type">int</span> sin_family ; <span class="comment">// 协议族</span></span><br><span class="line"> <span class="type">unsigned</span> <span class="type">short</span> <span class="type">int</span> sin_port ; <span class="comment">// 端口号</span></span><br><span class="line"> <span class="keyword">struct</span> <span class="title class_">in_addr</span> sin_addr ; <span class="comment">// internet 地址</span></span><br><span class="line"> <span class="type">unsigned</span> <span class="type">char</span> sin_zero[<span class="number">8</span>]; <span class="comment">// 置0</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// 存放internet 地址</span></span><br><span class="line"><span class="keyword">struct</span> <span class="title class_">in_addr</span>{</span><br><span class="line"> <span class="type">unsigned</span> <span class="type">long</span> s_addr;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>由于不同主机架构不同所定义的主机顺序不同,为了让数据在网络通讯中保持一致,所以还<br>有一些转换函数帮忙转换大端小端数据</p>
<figure class="highlight cpp"><table><tr><td class="code"><pre><span class="line">网络通信采用是大端顺序</span><br><span class="line"></span><br><span class="line">大端是指数据高字节存储在内存低有效位上</span><br><span class="line">小端则是数据高字节存储在内存高有效位上</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="meta">#<span class="keyword">include</span> <span class="string"><arpa/inet.h></span></span></span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="type">uint32_t</span> <span class="title">htonl</span><span class="params">(<span class="type">uint32_t</span> hostlong)</span></span>;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="type">uint16_t</span> <span class="title">htons</span><span class="params">(<span class="type">uint16_t</span> hostshort)</span></span>;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="type">uint32_t</span> <span class="title">ntohl</span><span class="params">(<span class="type">uint32_t</span> netlong)</span></span>;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="type">uint16_t</span> <span class="title">ntohs</span><span class="params">(<span class="type">uint16_t</span> netshort)</span></span>;</span><br></pre></td></tr></table></figure>
<ul>
<li>这里的h指的是host ,即主机顺序</li>
<li>n指的则是网络顺序,nl则是64bit(8 bytes)长度,ns是32bit( 4 bypes)长度</li>
</ul>
<p>举个例子</p>
<figure class="highlight cpp"><table><tr><td class="code"><pre><span class="line"><span class="keyword">struct</span> <span class="title class_">sockaddr_in</span>{</span><br><span class="line"> <span class="type">short</span> <span class="type">int</span> sin_family ; <span class="comment">// 协议族</span></span><br><span class="line"> <span class="type">unsigned</span> <span class="type">short</span> <span class="type">int</span> sin_port ; <span class="comment">// 端口号</span></span><br><span class="line"> <span class="keyword">struct</span> <span class="title class_">in_addr</span> sin_addr ; <span class="comment">// internet 地址</span></span><br><span class="line"> <span class="type">unsigned</span> <span class="type">char</span> sin_zero[<span class="number">8</span>]; <span class="comment">// 置0</span></span><br><span class="line">}addr;</span><br><span class="line"></span><br><span class="line"><span class="built_in">memset</span>(&addr,<span class="number">0</span>,<span class="built_in">sizeof</span>(addr));</span><br><span class="line">addr.sin_port = <span class="built_in">htons</span>(<span class="number">1234</span>); <span class="comment">/* 查看addr.sin_port 定义为unsigned short int */</span> </span><br><span class="line"></span><br></pre></td></tr></table></figure>
<ul>
<li>可见只需调用转换函数就可以不用关心自己主机是大端序还是<br>小端序了,统统转换为网络顺序即可</li>
</ul>
<p>当然如何判断大小端也是需要知道的</p>
<figure class="highlight cpp"><table><tr><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><stdio.h></span></span></span><br><span class="line"><span class="keyword">union</span> <span class="title class_">tmp</span>{</span><br><span class="line"> <span class="type">unsigned</span> <span class="type">short</span> <span class="type">int</span> val;</span><br><span class="line"> <span class="type">char</span> date;</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="comment">/*--------------------------------------------------------------</span></span><br><span class="line"><span class="comment"> 利用指针强制转换</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="type">int</span> i = <span class="number">1</span> ;</span><br><span class="line"> <span class="type">unsigned</span> <span class="type">char</span> * p = (<span class="type">unsigned</span> <span class="type">char</span> * )&i;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span>(*p)</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"small "</span>);</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"big "</span>);</span><br><span class="line"></span><br><span class="line"> <span class="comment">/*--------------------------------------------------------------</span></span><br><span class="line"><span class="comment"> 初始化一个16进制的类型的数据,然后把它放在一个char类型的数组中,由于十六进制的</span></span><br><span class="line"><span class="comment"> 数据一位代表四个bit位char型是8个bit位,那么十六进制的两位占一个char位,那么就可</span></span><br><span class="line"><span class="comment"> 以把数据位分离。</span></span><br><span class="line"><span class="comment"> 若是小字节,数值高字节在高有效位</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="type">unsigned</span> <span class="type">short</span> <span class="type">int</span> a = <span class="number">0x1122</span>;</span><br><span class="line"> <span class="type">unsigned</span> <span class="type">char</span> *pp = (<span class="type">unsigned</span> <span class="type">char</span> *)&a;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span>(pp[<span class="number">0</span>]==<span class="number">0x22</span> && pp[<span class="number">1</span>] == <span class="number">0x11</span>) </span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"small "</span>);</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"big "</span>);</span><br><span class="line"></span><br><span class="line"> <span class="comment">/*--------------------------------------------------------------</span></span><br><span class="line"><span class="comment"> 利用共用体内存占用为最小占用者大小性质</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">union</span> <span class="title class_">tmp</span> t;</span><br><span class="line"> t.val = <span class="number">0x1122</span>;</span><br><span class="line"> <span class="keyword">if</span>(t.date == <span class="number">0x11</span>)</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"big "</span>);</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"small "</span>);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>从sockaddr_in这个数据结构看出不仅有端口需要转换,还有ip地址也需要转换</p>
<figure class="highlight cpp"><table><tr><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><sys/socket.h></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><netinet/in.h></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><arpa/inet.h></span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">inet_aton</span><span class="params">(<span class="type">const</span> <span class="type">char</span> *cp, <span class="keyword">struct</span> in_addr *inp)</span></span>;</span><br><span class="line"><span class="comment">// 将cp所指向的.和数字组成的ip地址字符串转化为网络序存储在inp指向结构内</span></span><br><span class="line"><span class="function"><span class="type">char</span> *<span class="title">inet_ntoa</span><span class="params">(<span class="keyword">struct</span> in_addr in)</span></span>;<span class="comment">//</span></span><br><span class="line"><span class="comment">//跟上面函数相反,返回的为静态分配的数组</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">in_addr_t</span> <span class="title">inet_addr</span><span class="params">(<span class="type">const</span> <span class="type">char</span> *cp)</span></span>;</span><br><span class="line"><span class="comment">//将.和数字组成的ip地址字符串转换为网络序</span></span><br></pre></td></tr></table></figure>
<ul>
<li>简单例子<code>addr.sin_addr.s_addr = inet_addr("127.0.0.1");</code></li>
</ul>
<hr>
<h1 id="bind"><a href="#bind" class="headerlink" title="bind()"></a>bind()</h1><p>用于将地址和套接字描述符绑定</p>
<figure class="highlight cpp"><table><tr><td class="code"><pre><span class="line"> <span class="meta">#<span class="keyword">include</span> <span class="string"><sys/socket.h></span></span></span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="type">int</span> <span class="title">bind</span><span class="params">(<span class="type">int</span> sockfd, <span class="type">const</span> <span class="keyword">struct</span> sockaddr *addr,</span></span></span><br><span class="line"><span class="params"><span class="function"> <span class="type">socklen_t</span> addrlen)</span></span>;</span><br><span class="line"></span><br><span class="line">失败返回<span class="number">-1</span></span><br></pre></td></tr></table></figure>
<ul>
<li><p>从定义看出该函数用的是sockaddr结构,从sockaddr和sockaddr_in定义可以发现,这两个结构其实是等价的,sockaddr_in中的sin_port占两字节,sin_addr占4字节,sin_zero[8]为8字节,加起来刚好等于14字节对应sockaddr的sa_data[14]</p>
</li>
<li><p>所以我们可以通过sockaddr_in方便访问地址的每一部分,最后需要sockaddr的时候再进行类型转换就够了</p>
</li>
<li><p>当然数据都必须是网络字节顺序</p>
</li>
<li><p><code>bind(sockfd,(struct sockaddr *)addr_in,sizeof(addr_in));</code></p>
</li>
</ul>
<hr>
<h1 id="listen"><a href="#listen" class="headerlink" title="listen()"></a>listen()</h1><p>在一个套接字上监听一个连接</p>
<figure class="highlight cpp"><table><tr><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><sys/socket.h></span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">listen</span><span class="params">(<span class="type">int</span> sockfd, <span class="type">int</span> backlog)</span></span>;</span><br><span class="line"></span><br><span class="line">失败返回<span class="number">-1</span></span><br></pre></td></tr></table></figure>
<ul>
<li>backlog 为监听队列上最大监听数量</li>
<li>失败返回时具体原因代码存储在全局变量errno中,若在程序中使用了多个errno,在打印错误时要现将errno置0,否则errno可能为上一个发生的错误</li>
<li>errno 定义于 <code> <errno.h></code></li>
</ul>
<figure class="highlight cpp"><table><tr><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><stdio.h></span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">perror</span><span class="params">(<span class="type">const</span> <span class="type">char</span> *s)</span></span>;</span><br><span class="line"><span class="comment">// 可方便的将errno对应的原因打印出来</span></span><br><span class="line"><span class="comment">// 打印格式为 *s :error reason</span></span><br><span class="line"></span><br></pre></td></tr></table></figure>
<hr>
<h1 id="accept"><a href="#accept" class="headerlink" title="accept()"></a>accept()</h1><p>用于接受一个套接字连接,并返回新的套接字描述符</p>
<figure class="highlight cpp"><table><tr><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><sys/socket.h></span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">accept</span><span class="params">(<span class="type">int</span> sockfd, <span class="type">void</span> *addr, <span class="type">int</span> *addrlen)</span></span>;</span><br><span class="line"></span><br><span class="line">成功返回一个新的套接字描述符,失败返回<span class="number">-1</span></span><br></pre></td></tr></table></figure>
<ul>
<li>sockfd为之前监听的套接字</li>
<li>addr保存了远程机器连接的信息</li>
<li>*addelen为指向addr长度的指针</li>
<li>这里返回新的描述符用于进行读写操作,区别与之前用于监听的描述符</li>
</ul>
<hr>
<h1 id="connect"><a href="#connect" class="headerlink" title="connect()"></a>connect()</h1><p>建立一个新的套接字连接,客户端用于连接服务器</p>
<figure class="highlight cpp"><table><tr><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><sys/socket.h></span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">connect</span><span class="params">(<span class="type">int</span> sockfd, <span class="type">const</span> <span class="keyword">struct</span> sockaddr *addr,</span></span></span><br><span class="line"><span class="params"><span class="function"> <span class="type">socklen_t</span> addrlen)</span></span>;</span><br><span class="line"></span><br><span class="line"> 失败返回<span class="number">-1</span></span><br></pre></td></tr></table></figure>
<ul>
<li>这里的addr 是目标连接机器的信息结构</li>
</ul>
<hr>
<h1 id="recv-、send"><a href="#recv-、send" class="headerlink" title="recv()、send()"></a>recv()、send()</h1><p>类似与read()、write()</p>
<figure class="highlight cpp"><table><tr><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><sys/socket.h></span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">ssize_t</span> <span class="title">recv</span><span class="params">(<span class="type">int</span> sockfd, <span class="type">void</span> *buf, <span class="type">size_t</span> len, <span class="type">int</span> flags)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">ssize_t</span> <span class="title">send</span><span class="params">(<span class="type">int</span> sockfd, <span class="type">const</span> <span class="type">void</span> *buf, <span class="type">size_t</span> len, <span class="type">int</span> flags)</span></span>;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">返回接收、发送字节数</span><br></pre></td></tr></table></figure>
<ul>
<li>flags一般设为0</li>
</ul>
<hr>
<h1 id="简单C-x2F-S实现"><a href="#简单C-x2F-S实现" class="headerlink" title="简单C/S实现"></a>简单C/S实现</h1><p>服务端</p>
<figure class="highlight cpp"><table><tr><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><stdio.h></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><stdlib.h></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><sys/socket.h></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><arpa/inet.h></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><string.h></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><unistd.h></span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> IP <span class="string">"127.0.0.1"</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> PORT 1234</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> MAXLOG 10</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">server_error_exit</span><span class="params">(<span class="type">int</span> ,<span class="type">char</span> *)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"service is running at %s:%d\n"</span>,IP,PORT);</span><br><span class="line"> <span class="type">int</span> fd = <span class="built_in">socket</span>(AF_INET,SOCK_STREAM,<span class="number">0</span>);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span>(fd < <span class="number">0</span>)</span><br><span class="line"> <span class="built_in">server_error_exit</span>(fd,<span class="string">"init socket "</span>);</span><br><span class="line"></span><br><span class="line"> <span class="comment">// init local data structure</span></span><br><span class="line"> <span class="keyword">struct</span> <span class="title class_">sockaddr_in</span> addr_in;</span><br><span class="line"> <span class="built_in">memset</span>(&addr_in,<span class="number">0</span>,<span class="built_in">sizeof</span>(addr_in));</span><br><span class="line"> addr_in.sin_addr.s_addr = <span class="built_in">inet_addr</span>(IP);</span><br><span class="line"> addr_in.sin_family = AF_INET;</span><br><span class="line"> addr_in.sin_port = <span class="built_in">htons</span>(PORT);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span>(<span class="built_in">bind</span>(fd,(<span class="keyword">struct</span> sockaddr *)&addr_in,<span class="built_in">sizeof</span>(addr_in)) < <span class="number">0</span>)</span><br><span class="line"> <span class="built_in">server_error_exit</span>(fd,<span class="string">"bind "</span>);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span>(<span class="built_in">listen</span>(fd,MAXLOG) < <span class="number">0</span>)</span><br><span class="line"> <span class="built_in">server_error_exit</span>(fd,<span class="string">"listen error "</span>);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">struct</span> <span class="title class_">sockaddr_in</span> sock ;</span><br><span class="line"> <span class="type">uint32_t</span> sock_len = <span class="built_in">sizeof</span>(sock);</span><br><span class="line"> <span class="type">int</span> fd_d = <span class="built_in">accept</span>(fd,(<span class="keyword">struct</span> sockaddr *)&sock,&sock_len);</span><br><span class="line"> <span class="keyword">if</span>(fd_d < <span class="number">0</span> )</span><br><span class="line"> <span class="built_in">server_error_exit</span>(fd_d,<span class="string">"accept error "</span>);</span><br><span class="line"></span><br><span class="line"> <span class="type">char</span> buf[<span class="number">40</span>]=<span class="string">" \nthis is server"</span>;</span><br><span class="line"> <span class="built_in">send</span>(fd_d,buf,<span class="built_in">sizeof</span>(buf),<span class="number">0</span>);</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"do you accept ? "</span>);</span><br><span class="line"> <span class="built_in">sleep</span>(<span class="number">5</span>);</span><br><span class="line"></span><br><span class="line"> <span class="built_in">memset</span>(buf,<span class="number">0</span>,<span class="built_in">sizeof</span>(buf));</span><br><span class="line"> <span class="built_in">recv</span>(fd_d,buf,<span class="built_in">sizeof</span>(buf),<span class="number">0</span>);</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"\n%s remote port is %d"</span>,buf,<span class="built_in">ntohs</span>(sock.sin_port));</span><br><span class="line"></span><br><span class="line"> <span class="comment">//为了完整抓到四次挥手中的最后一次挥手</span></span><br><span class="line"> <span class="built_in">sleep</span>(<span class="number">1</span>);</span><br><span class="line"></span><br><span class="line"> <span class="built_in">close</span>(fd);</span><br><span class="line"> <span class="built_in">close</span>(fd_d);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">server_error_exit</span><span class="params">(<span class="type">int</span> fd,<span class="type">char</span> *buf)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="built_in">perror</span>(buf);</span><br><span class="line"> <span class="built_in">close</span>(fd);</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>客户端</p>
<figure class="highlight cpp"><table><tr><td class="code"><pre><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><stdio.h></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><string.h></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><arpa/inet.h></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><sys/socket.h></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><unistd.h></span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> IP <span class="string">"127.0.0.1"</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> PORT 1234</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">client_error_exit</span><span class="params">(<span class="type">int</span>,<span class="type">char</span> *)</span></span>;</span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span>{</span><br><span class="line"> <span class="comment">//init a socket</span></span><br><span class="line"> <span class="type">int</span> fd = <span class="built_in">socket</span>(AF_INET,SOCK_STREAM,<span class="number">0</span>);</span><br><span class="line"> <span class="keyword">if</span>(fd < <span class="number">0</span>)</span><br><span class="line"> <span class="built_in">client_error_exit</span>(fd,<span class="string">"socket init "</span>);</span><br><span class="line"></span><br><span class="line"> <span class="comment">//init remote pc data structure</span></span><br><span class="line"> <span class="keyword">struct</span> <span class="title class_">sockaddr_in</span> sock;</span><br><span class="line"> <span class="built_in">memset</span>(&sock,<span class="number">0</span>,<span class="built_in">sizeof</span>(sock));</span><br><span class="line"> sock.sin_addr.s_addr = <span class="built_in">inet_addr</span>(IP);</span><br><span class="line"> sock.sin_family = AF_INET;</span><br><span class="line"> sock.sin_port = <span class="built_in">ntohs</span>(PORT);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span>(<span class="built_in">connect</span>(fd,(<span class="keyword">struct</span> sockaddr *)&sock,<span class="built_in">sizeof</span>(sock)) < <span class="number">0</span>)</span><br><span class="line"> <span class="built_in">client_error_exit</span>(fd,<span class="string">"connect error "</span>);</span><br><span class="line"></span><br><span class="line"> <span class="comment">// read data from fd</span></span><br><span class="line"> <span class="type">char</span> buf[<span class="number">100</span>] = {<span class="number">0</span>};</span><br><span class="line"> <span class="keyword">if</span>(<span class="built_in">recv</span>(fd,buf,<span class="built_in">sizeof</span>(buf),<span class="number">0</span>) < <span class="number">0</span>)</span><br><span class="line"> <span class="built_in">client_error_exit</span>(fd,<span class="string">"recv "</span>);</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"this is client ! that is ? %s "</span>,buf);</span><br><span class="line"> <span class="built_in">sleep</span>(<span class="number">5</span>);</span><br><span class="line"></span><br><span class="line"> <span class="comment">// write data to fd</span></span><br><span class="line"> <span class="type">char</span> a[] = <span class="string">"yes !"</span>;</span><br><span class="line"> <span class="built_in">send</span>(fd,a,<span class="built_in">sizeof</span>(a),<span class="number">0</span>);</span><br><span class="line"></span><br><span class="line"> <span class="built_in">close</span>(fd);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">client_error_exit</span><span class="params">(<span class="type">int</span> fd,<span class="type">char</span> *buf)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="built_in">perror</span>(buf);</span><br><span class="line"> <span class="built_in">close</span>(fd);</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<figure class="highlight axapta"><table><tr><td class="code"><pre><span class="line">$ service <span class="keyword">is</span> running at <span class="number">127.0</span><span class="number">.0</span><span class="number">.1</span>:<span class="number">1234</span></span><br><span class="line"><span class="keyword">do</span> you accept ? </span><br><span class="line">yes ! remote port <span class="keyword">is</span> <span class="number">33744</span>% </span><br><span class="line"></span><br><span class="line"></span><br><span class="line">$ <span class="keyword">this</span> <span class="keyword">is</span> <span class="keyword">client</span> ! that <span class="keyword">is</span> ? </span><br><span class="line"><span class="keyword">this</span> <span class="keyword">is</span> <span class="keyword">server</span> % </span><br></pre></td></tr></table></figure>
<ul>
<li>可见正常工作</li>
</ul>
<hr>
<h1 id="抓包分析报文"><a href="#抓包分析报文" class="headerlink" title="抓包分析报文"></a>抓包分析报文</h1><figure class="highlight cmake"><table><tr><td class="code"><pre><span class="line">sudo apt <span class="keyword">install</span> -y wireshark </span><br><span class="line">sudo wireshark</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<ul>
<li><p>选择loop接口,分别运行server和client</p>
</li>
<li><p>在筛选框输入<code>tcp.port == 1234</code>,于是得到<br><img src="/images/20200115=1.png"></p>
</li>
<li><p>TCP报文格式<br><img src="/images/20200115=2.png"></p>
</li>
</ul>
<h2 id="TCP三次握手"><a href="#TCP三次握手" class="headerlink" title="TCP三次握手"></a>TCP三次握手</h2><p><img src="/images/20200115=4.png"></p>
<ol>
<li>客户端向服务器发起连接请求,SYN = 1 ,seq = 0,ack = 0</li>
<li>服务器收到后,允许建立连接,发送ACK = 1,SYN = 1 , seq = 0, ack = 1(表示客户端seq = 0 的报文收到)</li>
<li>客户端最后向服务器确认,发送ACK = 1,seq = 1 ,ack = 1(表示服务器seq = 0 的报文收到)</li>
</ol>
<ul>
<li>然后就可以发送数据了</li>
</ul>
<p>为什么需要三次握手</p>
<ul>
<li>为了确认SYN的有效性:如果是一次握手的话,客户端无法知道服务器是否建立了连接,两次握手的话只能确定服务器收到了客户端发来的请求,可能会出现客户端第一次发送SYN由于网络堵塞没能及时送至服务器,然后超时重传又发送了一次SYN,建立连接之后第一个SYN到达,此时服务器认为这是一个新连接,发送ACK给客户端,但此时客户端连接已经建立,会丢弃该报文,而服务器却在一直等待客户端回复,浪费了资源</li>
<li>为了数据的可靠传输,在TCP连接的双方都有一个序列号需要维护,两次握手只能确认连接发起方的数据顺序性,而连接被连接方的序号顺序性不能得到检验</li>
</ul>
<h2 id="TCP四次挥手"><a href="#TCP四次挥手" class="headerlink" title="TCP四次挥手"></a>TCP四次挥手</h2><p><img src="/images/20200115=3.png"><br>设A为连接先关闭的一方,B为另一方</p>
<ol>
<li>连接先关闭的一方先发送FIN = 1,ACK = 1,seq = x 給B</li>
<li>B 收到后先发送ACK = 1,seq= y,ack =x+1給A,表示A到B的连接已关闭,A只能接受不能发送</li>
<li>B 再发送FIN = 1 , ACK = 1,seq = p,ack = x+1給A</li>
<li>A 收到后,发送ACK = 1, seq = x+1,ack = p+1</li>
</ol>
<p>为什么需要四次挥手</p>
<ul>
<li>TCP连接是全双工的,每一边连接都需要发送终止信号并被确认直至链路没有数据传输才能销毁连接,如果是三次挥手的话,被动关闭方需要同时回复ACK = 1和FIN = 1,如果被动关闭方此时没有待处理数据,则是可以的,如果有则不行</li>
<li>这种情况在四次握手对应的是close-wait状况,被关闭方处理待发送数据</li>
<li>time-wait是2msl是为了防止最后一个ACK报文不能到达和使本次连接的报文都从网络中消失</li>
</ul>
]]></content>
<tags>
<tag>c</tag>
<tag>linux</tag>
</tags>
</entry>
<entry>
<title>UNIX下文件I/O学习</title>
<url>/2019/09/22/UNIX%E4%B8%8B%E6%96%87%E4%BB%B6I-O%E5%AD%A6%E4%B9%A0/</url>
<content><![CDATA[<hr>
<span id="more"></span>
<h1 id="引言"><a href="#引言" class="headerlink" title="引言"></a>引言</h1><p><img src="/images/20190922=0.png"></p>
<p>GUN操作系统也称GUN/linux,简称linux,其内核是linux内核</p>
<h2 id="c-标准"><a href="#c-标准" class="headerlink" title="c 标准"></a>c 标准</h2><ul>
<li>ISO C </li>
<li>IEEE POSIX </li>
<li>Single UNIX Seecification(SUS) [posix的一个超集]</li>
</ul>
<h2 id="UNIX标准的实现"><a href="#UNIX标准的实现" class="headerlink" title="UNIX标准的实现"></a>UNIX标准的实现</h2><p>标准是接口的规范,要由厂商采用转变为具体实现</p>
<ul>
<li>SVR</li>
<li>BSD</li>
<li>Linux</li>
<li>Mac os</li>
</ul>
<p><img src="/images/20190922=1.png"></p>
<ul>
<li>SVR4 为(AT&T)UNIX Systerm V Release 4.0 (被称为UNIX的商业版)</li>
<li>FreeBSD 基于4.4BSD-Lite</li>
</ul>
<hr>
<h1 id="文件I-x2F-O与目录"><a href="#文件I-x2F-O与目录" class="headerlink" title="文件I/O与目录"></a>文件I/O与目录</h1><h3 id="文件描述符"><a href="#文件描述符" class="headerlink" title="文件描述符"></a>文件描述符</h3><p>文件描述符是一个非负常数,当打开或新建一个文件时,内核会向进程返回一个文件描述符</p>
<p>直接使用的常数叫做幻数,如</p>
<table>
<thead>
<tr>
<th align="center">0</th>
<th align="center">1</th>
<th align="center">2</th>
</tr>
</thead>
<tbody><tr>
<td align="center">stdin</td>
<td align="center">stdout</td>
<td align="center">stderr</td>
</tr>
</tbody></table>
<h3 id="open"><a href="#open" class="headerlink" title="open()"></a>open()</h3><figure class="highlight objectivec"><table><tr><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">"fcntl.h"</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">int</span> open(<span class="keyword">const</span> <span class="type">char</span> *__file, <span class="type">int</span> __oflag, ...)</span><br><span class="line"></span><br><span class="line">成功返回文件描述符,失败返回<span class="number">-1</span></span><br></pre></td></tr></table></figure>
<ul>
<li><p>常用flag<br> O_RDONLY只读模式<br> O_WRONLY只写模式<br> O_RDWR读写模式<br> O_APPEND每次写操作都写入文件的末尾<br> O_CREAT如果指定文件不存在,则创建这个文件<br> O_EXCL如果要创建的文件已存在,则返回-1,并且修改errno的值<br> O_TRUNC如果文件存在,以只写/读写方式打开,并清空文件全部内容(即将其长度截短为0)</p>
</li>
<li><p>多个flag可用逻辑或连接</p>
</li>
<li><p>open返回的文件描述符一定是最小的未被使用的描述符</p>
</li>
</ul>
<h3 id="craet"><a href="#craet" class="headerlink" title="craet()"></a>craet()</h3><figure class="highlight erlang-repl"><table><tr><td class="code"><pre><span class="line">int creat(const char *__file, mode_t __mode)</span><br><span class="line"></span><br><span class="line">成功返回!!只写!!的文件描述符,失败返回-<span class="number">1</span></span><br></pre></td></tr></table></figure>
<ul>
<li>等效于open(path,O_WRONLY|O_CREAT|O_TRUNK,node)</li>
</ul>
<h3 id="close"><a href="#close" class="headerlink" title="close()"></a>close()</h3><figure class="highlight autoit"><table><tr><td class="code"><pre><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">"unistd.h"</span></span></span><br><span class="line"></span><br><span class="line"><span class="built_in">int</span> close(<span class="built_in">int</span> fd)</span><br><span class="line"></span><br><span class="line">成功返回<span class="number">0</span>,失败返回<span class="number">-1</span></span><br><span class="line"></span><br></pre></td></tr></table></figure>
<ul>
<li>当进程关闭时,内核会自动关闭打开的文件,即不需要调用close()</li>
</ul>
<h3 id="write"><a href="#write" class="headerlink" title="write()"></a>write()</h3><figure class="highlight angelscript"><table><tr><td class="code"><pre><span class="line">ssize_t write(<span class="built_in">int</span> __fd, <span class="keyword">const</span> <span class="built_in">void</span> *__buf, size_t __n)</span><br><span class="line"></span><br><span class="line">成功返回写入的字节数,失败返回<span class="number">-1</span></span><br><span class="line"></span><br></pre></td></tr></table></figure>
<h3 id="read"><a href="#read" class="headerlink" title="read()"></a>read()</h3><figure class="highlight sqf"><table><tr><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">"unistd.h"</span></span></span><br><span class="line"></span><br><span class="line">ssize_t read(int <span class="variable">__fd</span>, void *<span class="variable">__buf</span>, size_t <span class="variable">__nbytes</span>)</span><br><span class="line"></span><br><span class="line">成功返回读到的字节数,到文件尾返回<span class="number">0</span>,失败返回-<span class="number">1</span></span><br></pre></td></tr></table></figure>
<figure class="highlight arduino"><table><tr><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">"fcntl.h"</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">"stdio.h"</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">"unistd.h"</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">"stdlib.h"</span></span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">(<span class="type">int</span> argc, <span class="type">char</span> <span class="type">const</span> *argv[])</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="type">char</span> buf[<span class="number">6</span>]=<span class="string">"123456"</span>;</span><br><span class="line"> <span class="type">void</span> *Rbuf=<span class="built_in">malloc</span>(<span class="number">10</span>);</span><br><span class="line"> <span class="type">int</span> pi;</span><br><span class="line"> </span><br><span class="line"> <span class="comment">//创建文件并写入字符串</span></span><br><span class="line"> <span class="comment">//creat()返回的文件描述符是只写的 </span></span><br><span class="line"> <span class="keyword">if</span>(<span class="built_in">write</span>(<span class="built_in">creat</span>(<span class="string">"test"</span>,S_IRWXU),buf,<span class="number">6</span>)==<span class="number">-1</span>)</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"write error!"</span>);</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"write success!\n"</span>);</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="comment">//获得文件描述符</span></span><br><span class="line"> pi=<span class="built_in">open</span>(<span class="string">"test"</span>,O_RDONLY);</span><br><span class="line"> </span><br><span class="line"> <span class="comment">//读并打印</span></span><br><span class="line"> <span class="keyword">if</span>(<span class="built_in">read</span>(pi,Rbuf,<span class="built_in">sizeof</span>(buf))!=<span class="number">-1</span>)</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"read : %s"</span>,Rbuf);</span><br><span class="line"> <span class="keyword">else</span> </span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"read error!"</span>);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">> write success!</span><br><span class="line"> read : <span class="number">123456</span></span><br><span class="line"></span><br></pre></td></tr></table></figure>
<h3 id="lseek"><a href="#lseek" class="headerlink" title="lseek()"></a>lseek()</h3><p>通常文件读写从当前文件偏移量开始,并使偏移量增加所读写量<br>默认情况下偏移量被设为0,除了O_APPEND追加模式</p>
<figure class="highlight sqf"><table><tr><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">"unistd.h"</span></span></span><br><span class="line"></span><br><span class="line"><span class="variable">__off_t</span> lseek(int <span class="variable">__fd</span>, <span class="variable">__off_t</span> <span class="variable">__offset</span>, int <span class="variable">__whence</span>)</span><br><span class="line"></span><br><span class="line">成功返回新的偏移量,失败返回-<span class="number">1</span></span><br></pre></td></tr></table></figure>
<table>
<thead>
<tr>
<th align="center">whence</th>
<th align="center">SEEK_SET</th>
<th align="center">SEEK_CUR</th>
<th align="center">SEEK_END</th>
</tr>
</thead>
<tbody><tr>
<td align="center">距文件开始加上offset</td>
<td align="center">当前值加上</td>
<td align="center">文件末尾加上</td>
<td align="center"></td>
</tr>
</tbody></table>
<ul>
<li>lseek只修改偏移量,不进行I/O操作</li>
</ul>
<h3 id="内核打开文件的数据结构"><a href="#内核打开文件的数据结构" class="headerlink" title="内核打开文件的数据结构"></a>内核打开文件的数据结构</h3><p><img src="/images/20190922=2.png"></p>
<ol>
<li>进程表项<ul>
<li>fd标志即文件描述符的标志</li>
<li>文件指针</li>
</ul>
</li>
<li>文件表项<ul>
<li>文件状态标志 读写追加同步非阻塞 ( 详见open() flag))</li>
<li>文件偏移量</li>
<li>v节点指针</li>
</ul>
</li>
<li>v节点项<ul>
<li>v节点信息</li>
<li>v节点数据</li>
<li>i节点信息</li>
<li>当前文件长度</li>
<li>v节点指针</li>
</ul>
</li>
</ol>
<h3 id="dup-dup2"><a href="#dup-dup2" class="headerlink" title="dup() dup2()"></a>dup() dup2()</h3><p>用于复制文件描述符</p>
<figure class="highlight hsp"><table><tr><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">"unistd.h"</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">int</span> <span class="keyword">dup</span>(<span class="keyword">int</span> __fd)</span><br><span class="line"></span><br><span class="line"><span class="keyword">int</span> dup2(<span class="keyword">int</span> __fd, <span class="keyword">int</span> __fd2)</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<ul>
<li>文件描述符0、1、2默认由shell打开,dup(1)得到的是立即可用的最小描述符即3</li>
<li>dup2() 中fd2用于指定新的文件描述符,若fd等于fd2,则返回fd2</li>
<li>dup2()是一个原子操作,不会出现任务进行中进程切换导致前后状态不一致</li>
</ul>
<h3 id="sync"><a href="#sync" class="headerlink" title="sync()"></a>sync()</h3><figure class="highlight cpp"><table><tr><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">"unistd.h"</span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">sync</span><span class="params">(<span class="type">void</span>)</span></span></span><br><span class="line"><span class="function"></span></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">fsync</span><span class="params">(<span class="type">int</span> __fd)</span></span></span><br><span class="line"><span class="function"></span></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">fdatesync</span><span class="params">(<span class="type">int</span> __fd)</span></span></span><br></pre></td></tr></table></figure>
<ul>
<li>sync()将修改过的块缓存区排入写队列,然后返回,不等待实际磁盘I/O结束</li>
<li>fsync()指定文件作用,等待实际磁盘I/O结束才返回</li>
<li>fdatesync() 与fsync()类似,只更新数据,不更新属性</li>
</ul>
<hr>
<h1 id="补充"><a href="#补充" class="headerlink" title="补充"></a>补充</h1><p>假设test.c 是有错误的</p>
<table>
<thead>
<tr>
<th align="center">gcc test.c 2>&1 >outlfile</th>
<th align="center">gcc test.c >outlfile 2>&1</th>
</tr>
</thead>
<tbody><tr>
<td align="center">stdout有输出,而outfile没有</td>
<td align="center">outfile有错误输出,而stdout没有</td>
</tr>
</tbody></table>
<ul>
<li>shell从左到右执行</li>
<li>2 指向 1,于是stdout有了输出,然后 1 指向 outfile ,这时的1由于编译失败是没有的,所以outfile为空</li>
<li>gcc test.c >outlfile 2>&1 可简写为<figure class="highlight 1c"><table><tr><td class="code"><pre><span class="line">gcc test.c <span class="meta">&>outlfile </span></span><br><span class="line"></span><br><span class="line">gcc test.c ><span class="meta">&outlfile </span></span><br></pre></td></tr></table></figure></li>
</ul>
<hr>
]]></content>
<tags>
<tag>c</tag>
<tag>linux</tag>
</tags>
</entry>
<entry>
<title>UNIX下文件目录学习</title>
<url>/2019/09/24/UNIX%E4%B8%8B%E6%96%87%E4%BB%B6%E7%9B%AE%E5%BD%95%E5%AD%A6%E4%B9%A0/</url>
<content><![CDATA[<hr>
<span id="more"></span>
<h3 id="文件类型"><a href="#文件类型" class="headerlink" title="文件类型"></a>文件类型</h3><ol>
<li>普通文件</li>
<li>目录文件</li>
<li>块缓存文件(对文件设备提供带缓存的访问)</li>
<li>字符特殊文件(对设备提供不带缓存的访问)</li>
<li>FIFO(命名管道)</li>
<li>套接字</li>
<li>符号链接</li>
</ol>
<h3 id="stat"><a href="#stat" class="headerlink" title="stat()"></a>stat()</h3><figure class="highlight objectivec"><table><tr><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">"sys/stat.h"</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">int</span> stat(<span class="keyword">const</span> <span class="type">char</span> *__restrict__ __file, <span class="keyword">struct</span> stat *__restrict__ __buf)</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> fstat(<span class="type">int</span> __fd, <span class="keyword">struct</span> stat *__buf)</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> lstst(<span class="keyword">const</span> <span class="type">char</span> *__restrict__ __file, <span class="keyword">struct</span> stat *__restrict__ __buf)</span><br><span class="line"></span><br><span class="line">成功返回<span class="number">0</span>,失败返回<span class="number">-1</span></span><br></pre></td></tr></table></figure>
<ul>
<li>stat()第一个参数为文件路径,第二个参数是返回一个已经定义好的结构体</li>
</ul>
<figure class="highlight cpp"><table><tr><td class="code"><pre><span class="line"><span class="keyword">struct</span> <span class="title class_">stat</span> {</span><br><span class="line"></span><br><span class="line"> <span class="type">mode_t</span> st_mode; <span class="comment">//文件对应的模式,文件,目录等</span></span><br><span class="line"></span><br><span class="line"> <span class="type">ino_t</span> st_ino; <span class="comment">//inode节点号</span></span><br><span class="line"></span><br><span class="line"> <span class="type">dev_t</span> st_dev; <span class="comment">//设备号码</span></span><br><span class="line"></span><br><span class="line"> <span class="type">dev_t</span> st_rdev; <span class="comment">//特殊设备号码</span></span><br><span class="line"></span><br><span class="line"> <span class="type">nlink_t</span> st_nlink; <span class="comment">//文件的连接数</span></span><br><span class="line"></span><br><span class="line"> <span class="type">uid_t</span> st_uid; <span class="comment">//文件所有者</span></span><br><span class="line"></span><br><span class="line"> <span class="type">gid_t</span> st_gid; <span class="comment">//文件所有者对应的组</span></span><br><span class="line"></span><br><span class="line"> <span class="type">off_t</span> st_size; <span class="comment">//普通文件,对应的文件字节数</span></span><br><span class="line"></span><br><span class="line"> <span class="type">time_t</span> st_atime; <span class="comment">//文件最后被访问的时间</span></span><br><span class="line"></span><br><span class="line"> <span class="type">time_t</span> st_mtime; <span class="comment">//文件内容最后被修改的时间</span></span><br><span class="line"></span><br><span class="line"> <span class="type">time_t</span> st_ctime; <span class="comment">//文件状态改变时间</span></span><br><span class="line"></span><br><span class="line"> <span class="type">blksize_t</span> st_blksize; <span class="comment">//文件内容对应的块大小</span></span><br><span class="line"></span><br><span class="line"> <span class="type">blkcnt_t</span> st_blocks; <span class="comment">//该文件内容对应的块数量</span></span><br><span class="line"></span><br><span class="line"> };</span><br></pre></td></tr></table></figure>
<ul>
<li>fstat()则是用的文件描述符代替路径</li>
<li>lstat()与stat()类似,当打开文件是一个符号链接时,只返回符号链接本身,而不是指向的文件</li>
<li>在<sys/stat.h>中定义了判断文件类型的宏</li>
</ul>
<table>
<thead>
<tr>
<th align="center">宏</th>
<th align="center">文件类型</th>
</tr>
</thead>
<tbody><tr>
<td align="center">S_ISREG (st_mode)</td>
<td align="center">一般文件</td>
</tr>
<tr>
<td align="center">S_ISDIR (st_mode)</td>
<td align="center">目录</td>
</tr>
<tr>
<td align="center">S_ISCHR (st_mode)</td>
<td align="center">字符特殊文件</td>
</tr>
<tr>
<td align="center">S_ISBLK (st_mode)</td>
<td align="center">块特殊文件</td>
</tr>
<tr>
<td align="center">S_ISLNK (st_mode)</td>
<td align="center">符号连接</td>
</tr>
<tr>
<td align="center">S_ISBLK (st_mode)</td>
<td align="center">FIFO</td>
</tr>
<tr>
<td align="center">S_ISSOCK (st_mode)</td>
<td align="center">socket</td>
</tr>
</tbody></table>
<h3 id="文件访问权限"><a href="#文件访问权限" class="headerlink" title="文件访问权限"></a>文件访问权限</h3><ul>
<li>id 分有效id、实际id、设置id</li>
<li>一般有效id等于实际id</li>
<li>设置id 就是将执行该文件的进程有效id更换为文件所有者id ,在文件的st_mode值中</li>
</ul>
<p><img src="/images/20190924=0.png"></p>
<ul>
<li>对文件访问权限位也在st_mode内</li>
<li>为了打开目录内的文件,必须有对目录的读和执行权限、以及对文件的相应权限</li>
</ul>
<h3 id="access"><a href="#access" class="headerlink" title="access()"></a>access()</h3><figure class="highlight objectivec"><table><tr><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">"unistd.h"</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">int</span> access(<span class="keyword">const</span> <span class="type">char</span> *__name, <span class="type">int</span> __type)</span><br><span class="line"></span><br><span class="line">成功返回<span class="number">0</span>,失败返回<span class="number">-1</span></span><br></pre></td></tr></table></figure>
<ul>
<li>open()是以有效id测试其访问权限</li>
<li>acces()是以实际id测试</li>
</ul>
<table>
<thead>
<tr>
<th align="center">__type</th>
<th align="center">说明</th>
</tr>
</thead>
<tbody><tr>
<td align="center">F_OK</td>
<td align="center">文件是否存在</td>
</tr>
<tr>
<td align="center">R_OK</td>
<td align="center">读</td>
</tr>
<tr>
<td align="center">W_OK</td>
<td align="center">写</td>
</tr>
<tr>
<td align="center">X_OK</td>
<td align="center">执行</td>
</tr>
</tbody></table>
<h3 id="umask"><a href="#umask" class="headerlink" title="umask()"></a>umask()</h3><figure class="highlight sqf"><table><tr><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">"fcntl.h"</span></span></span><br><span class="line"></span><br><span class="line"><span class="variable">__mode_t</span> umask(<span class="variable">__mode_t</span> <span class="variable">__mask</span>)</span><br><span class="line"></span><br><span class="line">返回之前的文件模式创建屏蔽字</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<ul>
<li>__mask 即为文件权限描述符</li>
<li>umask()即屏蔽相应权限</li>
<li>shell 中<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">格式化查看当前文件模式创建屏蔽字</span><br><span class="line"></span><br><span class="line"><span class="built_in">umask</span> -S</span><br><span class="line"></span><br><span class="line">屏蔽others所有权限</span><br><span class="line"></span><br><span class="line"><span class="built_in">umask</span> 007</span><br></pre></td></tr></table></figure></li>
</ul>
<h3 id="chmod"><a href="#chmod" class="headerlink" title="chmod()"></a>chmod()</h3><figure class="highlight cpp"><table><tr><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> “sys/stat.h” </span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">chmod</span><span class="params">(<span class="type">const</span> <span class="type">char</span> *pathname,<span class="type">mode_t</span> mode)</span></span>; </span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">fchmod</span><span class="params">(<span class="type">int</span> fd,<span class="type">mode_t</span> mode)</span></span>; </span><br><span class="line"></span><br><span class="line">成功返回<span class="number">0</span>,失败返回<span class="number">-1</span></span><br><span class="line"></span><br></pre></td></tr></table></figure>
<ul>
<li>node 除了基本的9个外,还可用</li>
</ul>
<table>
<thead>
<tr>
<th align="center">S_ISUID</th>
<th align="center">设置用户id</th>
</tr>
</thead>
<tbody><tr>
<td align="center">S_ISGID</td>
<td align="center">设置组id</td>
</tr>
<tr>
<td align="center">S_ISVTX</td>
<td align="center">保存粘着位(保存正文位)</td>
</tr>
<tr>
<td align="center">S_IRWXU</td>
<td align="center">用户读写执行</td>
</tr>
<tr>
<td align="center">S_IRWXG</td>
<td align="center">群组读写执行</td>
</tr>
<tr>
<td align="center">S_IRWXO</td>
<td align="center">其他读写执行</td>
</tr>
</tbody></table>
<ul>
<li>一个可执行文件的粘着位设置后,那么当它第一次被执行被终止的的时候,程序正文部分的一个副本会被保存在交换区,方便下次执行的时候快速载入内存</li>
<li>也允许对一个目录设置粘着位,如/var/tmp、/tmp,必须对该目录有写权限且拥有该目录或文件才能删除或重命名文件,当然root是全能的</li>
</ul>
<h3 id="文件系统"><a href="#文件系统" class="headerlink" title="文件系统"></a>文件系统</h3><p><img src="/images/20190924=1.png"></p>
<p><img src="/images/20190924=2.png"></p>
<ul>
<li>二图中有两个目录项指向同一个i节点,也就是链接数为2,存在于i节点。</li>
<li>当链接数减少为0的时候才删除相应数据块,这种链接类型被称为硬链接</li>
<li>而另一种链接方式是链接文件所指向的是另一个文件名字,类似于windows下的快捷方式,对于一个文件的简介指针这是符号链接</li>
<li>一个空文件夹最小链接数为2,即. 和 ..</li>
</ul>
<h3 id="link"><a href="#link" class="headerlink" title="link()"></a>link()</h3><figure class="highlight objectivec"><table><tr><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">"unistd.h"</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">int</span> link(<span class="keyword">const</span> <span class="type">char</span> *__from, <span class="keyword">const</span> <span class="type">char</span> *__to)</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> unlink(<span class="keyword">const</span> <span class="type">char</span> *__name)</span><br><span class="line"> </span><br><span class="line">成功返回<span class="number">0</span>,失败返回<span class="number">-1</span></span><br></pre></td></tr></table></figure>
<ul>
<li>被指向路径只应该最后一部分不存在,否则失败</li>
</ul>
<figure class="highlight objectivec"><table><tr><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">"stdio.h"</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">int</span> remove(<span class="keyword">const</span> <span class="type">char</span> *__filename)</span><br><span class="line"></span><br><span class="line">成功返回<span class="number">0</span>,失败返回<span class="number">-1</span></span><br></pre></td></tr></table></figure>
<ul>
<li>等同于unink(),针对的是非UNIX系统</li>
</ul>
<h3 id="rename"><a href="#rename" class="headerlink" title="rename()"></a>rename()</h3><figure class="highlight objectivec"><table><tr><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span>“stdio”</span></span><br><span class="line"></span><br><span class="line"><span class="type">int</span> rename(<span class="keyword">const</span> <span class="type">char</span> *__old, <span class="keyword">const</span> <span class="type">char</span> *__new)</span><br><span class="line"></span><br><span class="line">成功返回<span class="number">0</span>,失败返回<span class="number">-1</span></span><br></pre></td></tr></table></figure>
<h3 id="mkdir"><a href="#mkdir" class="headerlink" title="mkdir()"></a>mkdir()</h3><figure class="highlight objectivec"><table><tr><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">"sys/stat.h"</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">int</span> mkdir(<span class="keyword">const</span> <span class="type">char</span> *__path, __mode_t __mode)</span><br><span class="line"></span><br><span class="line">成功返回<span class="number">0</span>,失败返回<span class="number">-1</span></span><br></pre></td></tr></table></figure>
<ul>
<li>目录必须拥有一个执行位</li>
<li>文件模式屏蔽字同样适用</li>
</ul>
<figure class="highlight axapta"><table><tr><td class="code"><pre><span class="line"><span class="meta">#include“unistd.h"</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">int</span> rmdir(<span class="keyword">const</span> <span class="built_in">char</span> *__path)</span><br><span class="line"></span><br><span class="line">成功返回<span class="number">0</span>,失败返回<span class="number">-1</span></span><br></pre></td></tr></table></figure>
<h3 id="chdir"><a href="#chdir" class="headerlink" title="chdir()"></a>chdir()</h3><figure class="highlight axapta"><table><tr><td class="code"><pre><span class="line"><span class="meta">#include”unistd.h"</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">int</span> chdir(<span class="keyword">const</span> <span class="built_in">char</span> *__path)</span><br><span class="line"></span><br><span class="line"><span class="built_in">int</span> fchdir(<span class="built_in">int</span> fd)</span><br><span class="line"></span><br><span class="line">成功返回<span class="number">0</span>,失败返回<span class="number">-1</span></span><br></pre></td></tr></table></figure>
<ul>
<li>执行chdir()后shell并不会切换目录、</li>
</ul>
<figure class="highlight objectivec"><table><tr><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">"unisted.h"</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">char</span> * getcwd(<span class="type">char</span> *__buf, size_t __size)</span><br><span class="line"></span><br><span class="line">成功返回<span class="number">0</span>,失败返回<span class="number">-1</span></span><br></pre></td></tr></table></figure>
<ul>
<li>用于获得绝对路径</li>
</ul>
<h3 id="文件位权限位小结"><a href="#文件位权限位小结" class="headerlink" title="文件位权限位小结"></a>文件位权限位小结</h3><p><img src="/images/20190924=3.png"></p>
<h3 id="补充"><a href="#补充" class="headerlink" title="补充"></a>补充</h3><p><a href="https://www.cnblogs.com/luntai/p/6129634.html">复杂定义读法</a><br>从变量名看起,先往右,再往左,碰到圆括号就调转阅读的方向;括号内分析完就跳出括号,还是先右后左的顺序。如此循环,直到分析完整个定义。</p>
<figure class="highlight angelscript"><table><tr><td class="code"><pre><span class="line"><span class="built_in">int</span> (*pfunc) (<span class="built_in">int</span>);</span><br><span class="line"> 找到变量名pfunc,先往右是圆括号,调转方向,左边是一个*号,这说明pfunc是一个指针;然</span><br><span class="line"> 后跳出这个圆括号,先看右边,又遇到圆括号,这说明(*pfunc)是一个函数,所以pfunc是一个</span><br><span class="line"> 指向这类函数的指针,即函数指针,这类函数具有一个<span class="built_in">int</span>类型的参数,返回值类型是<span class="built_in">int</span>。</span><br></pre></td></tr></table></figure>
<figure class="highlight angelscript"><table><tr><td class="code"><pre><span class="line"><span class="built_in">float</span> (* (*fp2) (<span class="built_in">int</span>, <span class="built_in">int</span>, <span class="built_in">float</span>)) (<span class="built_in">int</span>);</span><br><span class="line">找到变量名fp2,往右看是圆括号,调转方向往左看到*号,说明fp2是一个指针;跳出内层圆括号</span><br><span class="line">,往右看是参数列表,说明fp2是一个函数指针,接着往 左看是*号,说明指向的函数返回值是指</span><br><span class="line">针;再跳出外层圆括号,往右看还是参数列表,说明返回的指针是一个函数指针,该函数有一个</span><br><span class="line"><span class="built_in">int</span>类型的参数,返回值 类型是<span class="built_in">float</span>。简言之,fp2是一个指向函数的指针,该函数接受三个参</span><br><span class="line">数(<span class="built_in">int</span>, <span class="built_in">int</span>和<span class="built_in">float</span>),且返回一个指向函数的指针,该函数接受一个整型参数并返回一个<span class="built_in">float</span>。</span><br></pre></td></tr></table></figure>
]]></content>
<tags>
<tag>c</tag>
<tag>linux</tag>
</tags>
</entry>
<entry>
<title>UNIX下文件系统学习</title>
<url>/2019/11/01/UNIX%E4%B8%8B%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F%E5%AD%A6%E4%B9%A0/</url>
<content><![CDATA[<hr>
<span id="more"></span>
<p><img src="/images/20191103=0.png"><br><a href="http://makelinux.net/kernel_map/">原图地址</a></p>
<p>在UNIX中,文件是一个数据容器的抽象概念,文件系统则允许用户来组织、管理和使用不同的文件</p>
<p><img src="/images/20191103=1.png"></p>
<p>该图较为直观的展现了文件系统与内核其他部分的关系</p>
<h1 id="文件的用户接口"><a href="#文件的用户接口" class="headerlink" title="文件的用户接口"></a>文件的用户接口</h1><p>内核允许用户进程通过一个定义良好的、过程化的接口来与文件系统交互。</p>
<p>这些接口封装了文件系统的用户视图并指定所有的相关系统调用的行为与场景。</p>
<p>这些接口向用户暴露出几个抽象概念:</p>
<ul>
<li>文件</li>
<li>目录</li>
<li>文件描述符</li>
<li>文件系统</li>
</ul>
<hr>
<h1 id="vnode-x2F-vfs"><a href="#vnode-x2F-vfs" class="headerlink" title="vnode/vfs"></a>vnode/vfs</h1><p>传统的UNIX内核中的文件系统是单一组织的。它仅支持一种文件系统。</p>
<p>为了同时支持多种文件系统而不用修改内核,这时文件系统框架出现了,而最流行的是 <strong>Vnode/Vfs</strong>虚拟文件系统,它被集成为内核的一个功能</p>
<p>下面将对字符设备进行<strong>read</strong>系统调用来说明:</p>
<ol>
<li>使用文件描述符获得打开文件对象</li>
<li>检查是否被打开用于读取</li>
<li>从这个项中获得指向内存inode节点的指针</li>
<li>锁定该inode以便串行化访问该文件</li>
<li>检查inode文件属性,发现该文件是一个字符设备</li>
<li>使用存储在inode中的主设备号来定位字符设备表并得到针对该设备的cdexsw项。该项指向针对该设备的特定操作函数</li>
<li>从sdevsw结构中获得d_raed函数指针</li>
<li>调用该函数来执行操作</li>
<li>解锁inode并返回</li>
</ol>
<p>从中可以发现大多数操作与设备无关:</p>
<ul>
<li>1-4、9步与文件类型无关</li>
<li>5-7步是执行了内核与设备之间的接口</li>
<li>第8步才是对设备进行操作</li>
</ul>
<p>这种设计方式将文件系统代码分为文件系统相关和文件系统不相关两部分<br>两部分之间的接口则为一组通用函数,文件系统无关部分调用这些函数来执行不同的文件操作和访问,相关部分代码则与文件系统类型相关,提供对每种函数的实现</p>
<p><strong>vnode/vfs接口使用了面向对象的编程概念设计</strong></p>
<ul>
<li>一般而言,我们用基类来简单表示一个抽象类或定义一个接口,用派生类来实现其成员函数的实现。由此文件类可以创建一个creat()的成员函数,但是当用户调用这个函数来处理任何文件时,将基于文件类型来调用不同的函数。 而实际上,没有通用的可以创建任何文件的通用函数实现,这样的函数叫虚函数</li>
<li>由于基类针对该函数没有具体的实现,因此该基类不能被实例化。 它仅可以被提供该虚函数特定实现的派生子类使用,但它可以被子类重写该函数,就叫面向对象的重载</li>
<li>所有对象是派生类的一个实例,但用户可以使用一个指向基类的指针来操作对象,不需要知道该对象属于哪个子类。当对象调用一个虚函数时,实现将基于对象的实际类型自动决定调用哪个具体的函数</li>
</ul>
<p>vnode(virtual node)抽象表示在UNIX内核中一个的文件,vfs(virtual file system)抽象表示为一个文件系统,都被认为是抽象基类,由这两个基类派生出针对不同文件系统类型实现的子类,如<br>s5fs、ufs、NFS、FAT等等</p>
<p>在vnode基类的数据域均为文件系统类型无关的属性,而其成员函数分为两类:</p>
<ol>
<li>定义了文件系统相关接口的虚函数集合,每种不同的文件系统必须给出相应的函数实现</li>
<li>另一类是可以被其他内核子系统用来操作文件的高层工具函数,这些函数可以调用文件系统相关的函数来执行底层任务</li>
</ol>
<p><img src="/images/20191103=2.png"><br><img src="/images/20190922=2.png"></p>
<p>vnode基类由两个数据域来实现子类化。</p>
<ul>
<li>第一个是v_data,它是一个指针,指向保存着特定文件系统的vnode数据的私有数据结构,对于s5fs,这个结构是inode,对于nfs,它是rnode。 因为这个结构直接通过v_data访问,所以它对vnode基类不透明,其字段仅仅对特定文件系统的内部函数可见。</li>
<li>另一个数据域为v_op,其指向一个vnoideops结构,该结构包含一个vnode虚拟接口的函数实现集合</li>
</ul>
<blockquote>
<p>v-data和v_op域在vnode被初始化时赋值,一般是在open或create系统调用过程中。当文件系统无关的代码调用任意一个vnode的虚函数时,把内核解除v_op指针的引用并调用对应文件系统的实现函数。比如VOP_CLOSE操作允许调用者关闭域vnode关联的文件,其宏定义为<br> <figure class="highlight lisp"><table><tr><td class="code"><pre><span class="line">#define VOP_CLOSE(<span class="name">vp</span>,...) (<span class="name">*</span>((<span class="name">vp</span>)->v_op->vop_close))(<span class="name">vp</span>,...)</span><br></pre></td></tr></table></figure></p>
</blockquote>
<hr>
<p><img src="/images/20191103=3.png"></p>
<p>同样的,vfs基类也有两个数据域,分别为vfs_data和vfs_op,它们将链接到特定文件系统<br>实现的数据与函数</p>
<p><strong>在c语言中,一个基类通过结构体的方式实现,在结构中包含了一些定义为公共的非虚的全局内核函数(或宏)。基类包含了指向另一个结构的指针,该结构包含了一个函数指针集合(每个虚函数一个函数指针)</strong></p>
<hr>
<h1 id="文件系统"><a href="#文件系统" class="headerlink" title="文件系统"></a>文件系统</h1><blockquote>
<p>计算机的文件系统是一种存储和组织计算机数据的方法,它使得对其访问和查找变得容易,文件系统使用文件和树形目录的抽象逻辑概念代替了硬盘和光盘等物理设备使用数据块的概念,用户使用文件系统来保存数据不必关心数据实际保存在硬盘(或者光盘)的地址为多少的数据块上,只需要记住这个文件的所属目录和文件名。在写入新数据之前,用户不必关心硬盘上的那个块地址没有被使用,硬盘上的存储空间管理(分配和释放)功能由文件系统自动完成,用户只需要记住数据被写入到了哪个文件中。</p>
</blockquote>
<p><a href="https://juejin.im/post/5b8ba9e26fb9a019c372e100">补充链接</a></p>
<h3 id="s5fs"><a href="#s5fs" class="headerlink" title="s5fs"></a>s5fs</h3><p><img src="/images/20191103=4.png"><br><img src="/images/20190924=1.png"></p>
<p><strong>超级块</strong>中包含文件系统的元数据,每一个文件系统都有一个超级快,它驻留在磁盘上文件系统的开始处。当挂载一个文件系统时,内核读取超级块到内存中,当文件系统被卸载时,将其从内存中删除。 </p>
<p>一个超级块中包含:</p>
<ul>
<li>文件系统块大小</li>
<li>inode列表中块大小</li>
<li>空闲块和空闲inode数目</li>
<li>空闲块列表</li>
<li>空闲inode列表</li>
</ul>
<h3 id="ffs"><a href="#ffs" class="headerlink" title="ffs"></a>ffs</h3><p><img src="/images/20191103=5.png"><br><img src="/images/20191103=6.png"></p>
<h3 id="关于缓存"><a href="#关于缓存" class="headerlink" title="关于缓存"></a>关于缓存</h3><p><img src="/images/20191103=7.png"><br><img src="/images/20191103=8.png"><br><img src="/images/20191103=9.png"></p>
<h3 id="日志文件系统"><a href="#日志文件系统" class="headerlink" title="日志文件系统"></a>日志文件系统</h3><p><img src="/images/20191103=10.png"><br><img src="/images/20191103=11.png"><br><a href="https://zh.wikipedia.org/wiki/%E6%97%A5%E5%BF%97%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F">wiki</a><br><a href="https://www.ibm.com/developerworks/cn/linux/l-journaling-filesystems/index.html">IBM-learn</a></p>
]]></content>
<tags>
<tag>linux</tag>
<tag>文件系统</tag>
</tags>
</entry>
<entry>
<title>UNIX下标准I/O与系统信息学习</title>
<url>/2019/09/28/UNIX%E4%B8%8B%E6%A0%87%E5%87%86I-O%E4%B8%8E%E7%B3%BB%E7%BB%9F%E4%BF%A1%E6%81%AF%E5%AD%A6%E4%B9%A0/</url>
<content><![CDATA[<hr>
<span id="more"></span>
<h1 id="标准I-x2F-O"><a href="#标准I-x2F-O" class="headerlink" title="标准I/O"></a>标准I/O</h1><h3 id="流与文件指针"><a href="#流与文件指针" class="headerlink" title="流与文件指针"></a>流与文件指针</h3><blockquote>
<p> a <a href="https://en.wikipedia.org/wiki/Stream_(computing)">stream</a> is a source or sink of data, usually individual bytes or characters.</p>
</blockquote>
<ul>
<li>标准I/O都是围绕流来进行的</li>
<li>同样标准I/O操作都是围绕FILE指针完成的</li>
<li>典型的stdin、stdout、stderr流都是被相应的文件指针绑定的</li>
</ul>
<h3 id="缓冲"><a href="#缓冲" class="headerlink" title="缓冲"></a>缓冲</h3><ul>
<li>全缓冲(填满缓冲区进行IO)</li>
<li>行缓冲(遇到换行符就进行IO))</li>
<li>不缓冲</li>
</ul>
<figure class="highlight sqf"><table><tr><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">"stdio.h"</span></span></span><br><span class="line"></span><br><span class="line">void setbuf(FILE *<span class="variable">__restrict__</span> <span class="variable">__stream</span>, char *<span class="variable">__restrict__</span> <span class="variable">__buf</span>)</span><br><span class="line"></span><br><span class="line">int setvbuf(FILE *<span class="variable">__restrict__</span> <span class="variable">__stream</span>, char *<span class="variable">__restrict__</span> <span class="variable">__buf</span>, int <span class="variable">__modes</span>, size_t <span class="variable">__n</span>)</span><br><span class="line"></span><br><span class="line">成功返回<span class="number">0</span>,失败返回非<span class="number">0</span></span><br><span class="line"></span><br></pre></td></tr></table></figure>
<ul>
<li>setbuf()通常设置后是全缓冲,但终端设备可以是行缓冲,不进行缓冲则将buf设置为NULL</li>
<li>setvbuf()可以指定缓冲类型,具体见下图<br><img src="/images/20190928=0.png"></li>
</ul>
<h3 id="打开流"><a href="#打开流" class="headerlink" title="打开流"></a>打开流</h3><figure class="highlight stata"><table><tr><td class="code"><pre><span class="line">#<span class="keyword">include</span><span class="string">"stdio.h"</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">FILE</span> * fopen(<span class="keyword">const</span> <span class="keyword">char</span> *__restrict__ __filename, <span class="keyword">const</span> <span class="keyword">char</span> *__restrict__ __modes)</span><br><span class="line"></span><br><span class="line"><span class="keyword">FILE</span> *freopen(<span class="keyword">const</span> <span class="keyword">char</span> *__restrict__ __filename, <span class="keyword">const</span> <span class="keyword">char</span> *__restrict__ __modes, <span class="keyword">FILE</span> *__restrict__ __stream)</span><br><span class="line"></span><br><span class="line"><span class="keyword">FILE</span> *fdopen (int __fd, <span class="keyword">const</span> <span class="keyword">char</span> *__modes)</span><br><span class="line"></span><br><span class="line">成功返回文件指针,失败返回NULL</span><br></pre></td></tr></table></figure>
<ul>
<li>freopen()用于在一个指定的流上打开文件</li>
<li>type<br><img src="/images/20190928=1.png"></li>
</ul>
<h3 id="读写流"><a href="#读写流" class="headerlink" title="读写流"></a>读写流</h3><ul>
<li><p>读</p>
<figure class="highlight objectivec"><table><tr><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">"stdio.h"</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> getc(_fp) _IO_getc (_fp)</span></span><br><span class="line"><span class="type">int</span> _IO_getc(_IO_FILE *__fp)</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> fgetc(FILE *__stream)</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> getchar(<span class="type">void</span>)</span><br><span class="line"></span><br><span class="line">成功返回下一个字符,失败返回EOF</span><br><span class="line"></span><br></pre></td></tr></table></figure>
</li>
<li><p>写</p>
<figure class="highlight autoit"><table><tr><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">"stdio.h"</span></span></span><br><span class="line"></span><br><span class="line"><span class="built_in">int</span> putc(_ch,_fp) </span><br><span class="line"></span><br><span class="line"><span class="built_in">int</span> fputc(<span class="built_in">int</span> __c, FILE *__stream)</span><br><span class="line"></span><br><span class="line"><span class="built_in">int</span> putchar(<span class="built_in">int</span> __c)</span><br><span class="line"></span><br><span class="line">成功返回c,失败返回<span class="literal">NULL</span></span><br></pre></td></tr></table></figure></li>
<li><p>返回的c为ASCII字符</p>
</li>
</ul>
<p>行IO</p>
<figure class="highlight gradle"><table><tr><td class="code"><pre><span class="line"><span class="keyword">char</span> * fgets(<span class="keyword">char</span> *__restrict__ __s, <span class="keyword">int</span> __n, <span class="keyword">FILE</span> *__restrict__ __stream)</span><br><span class="line"></span><br><span class="line">成功返回buf,失败返回<span class="keyword">NULL</span></span><br></pre></td></tr></table></figure>
<figure class="highlight gradle"><table><tr><td class="code"><pre><span class="line"><span class="keyword">int</span> fputs(const <span class="keyword">char</span> *__restrict__ __s, <span class="keyword">FILE</span> *__restrict__ __stream)</span><br><span class="line"></span><br><span class="line">成功返回非负,失败返回<span class="keyword">NULL</span></span><br><span class="line"></span><br></pre></td></tr></table></figure>
<h3 id="定位流"><a href="#定位流" class="headerlink" title="定位流"></a>定位流</h3><figure class="highlight gradle"><table><tr><td class="code"><pre><span class="line">#<span class="keyword">include</span><span class="string">"stdio.h"</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">long</span> ftell(<span class="keyword">FILE</span> *__stream)</span><br><span class="line"></span><br><span class="line">成功返回当前文件位置指示,失败返回-<span class="number">1</span>L</span><br><span class="line"></span><br><span class="line"><span class="keyword">int</span> fseek(<span class="keyword">FILE</span> *__stream, <span class="keyword">long</span> __off, <span class="keyword">int</span> __whence)</span><br><span class="line"></span><br><span class="line">成功返回<span class="number">0</span>,失败返回-<span class="number">1</span></span><br><span class="line"></span><br></pre></td></tr></table></figure>
<h3 id="临时文件"><a href="#临时文件" class="headerlink" title="临时文件"></a>临时文件</h3><figure class="highlight objectivec"><table><tr><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">"stdio.h"</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">char</span> * tmpnam(<span class="type">char</span> *__s)</span><br><span class="line"></span><br><span class="line">成功返回文件指针,失败返回<span class="literal">NULL</span></span><br><span class="line"></span><br></pre></td></tr></table></figure>
<hr>
<h1 id="系统数据文件信息"><a href="#系统数据文件信息" class="headerlink" title="系统数据文件信息"></a>系统数据文件信息</h1><h3 id="passwd文件"><a href="#passwd文件" class="headerlink" title="passwd文件"></a>passwd文件</h3><figure class="highlight elixir"><table><tr><td class="code"><pre><span class="line"><span class="comment"># /etc/passwd</span></span><br><span class="line"></span><br><span class="line"><span class="symbol">root:</span><span class="symbol">x:</span><span class="number">0</span><span class="symbol">:</span><span class="number">0</span><span class="symbol">:root</span><span class="symbol">:/root</span><span class="symbol">:/bin/bash</span></span><br><span class="line"><span class="symbol">daemon:</span><span class="symbol">x:</span><span class="number">1</span><span class="symbol">:</span><span class="number">1</span><span class="symbol">:daemon</span><span class="symbol">:/usr/sbin</span><span class="symbol">:/usr/sbin/nologin</span></span><br><span class="line"><span class="symbol">bin:</span><span class="symbol">x:</span><span class="number">2</span><span class="symbol">:</span><span class="number">2</span><span class="symbol">:bin</span><span class="symbol">:/bin</span><span class="symbol">:/usr/sbin/nologin</span></span><br><span class="line"><span class="symbol">sys:</span><span class="symbol">x:</span><span class="number">3</span><span class="symbol">:</span><span class="number">3</span><span class="symbol">:sys</span><span class="symbol">:/dev</span><span class="symbol">:/usr/sbin/nologin</span></span><br><span class="line"><span class="symbol">sync:</span><span class="symbol">x:</span><span class="number">4</span><span class="symbol">:</span><span class="number">65534</span><span class="symbol">:sync</span><span class="symbol">:/bin</span><span class="symbol">:/bin/sync</span></span><br><span class="line"><span class="symbol">games:</span><span class="symbol">x:</span><span class="number">5</span><span class="symbol">:</span><span class="number">60</span><span class="symbol">:games</span><span class="symbol">:/usr/games</span><span class="symbol">:/usr/sbin/nologin</span></span><br><span class="line"><span class="symbol">nobody:</span><span class="symbol">x:</span><span class="number">65534</span><span class="symbol">:</span><span class="number">65534</span><span class="symbol">:nobody</span><span class="symbol">:/nonexistent</span><span class="symbol">:/usr/sbin/nologin</span></span><br></pre></td></tr></table></figure>
<ul>
<li>相对应的是用户、口令、用户id、组id、注释、用户工作目录、登录可执行文件</li>
<li>像/usr/sbin/nologin、/dev/null是为了防止其登录</li>
<li>用户id、组id65534 没有任何特权,只能访问人人都能读写的文件</li>
<li>一般口令经单向加密算法加密后存放在/etc/shadow</li>
</ul>
<h3 id="组文件与id"><a href="#组文件与id" class="headerlink" title="组文件与id"></a>组文件与id</h3><figure class="highlight apache"><table><tr><td class="code"><pre><span class="line"><span class="comment"># /etc/group</span></span><br><span class="line"></span><br><span class="line"><span class="attribute">root</span>:x:<span class="number">0</span>:</span><br><span class="line"><span class="attribute">daemon</span>:x:<span class="number">1</span>:</span><br><span class="line"><span class="attribute">bin</span>:x:<span class="number">2</span>:</span><br><span class="line"><span class="attribute">sys</span>:x:<span class="number">3</span>:</span><br><span class="line"><span class="attribute">adm</span>:x:<span class="number">4</span>:syslog</span><br><span class="line"><span class="attribute">tty</span>:x:<span class="number">5</span>:</span><br><span class="line"><span class="attribute">disk</span>:x:<span class="number">6</span>:</span><br><span class="line"><span class="attribute">lp</span>:x:<span class="number">7</span>:</span><br></pre></td></tr></table></figure>
<ul>
<li>类似于passwd结构,相对应是组名、口令、组id、所包含的用户名</li>
<li>在使用useradd命令创建用户的时侯可以用-g 和-G 指定用户所属组和附属组。<br>基本组:如果没有指定用户组,创建用户的时候系统会默认同时创建一个和这个用户名同名的组,这个组就是基本组,不可以把用户从基本组中删除。在创建文件时,文件的所属组就是用户的基本组。<br>附加组:除了基本组之外,用户所在的其他组,都是附加组。用户是可以从附加组中被删除的。<br>用户不论是在基本组中还是附加组中,就会拥有该组的权限。一个用户可以属于多个附加组。但是一个用户只能有一个基本组。</li>
</ul>
<p>使用下列命令查看当前用户(user)权限</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_">$ </span><span class="language-bash"><span class="built_in">id</span> user</span></span><br></pre></td></tr></table></figure>
<figure class="highlight apache"><table><tr><td class="code"><pre><span class="line"><span class="attribute">uid</span>=<span class="number">1000</span>(<span class="number">123</span>) gid=<span class="number">1000</span>(<span class="number">123</span>) groups=<span class="number">1000</span>(<span class="number">123</span>),<span class="number">4</span>(adm),<span class="number">20</span>(dialout),<span class="number">24</span>(cdrom),<span class="number">25</span>(floppy),<span class="number">27</span>(sudo),<span class="number">29</span>(audio),<span class="number">30</span>(dip),<span class="number">44</span>(video),<span class="number">46</span>(plugdev),<span class="number">108</span>(lxd),<span class="number">114</span>(netdev)</span><br></pre></td></tr></table></figure>
<ul>
<li>groups后除了123组之外,全是附属组</li>
</ul>
<hr>
<h3 id="日期"><a href="#日期" class="headerlink" title="日期"></a>日期</h3><figure class="highlight sqf"><table><tr><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">"time.h"</span></span></span><br><span class="line"></span><br><span class="line">time_t <span class="built_in">time</span>(time_t *<span class="variable">__timer</span>)</span><br><span class="line"></span><br><span class="line">成功返回时间值,失败返回-<span class="number">1</span></span><br></pre></td></tr></table></figure>
<ul>
<li><p>返回的是日历时间,又叫Unix时间戳(Unix timestamp),或称Unix时间(Unix time)、POSIX时间(POSIX time),是一种时间表示方式,定义为从格林威治时间1970年01月01日00时00分00秒起至现在的总秒数。Unix时间戳不仅被使用在Unix系统、类Unix系统中,也在许多其他操作系统中被广泛采用</p>
</li>
<li><p>时间值被保存在__timer所指单元内</p>
</li>
</ul>
<figure class="highlight cpp"><table><tr><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">"time.h"</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">struct</span> <span class="title class_">tm</span> *<span class="built_in">gmtime</span>(<span class="type">const</span> <span class="type">time_t</span> *__timer)</span><br><span class="line"></span><br><span class="line"><span class="keyword">struct</span> <span class="title class_">tm</span> *<span class="built_in">localtime</span>(<span class="type">const</span> <span class="type">time_t</span> *__timer)</span><br><span class="line"></span><br><span class="line">成功返回指向tm结构体的指针,失败返回<span class="literal">NULL</span></span><br><span class="line"></span><br></pre></td></tr></table></figure>
<ul>
<li>gtime()将日历时间转化为UTC时间(协调世界时),localtime则是本地时间</li>
</ul>
<figure class="highlight cpp"><table><tr><td class="code"><pre><span class="line"><span class="keyword">struct</span> <span class="title class_">tm</span></span><br><span class="line">{</span><br><span class="line"> <span class="type">int</span> tm_sec; <span class="comment">/* Seconds. [0-60] (1 leap second) */</span></span><br><span class="line"> <span class="type">int</span> tm_min; <span class="comment">/* Minutes. [0-59] */</span></span><br><span class="line"> <span class="type">int</span> tm_hour; <span class="comment">/* Hours. [0-23] */</span></span><br><span class="line"> <span class="type">int</span> tm_mday; <span class="comment">/* Day. [1-31] */</span></span><br><span class="line"> <span class="type">int</span> tm_mon; <span class="comment">/* Month. [0-11] */</span></span><br><span class="line"> <span class="type">int</span> tm_year; <span class="comment">/* Year - 1900. */</span></span><br><span class="line"> <span class="type">int</span> tm_wday; <span class="comment">/* Day of week. [0-6] */</span></span><br><span class="line"> <span class="type">int</span> tm_yday; <span class="comment">/* Days in year.[0-365] */</span></span><br><span class="line"> <span class="type">int</span> tm_isdst; <span class="comment">/* DST. [-1/0/1]*/</span></span><br><span class="line"></span><br><span class="line"><span class="meta"># <span class="keyword">ifdef</span> __USE_MISC</span></span><br><span class="line"> <span class="type">long</span> <span class="type">int</span> tm_gmtoff; <span class="comment">/* Seconds east of UTC. */</span></span><br><span class="line"> <span class="type">const</span> <span class="type">char</span> *tm_zone; <span class="comment">/* Timezone abbreviation. */</span></span><br><span class="line"><span class="meta"># <span class="keyword">else</span></span></span><br><span class="line"> <span class="type">long</span> <span class="type">int</span> __tm_gmtoff; <span class="comment">/* Seconds east of UTC. */</span></span><br><span class="line"> <span class="type">const</span> <span class="type">char</span> *__tm_zone; <span class="comment">/* Timezone abbreviation. */</span></span><br><span class="line"><span class="meta"># <span class="keyword">endif</span></span></span><br><span class="line">};</span><br></pre></td></tr></table></figure>
<p><em>用于格式化输出时间</em></p>
<figure class="highlight sqf"><table><tr><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">"time.h"</span></span></span><br><span class="line"></span><br><span class="line">size_t strftime(char *<span class="variable">__restrict__</span> <span class="variable">__s</span>, size_t <span class="variable">__maxsize</span>, const char *<span class="variable">__restrict__</span> <span class="variable">__format</span>, const struct tm *<span class="variable">__restrict__</span> <span class="variable">__tp</span>)</span><br><span class="line"></span><br><span class="line">成功返回存入数组字节,失败返回<span class="number">0</span></span><br></pre></td></tr></table></figure>
<p><img src="/images/20190928=2.png"></p>
<figure class="highlight perl"><table><tr><td class="code"><pre><span class="line">// 示例</span><br><span class="line"></span><br><span class="line"><span class="comment">#include"stdio.h"</span></span><br><span class="line"><span class="comment">#include"time.h"</span></span><br><span class="line"> </span><br><span class="line"><span class="keyword">int</span> main(){</span><br><span class="line"> </span><br><span class="line"> char <span class="string">qq[100]</span>;</span><br><span class="line"> struct tm *stime;</span><br><span class="line"> time_t timer;</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">time</span>(&timer);</span><br><span class="line"> stime=<span class="keyword">localtime</span>(&timer);</span><br><span class="line"> strftime(<span class="keyword">qq</span>,<span class="number">100</span>,<span class="string">"%c"</span>,stime);</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">printf</span>(<span class="string">"%s\n"</span>,<span class="keyword">qq</span>);</span><br><span class="line"> <span class="keyword">printf</span>(<span class="string">"%ld"</span>,timer);</span><br><span class="line"></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">> Sat Sep <span class="number">28</span> <span class="number">18</span>:<span class="number">33</span>:<span class="number">54</span> <span class="number">2019</span></span><br><span class="line"><span class="number">1569666834</span></span><br></pre></td></tr></table></figure>
<ul>
<li>可见可以快速打印出漂亮的格式</li>
</ul>
]]></content>
<tags>
<tag>c</tag>
<tag>linux</tag>
</tags>
</entry>
<entry>
<title>UNIX下线程学习</title>
<url>/2019/10/23/UNIX%E4%B8%8B%E7%BA%BF%E7%A8%8B%E5%AD%A6%E4%B9%A0/</url>
<content><![CDATA[<hr>
<span id="more"></span>
<h1 id="关于线程"><a href="#关于线程" class="headerlink" title="关于线程"></a>关于线程</h1><p><img src="/images/20191024=3.png"></p>
<blockquote>
<p>线程(英语:thread)是操作系统能够进行运算调度的最小单位。大部分情况下,它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。在Unix System V及SunOS中也被称为轻量进程(lightweight processes),但轻量进程更多指内核线程(kernel thread),而把用户线程(user thread)称为线程。</p>
</blockquote>
<p>进程 = 一组线程 + 一组资源</p>
<p>内核线程: 在内核内部根据需要创建和销毁,负责执行一个特殊功能,耗费资源最多</p>
<p>轻量进程:由内核支持的用户进程,依赖于内核进程</p>
<p>用户进程:由库实现的进程,并不与内核交互,其库相当于微内核(管理者),耗费资源最少</p>
<p><img src="/images/20191024=0.png"></p>
<p><img src="/images/20191024=1.png"></p>
<p><img src="/images/20191024=2.png"></p>
<hr>
<h1 id="线程管理"><a href="#线程管理" class="headerlink" title="线程管理"></a>线程管理</h1><p>而这里的线程都指用户线程</p>
<figure class="highlight livecodeserver"><table><tr><td class="code"><pre><span class="line">pthread库不是Linux系统默认的库,连接时需要使用静态库</span><br><span class="line">libpthread.<span class="keyword">a</span>,所以需要链接该库。在编译中要加 -lpthread参数。</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<h3 id="线程id"><a href="#线程id" class="headerlink" title="线程id"></a>线程id</h3><figure class="highlight objectivec"><table><tr><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">"pthread.h"</span></span></span><br><span class="line"></span><br><span class="line">pthread_t pthread_self(<span class="type">void</span>)</span><br><span class="line"></span><br><span class="line">返回调用线程的线程<span class="type">id</span></span><br></pre></td></tr></table></figure>
<h3 id="线程创建"><a href="#线程创建" class="headerlink" title="线程创建"></a>线程创建</h3><figure class="highlight sqf"><table><tr><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">"pthread.h"</span></span></span><br><span class="line"></span><br><span class="line">int pthread_create(pthread_t *<span class="variable">__restrict__</span> <span class="variable">__newthread</span>,</span><br><span class="line"> const pthread_attr_t *<span class="variable">__restrict__</span> <span class="variable">__attr</span>, </span><br><span class="line"> void *(*<span class="variable">__start_routine</span>)(void *), </span><br><span class="line"> void *<span class="variable">__restrict__</span> <span class="variable">__arg</span>)</span><br><span class="line"></span><br><span class="line">成功返回<span class="number">0</span>,失败返回错误编号</span><br></pre></td></tr></table></figure>
<ul>