Repository navigation
Expand file tree
/
Copy pathindex.html
More file actions
1632 lines (1149 loc) · 346 KB
/
Copy pathindex.html
File metadata and controls
1632 lines (1149 loc) · 346 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=2">
<meta name="theme-color" content="#222">
<meta name="generator" content="Hexo 4.2.0">
<link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png">
<link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32-next.png">
<link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16-next.png">
<link rel="mask-icon" href="/images/logo.svg" color="#222">
<link rel="stylesheet" href="/css/main.css">
<link rel="stylesheet" href="/lib/font-awesome/css/font-awesome.min.css">
<script id="hexo-configurations">
var NexT = window.NexT || {};
var CONFIG = {"hostname":"yoursite.com","root":"/","scheme":"Muse","version":"7.7.2","exturl":false,"sidebar":{"position":"right","display":"post","padding":18,"offset":12,"onmobile":false},"copycode":{"enable":true,"show_result":false,"style":"default"},"back2top":{"enable":true,"sidebar":false,"scrollpercent":false},"bookmark":{"enable":false,"color":"#222","save":"auto"},"fancybox":false,"mediumzoom":false,"lazyload":false,"pangu":false,"comments":{"style":"tabs","active":null,"storage":true,"lazyload":false,"nav":null},"algolia":{"hits":{"per_page":10},"labels":{"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}},"localsearch":{"enable":false,"trigger":"auto","top_n_per_article":1,"unescape":false,"preload":false},"motion":{"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}}};
</script>
<meta name="description" content="SYSU 计算机专业大二在读">
<meta property="og:type" content="website">
<meta property="og:title" content="reeeeeeeeeein的博客">
<meta property="og:url" content="http://yoursite.com/index.html">
<meta property="og:site_name" content="reeeeeeeeeein的博客">
<meta property="og:description" content="SYSU 计算机专业大二在读">
<meta property="og:locale" content="zh_CN">
<meta property="article:author" content="reeeeeeeeeein">
<meta name="twitter:card" content="summary">
<link rel="canonical" href="http://yoursite.com/">
<script id="page-configurations">
// https://hexo.io/docs/variables.html
CONFIG.page = {
sidebar: "",
isHome : true,
isPost : false
};
</script>
<title>reeeeeeeeeein的博客</title>
<noscript>
<style>
.use-motion .brand,
.use-motion .menu-item,
.sidebar-inner,
.use-motion .post-block,
.use-motion .pagination,
.use-motion .comments,
.use-motion .post-header,
.use-motion .post-body,
.use-motion .collection-header { opacity: initial; }
.use-motion .site-title,
.use-motion .site-subtitle {
opacity: initial;
top: initial;
}
.use-motion .logo-line-before i { left: initial; }
.use-motion .logo-line-after i { right: initial; }
</style>
</noscript>
<script type="text/javascript" src="//cdn.bootcss.com/canvas-nest.js/1.0.0/canvas-nest.min.js">
</script>
</head>
<body itemscope itemtype="http://schema.org/WebPage">
<div class="bg_content">
<canvas id="canvas"></canvas>
</div>
<div class="container use-motion">
<div class="headband"></div>
<header class="header" itemscope itemtype="http://schema.org/WPHeader">
<div class="header-inner"><div class="site-brand-container">
<div class="site-nav-toggle">
<div class="toggle" aria-label="切换导航栏">
<span class="toggle-line toggle-line-first"></span>
<span class="toggle-line toggle-line-middle"></span>
<span class="toggle-line toggle-line-last"></span>
</div>
</div>
<div class="site-meta">
<div>
<a href="/" class="brand" rel="start">
<span class="logo-line-before"><i></i></span>
<span class="site-title">reeeeeeeeeein的博客</span>
<span class="logo-line-after"><i></i></span>
</a>
</div>
</div>
<div class="site-nav-right">
<div class="toggle popup-trigger">
</div>
</div>
</div>
<nav class="site-nav">
<ul id="menu" class="menu">
<li class="menu-item menu-item-home">
<a href="/archives/" rel="section"><i class="fa fa-fw fa-home"></i>首页</a>
</li>
<li class="menu-item menu-item-about">
<a href="/about/" rel="section"><i class="fa fa-fw fa-user"></i>关于</a>
</li>
<li class="menu-item menu-item-tags">
<a href="/tags/" rel="section"><i class="fa fa-fw fa-tags"></i>标签</a>
</li>
<li class="menu-item menu-item-links">
<a href="/links/" rel="section"><i class="fa fa-fw fa-link"></i>友链</a>
</li>
</ul>
</nav>
</div>
</header>
<div class="back-to-top">
<i class="fa fa-arrow-up"></i>
<span>0%</span>
</div>
<main class="main">
<div class="main-inner">
<div class="content-wrap">
<div class="content">
<div class="posts-expand">
<article itemscope itemtype="http://schema.org/Article" class="post-block home" lang="zh-CN">
<link itemprop="mainEntityOfPage" href="http://yoursite.com/2020/06/13/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E5%AE%9E%E9%AA%8C%E4%BA%94_%E6%96%87%E4%BB%B6%E4%BC%A0%E8%BE%93%E5%AE%9E%E9%AA%8C/">
<span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
<meta itemprop="image" content="/images/avatar.gif">
<meta itemprop="name" content="reeeeeeeeeein">
<meta itemprop="description" content="SYSU 计算机专业大二在读">
</span>
<span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
<meta itemprop="name" content="reeeeeeeeeein的博客">
</span>
<header class="post-header">
<h1 class="post-title" itemprop="name headline">
<a href="/2020/06/13/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E5%AE%9E%E9%AA%8C%E4%BA%94_%E6%96%87%E4%BB%B6%E4%BC%A0%E8%BE%93%E5%AE%9E%E9%AA%8C/" class="post-title-link" itemprop="url">计算机网络实验五_文件传输实验</a>
</h1>
<div class="post-meta">
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="fa fa-calendar-o"></i>
</span>
<span class="post-meta-item-text">发表于</span>
<time title="创建时间:2020-06-13 22:52:40" itemprop="dateCreated datePublished" datetime="2020-06-13T22:52:40+08:00">2020-06-13</time>
</span>
</div>
</header>
<div class="post-body" itemprop="articleBody">
<h1 id="文件传输实验"><a href="#文件传输实验" class="headerlink" title="文件传输实验"></a>文件传输实验</h1><h2 id="实验目的"><a href="#实验目的" class="headerlink" title="实验目的"></a>实验目的</h2><p>学习利用套接字传送文件。</p>
<h2 id="实验环境"><a href="#实验环境" class="headerlink" title="实验环境"></a>实验环境</h2><p>WSL,gcc</p>
<h2 id="实验内容"><a href="#实验内容" class="headerlink" title="实验内容"></a>实验内容</h2><h3 id="写一个Ftp客户端程序,用FTP协议下载多个文件到指定目录"><a href="#写一个Ftp客户端程序,用FTP协议下载多个文件到指定目录" class="headerlink" title="写一个Ftp客户端程序,用FTP协议下载多个文件到指定目录"></a>写一个Ftp客户端程序,用FTP协议下载多个文件到指定目录</h3><p>把上次的mytelnet客户端稍作修改,让接受消息的线程在收到227 Entering Passive Mode(103,26,79,35,219,79). 这个消息后自动计算端口号,并绑定一个套接字,启动一个新的线程来接受文件内容。</p>
<h4 id="源代码"><a href="#源代码" class="headerlink" title="源代码"></a>源代码</h4><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string"><netdb.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string"><iostream></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string"><stdlib.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><sys/types.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><sys/socket.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string"><bits/stdc++.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><stdio.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><netinet/in.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><arpa/inet.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><unistd.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><string.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><error.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><pthread.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> BUFLEN 20000 <span class="comment">// 缓冲区大小</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> File_Size 2000000 <span class="comment">// 缓冲区大小</span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> <span class="built_in">std</span>;</span><br><span class="line"><span class="keyword">char</span> host[<span class="number">50</span>];</span><br><span class="line">ofstream out;</span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">input</span><span class="params">(<span class="keyword">char</span>* buf)</span></span>{</span><br><span class="line"> fgets(buf,BUFLEN,<span class="built_in">stdin</span>);</span><br><span class="line"> <span class="keyword">int</span> len=<span class="built_in">strlen</span>(buf);</span><br><span class="line"> buf[len<span class="number">-1</span>]=<span class="string">'\r'</span>,buf[len]=<span class="string">'\n'</span>,buf[++len]=<span class="string">'\0'</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span>* <span class="title">file_recv</span><span class="params">(<span class="keyword">void</span>* in)</span></span>{</span><br><span class="line"> <span class="keyword">int</span> my_sock=(<span class="keyword">long</span>)in;</span><br><span class="line"> <span class="keyword">char</span>* buf=(<span class="keyword">char</span>*)<span class="built_in">malloc</span>((File_Size)*<span class="keyword">sizeof</span>(<span class="keyword">char</span>));</span><br><span class="line"> <span class="keyword">int</span> c1;</span><br><span class="line"> <span class="keyword">while</span>(c1=recv(my_sock,buf,File_Size,<span class="number">0</span>)){</span><br><span class="line"> <span class="keyword">if</span>(c1==<span class="number">-1</span>){</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">NULL</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">cout</span><<c1<<<span class="built_in">endl</span>;</span><br><span class="line"> out.write(buf,c1);</span><br><span class="line"> }</span><br><span class="line"> out.close();</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">NULL</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span>* <span class="title">client_recv</span><span class="params">(<span class="keyword">void</span>* in)</span></span>{</span><br><span class="line"> <span class="keyword">int</span> my_sock=(<span class="keyword">long</span>)in;</span><br><span class="line"> <span class="keyword">char</span>* buf=(<span class="keyword">char</span>*)<span class="built_in">malloc</span>((BUFLEN+<span class="number">1</span>)*<span class="keyword">sizeof</span>(<span class="keyword">char</span>));</span><br><span class="line"> <span class="keyword">while</span>(<span class="number">1</span>){</span><br><span class="line"> <span class="keyword">int</span> c1=recv(my_sock,buf,BUFSIZ,<span class="number">0</span>);</span><br><span class="line"> <span class="keyword">if</span>(c1==<span class="number">0</span>){</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">NULL</span>;</span><br><span class="line"> }</span><br><span class="line"> buf[c1]=<span class="string">'\0'</span>;</span><br><span class="line"> <span class="keyword">if</span>(<span class="built_in">strncmp</span>(buf,<span class="string">"227"</span>,<span class="number">3</span>)==<span class="number">0</span>){</span><br><span class="line"> <span class="keyword">char</span>* tem=buf;</span><br><span class="line"> <span class="keyword">while</span>(*tem!=<span class="string">')'</span>)tem++;</span><br><span class="line"> <span class="keyword">while</span>(*tem!=<span class="string">','</span>)tem--;</span><br><span class="line"> <span class="keyword">int</span> port1=strtol(tem+<span class="number">1</span>,<span class="literal">NULL</span>,<span class="number">10</span>);</span><br><span class="line"> tem--;</span><br><span class="line"> <span class="keyword">while</span>(*tem!=<span class="string">','</span>)tem--;</span><br><span class="line"> <span class="keyword">int</span> port2=strtol(tem+<span class="number">1</span>,<span class="literal">NULL</span>,<span class="number">10</span>);</span><br><span class="line"> port2=(port2<<<span class="number">8</span>)+port1;</span><br><span class="line"> <span class="built_in">cout</span><<port2<<<span class="built_in">endl</span>;</span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">sockaddr_in</span> <span class="title">sin</span>;</span> <span class="comment">/* an Internet endpoint address */</span></span><br><span class="line"> <span class="keyword">char</span> buf[BUFLEN+<span class="number">1</span>]; <span class="comment">/* buffer for one line of text */</span></span><br><span class="line"> <span class="keyword">int</span> sock; <span class="comment">/* socket descriptor */</span></span><br><span class="line"> <span class="keyword">int</span> cc; <span class="comment">/* recv character count */</span></span><br><span class="line"> <span class="keyword">pthread_t</span> thread_handle2;</span><br><span class="line"> sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); <span class="comment">//创建套接字,参数:因特网协议簇(family),流套接字,TCP协议</span></span><br><span class="line"> <span class="comment">//返回:要监听套接字的描述符或INVALID_SOCKET</span></span><br><span class="line"> <span class="built_in">memset</span>(&<span class="built_in">sin</span>, <span class="number">0</span>, <span class="keyword">sizeof</span>(<span class="built_in">sin</span>)); <span class="comment">// 从&sin开始的长度为sizeof(sin)的内存清0</span></span><br><span class="line"> <span class="built_in">sin</span>.sin_family = AF_INET; <span class="comment">// 因特网地址簇</span></span><br><span class="line"> <span class="built_in">sin</span>.sin_addr.s_addr = inet_addr(host);</span><br><span class="line"> <span class="comment">// printf("%d\n",sin.sin_addr.s_addr); // 设置服务器IP地址(32位)</span></span><br><span class="line"> <span class="built_in">sin</span>.sin_port = htons((<span class="keyword">unsigned</span> short)port2); <span class="comment">// 设置服务器端口号</span></span><br><span class="line"> <span class="keyword">int</span> ret=connect(sock, (struct sockaddr *)&<span class="built_in">sin</span>, <span class="keyword">sizeof</span>(<span class="built_in">sin</span>)); <span class="comment">// 连接到服务器,第二个参数指向存放服务器地址的结构,第三个参数为该结构的大小,返回值为0时表示无错误发生,</span></span><br><span class="line"> pthread_create(&thread_handle2,<span class="literal">NULL</span>,file_recv,(<span class="keyword">void</span>*)sock);</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%s\n"</span>,buf);</span><br><span class="line"> <span class="keyword">if</span>(<span class="built_in">strncmp</span>(buf,<span class="string">"221"</span>,<span class="number">3</span>)==<span class="number">0</span>){</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">NULL</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"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">(<span class="keyword">int</span> argc,<span class="keyword">char</span>* argv[])</span></span>{</span><br><span class="line"> <span class="keyword">if</span>(argc!=<span class="number">4</span>){</span><br><span class="line"> <span class="built_in">abort</span>();</span><br><span class="line"> }</span><br><span class="line"> out.open(argv[<span class="number">3</span>],ios::out);</span><br><span class="line"> <span class="built_in">strcpy</span>(host,argv[<span class="number">1</span>]);</span><br><span class="line"></span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%s"</span>,host);</span><br><span class="line"> <span class="keyword">char</span> *service = <span class="string">"21"</span>; <span class="comment">/* server port to connect */</span></span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">sockaddr_in</span> <span class="title">sin</span>;</span> <span class="comment">/* an Internet endpoint address */</span></span><br><span class="line"> <span class="keyword">char</span> buf[BUFLEN+<span class="number">1</span>]; <span class="comment">/* buffer for one line of text */</span></span><br><span class="line"> <span class="keyword">int</span> sock; <span class="comment">/* socket descriptor */</span></span><br><span class="line"> <span class="keyword">int</span> cc; <span class="comment">/* recv character count */</span></span><br><span class="line"> <span class="keyword">pthread_t</span> thread_handle;</span><br><span class="line"> sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); <span class="comment">//创建套接字,参数:因特网协议簇(family),流套接字,TCP协议</span></span><br><span class="line"> <span class="comment">//返回:要监听套接字的描述符或INVALID_SOCKET</span></span><br><span class="line"> <span class="built_in">memset</span>(&<span class="built_in">sin</span>, <span class="number">0</span>, <span class="keyword">sizeof</span>(<span class="built_in">sin</span>)); <span class="comment">// 从&sin开始的长度为sizeof(sin)的内存清0</span></span><br><span class="line"> <span class="built_in">sin</span>.sin_family = AF_INET; <span class="comment">// 因特网地址簇</span></span><br><span class="line"> <span class="built_in">sin</span>.sin_addr.s_addr = inet_addr(host);</span><br><span class="line"><span class="comment">// printf("%d\n",sin.sin_addr.s_addr); // 设置服务器IP地址(32位)</span></span><br><span class="line"> <span class="built_in">sin</span>.sin_port = htons((<span class="keyword">unsigned</span> short)atoi(service)); <span class="comment">// 设置服务器端口号</span></span><br><span class="line"> <span class="keyword">int</span> ret=connect(sock, (struct sockaddr *)&<span class="built_in">sin</span>, <span class="keyword">sizeof</span>(<span class="built_in">sin</span>)); <span class="comment">// 连接到服务器,第二个参数指向存放服务器地址的结构,第三个参数为该结构的大小,返回值为0时表示无错误发生,</span></span><br><span class="line"> pthread_create(&thread_handle,<span class="literal">NULL</span>,client_recv,(<span class="keyword">void</span>*)sock);</span><br><span class="line"> <span class="keyword">char</span> tem[<span class="number">10</span>][<span class="number">100</span>]={<span class="string">"user net\r\n\0"</span>,<span class="string">"pass 123456\r\n\0"</span>,<span class="string">"pasv\r\n\0"</span>,<span class="string">""</span>,<span class="string">"quit\r\n\0"</span>};</span><br><span class="line"> <span class="built_in">sprintf</span>(tem[<span class="number">3</span>],<span class="string">"retr .%s\r\n\0"</span>,argv[<span class="number">2</span>]);</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">0</span>;i<<span class="number">5</span>;i++){</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%s\n"</span>,tem[i]);</span><br><span class="line"> <span class="keyword">int</span> c1=send(sock,tem[i],<span class="built_in">strlen</span>(tem[i]),<span class="number">0</span>);</span><br><span class="line"> <span class="keyword">if</span>(c1==<span class="number">0</span>){</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"Error !\n"</span>);</span><br><span class="line"> <span class="built_in">abort</span>();</span><br><span class="line"> }</span><br><span class="line"> } <span class="comment">// 关闭监听套接字</span></span><br><span class="line"> pthread_join(thread_handle,<span class="literal">NULL</span>);</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"按回车键继续..."</span>);</span><br><span class="line"> getchar(); <span class="comment">// 等待任意按键</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h4 id="运行截屏及说明"><a href="#运行截屏及说明" class="headerlink" title="运行截屏及说明"></a>运行截屏及说明</h4><p>这个有点坑,一个是斜杠和反斜杠不能搞错,另一个是传大文件的时候要多recv几次,不然一次recv收不下来。<br>由于我是在wsl里完成的实验,因此命令行的最后一个参数用 /mnt/e 把文件放置在windows系统的e盘。<br><img src="https://i.loli.net/2020/06/13/5daU4Ao8g7Tfpei.png" alt="image.png"><br><img src="https://i.loli.net/2020/06/13/49E1uSgbnCUfPyF.png" alt="image.png"></p>
<h3 id="通过建立TCP连接实现一对一的聊天和传输文件功能"><a href="#通过建立TCP连接实现一对一的聊天和传输文件功能" class="headerlink" title="通过建立TCP连接实现一对一的聊天和传输文件功能"></a>通过建立TCP连接实现一对一的聊天和传输文件功能</h3><h4 id="功能说明"><a href="#功能说明" class="headerlink" title="功能说明"></a>功能说明</h4><p>在客户和服务器之间建立TCP连接之后,任何一方可以输入并执行命令:</p>
<p>rdir d:\test 设置接收文件的目录d:\test<br>chat hello 向对方发送聊天字符串“hello”或者 >hello (非命令即可)<br>send c:\temp\ftp.pdf 向对方发送文件ftp.pdf,接收方对重名文件加编号。<br>quit 退出程序</p>
<h4 id="数据包设计(仅作参考)"><a href="#数据包设计(仅作参考)" class="headerlink" title="数据包设计(仅作参考)"></a>数据包设计(仅作参考)</h4><p>一个包由三部分构成:结构1,结构2(多种类型),数据。其中:结构1和结构2分别包含数据类型和数据长度。<br>在接收结构1之后,通过数据类型确定结构2,不同数据类型的结构2可以不同,再通过结构2中的数据长度接收数据。<br>接收结构和数据均要根据该结构或数据的长度接收。 要累计已接收的字节数,直到全部接收完毕,再接收下一部分。</p>
<h4 id="源代码-1"><a href="#源代码-1" class="headerlink" title="源代码"></a>源代码</h4><p>客户端:(p2pClient.cpp)</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><netdb.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><stdlib.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><sys/types.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><sys/socket.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><stdio.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><netinet/in.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><arpa/inet.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><unistd.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><string.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><error.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><pthread.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><semaphore.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><bits/stdc++.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> BUFLEN 20000 <span class="comment">// 缓冲区大小</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> FILE_SIZE 1001000</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> FILE_NAME_LEN 300</span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> <span class="built_in">std</span>;</span><br><span class="line"><span class="built_in">map</span><<span class="built_in">string</span>, <span class="keyword">int</span>> mp;</span><br><span class="line"><span class="keyword">char</span> dest_folder[<span class="number">100</span>]=<span class="string">"./new"</span>;</span><br><span class="line">ofstream out;</span><br><span class="line"><span class="keyword">sem_t</span> my_semaphore;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">FileStruct</span></span></span><br><span class="line"><span class="class">{</span></span><br><span class="line"> <span class="keyword">char</span> fileName[<span class="number">300</span>];</span><br><span class="line"> <span class="keyword">long</span> <span class="keyword">long</span> fileSize;</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">long</span> <span class="keyword">long</span> <span class="title">getFileSize</span><span class="params">(<span class="keyword">char</span> *fileName)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> FILE *fp = fopen(fileName, <span class="string">"r"</span>);</span><br><span class="line"> <span class="keyword">if</span>(fp==<span class="literal">NULL</span>)<span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line"> fseek(fp, <span class="number">0</span>, SEEK_END);</span><br><span class="line"> <span class="keyword">size_t</span> size = ftell(fp);</span><br><span class="line"> fclose(fp);</span><br><span class="line"> <span class="keyword">return</span> size;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">char</span> *<span class="title">getFileName</span><span class="params">(<span class="keyword">char</span> *pathName)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">char</span>* tem=pathName;</span><br><span class="line"> <span class="keyword">while</span> (*tem != <span class="string">'\0'</span>)</span><br><span class="line"> tem++;</span><br><span class="line"> <span class="keyword">while</span> (*tem != <span class="string">'/'</span> && tem!=pathName)</span><br><span class="line"> tem--;</span><br><span class="line"> <span class="keyword">return</span> tem==pathName?tem:tem+<span class="number">1</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">input</span><span class="params">(<span class="keyword">char</span> *buf)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> fgets(buf, BUFLEN, <span class="built_in">stdin</span>);</span><br><span class="line"> <span class="keyword">int</span> len = <span class="built_in">strlen</span>(buf);</span><br><span class="line"> buf[len - <span class="number">1</span>] = <span class="string">'\0'</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">Unpack</span><span class="params">(struct FileStruct *fileStruct, <span class="keyword">char</span> *file_content, <span class="keyword">char</span> *folder_name)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">char</span> Full_name[FILE_NAME_LEN];</span><br><span class="line"> <span class="built_in">sprintf</span>(Full_name, <span class="string">"%s/%s"</span>, folder_name, fileStruct->fileName);</span><br><span class="line"> <span class="comment">// printf("%s\n",Full_name);</span></span><br><span class="line"> FILE *file = fopen(Full_name, <span class="string">"wb"</span>);</span><br><span class="line"> fwrite(file_content, <span class="keyword">sizeof</span>(<span class="keyword">char</span>), fileStruct->fileSize, file);</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">add_suffix</span><span class="params">(<span class="keyword">char</span> *new_filename, <span class="keyword">int</span> occur_time, <span class="keyword">char</span> *old_filename)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">char</span> *tem = old_filename;</span><br><span class="line"> <span class="keyword">while</span> (*tem != <span class="string">'\0'</span>)</span><br><span class="line"> tem++;</span><br><span class="line"> <span class="keyword">while</span> (*tem != <span class="string">'.'</span> && tem != old_filename)</span><br><span class="line"> tem--;</span><br><span class="line"> <span class="keyword">if</span> (tem != old_filename)</span><br><span class="line"> {</span><br><span class="line"> *tem = <span class="string">'\0'</span>;</span><br><span class="line"> <span class="built_in">sprintf</span>(new_filename, <span class="string">"%s(%d).%s"</span>, old_filename, occur_time, tem + <span class="number">1</span>);</span><br><span class="line"> *tem = <span class="string">'.'</span>;</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">sprintf</span>(new_filename, <span class="string">"%s(%d)"</span>, old_filename, occur_time);</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> *<span class="title">client_recv</span><span class="params">(<span class="keyword">void</span> *in)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">int</span> my_sock = (<span class="keyword">long</span>)in;</span><br><span class="line"> <span class="keyword">char</span> *buf = (<span class="keyword">char</span> *)<span class="built_in">malloc</span>((BUFLEN + <span class="number">1</span>) * <span class="keyword">sizeof</span>(<span class="keyword">char</span>));</span><br><span class="line"> <span class="keyword">while</span> (<span class="number">1</span>)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> c1 = recv(my_sock, buf, BUFSIZ, <span class="number">0</span>);</span><br><span class="line"> <span class="keyword">if</span> (c1 == <span class="number">-1</span> || c1 == <span class="number">0</span>)</span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"接收消息错误!\n"</span>);</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">NULL</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (c1 <= <span class="number">300</span>)</span><br><span class="line"> {</span><br><span class="line"> buf[c1] = <span class="string">'\0'</span>;</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"收到消息:\n%s\n"</span>, buf);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">char</span> file_name[FILE_NAME_LEN];</span><br><span class="line"> <span class="keyword">char</span> full_file_name[FILE_NAME_LEN];</span><br><span class="line"> <span class="built_in">memcpy</span>(file_name, buf, FILE_NAME_LEN);</span><br><span class="line"><span class="comment">// printf("file name: %s",file_name);</span></span><br><span class="line"> sem_wait(&my_semaphore);</span><br><span class="line"> <span class="keyword">if</span> (mp.count(<span class="built_in">string</span>(file_name)))</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">char</span> new_file_name[FILE_NAME_LEN];</span><br><span class="line"> add_suffix(new_file_name, mp[<span class="built_in">string</span>(file_name)], file_name);</span><br><span class="line"> <span class="built_in">strcpy</span>(file_name, new_file_name);</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">sprintf</span>(full_file_name, <span class="string">"%s/%s"</span>, dest_folder, file_name);</span><br><span class="line"> mp[<span class="built_in">string</span>(file_name)]++;</span><br><span class="line"> sem_post(&my_semaphore);</span><br><span class="line"> out.open(full_file_name, ios::out);</span><br><span class="line"></span><br><span class="line"> out.write(buf + <span class="keyword">sizeof</span>(FileStruct), <span class="built_in">strlen</span>(buf + <span class="keyword">sizeof</span>(FileStruct)));</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"文件已经被写入到 %s!\n"</span>, full_file_name);</span><br><span class="line"> out.close();</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="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">(<span class="keyword">int</span> argc, <span class="keyword">char</span> *argv[])</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (argc != <span class="number">3</span>)</span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">abort</span>();</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">const</span> <span class="keyword">char</span> *host = argv[<span class="number">1</span>];</span><br><span class="line"> <span class="comment">// printf("%s", host);</span></span><br><span class="line"> <span class="keyword">char</span> *service = argv[<span class="number">2</span>]; <span class="comment">/* server port to connect */</span></span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">sockaddr_in</span> <span class="title">sin</span>;</span> <span class="comment">/* an Internet endpoint address */</span></span><br><span class="line"> <span class="keyword">char</span> buf[BUFLEN + <span class="number">1</span>]; <span class="comment">/* buffer for one line of text */</span></span><br><span class="line"> <span class="keyword">int</span> sock; <span class="comment">/* socket descriptor */</span></span><br><span class="line"> <span class="keyword">int</span> cc; <span class="comment">/* recv character count */</span></span><br><span class="line"> <span class="keyword">pthread_t</span> thread_handle;</span><br><span class="line"> sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); <span class="comment">//创建套接字,参数:因特网协议簇(family),流套接字,TCP协议</span></span><br><span class="line"> <span class="comment">//返回:要监听套接字的描述符或INVALID_SOCKET</span></span><br><span class="line"> <span class="built_in">memset</span>(&<span class="built_in">sin</span>, <span class="number">0</span>, <span class="keyword">sizeof</span>(<span class="built_in">sin</span>)); <span class="comment">// 从&sin开始的长度为sizeof(sin)的内存清0</span></span><br><span class="line"> <span class="built_in">sin</span>.sin_family = AF_INET; <span class="comment">// 因特网地址簇</span></span><br><span class="line"> <span class="built_in">sin</span>.sin_addr.s_addr = inet_addr(host);</span><br><span class="line"> <span class="comment">// printf("%d\n",sin.sin_addr.s_addr); // 设置服务器IP地址(32位)</span></span><br><span class="line"> <span class="built_in">sin</span>.sin_port = htons((<span class="keyword">unsigned</span> short)atoi(service)); <span class="comment">// 设置服务器端口号</span></span><br><span class="line"> <span class="keyword">int</span> ret = connect(sock, (struct sockaddr *)&<span class="built_in">sin</span>, <span class="keyword">sizeof</span>(<span class="built_in">sin</span>)); <span class="comment">// 连接到服务器,第二个参数指向存放服务器地址的结构,第三个参数为该结构的大小,返回值为0时表示无错误发生,</span></span><br><span class="line"></span><br><span class="line"> sem_init(&my_semaphore, <span class="number">0</span>, <span class="number">1</span>);</span><br><span class="line"> pthread_create(&thread_handle, <span class="literal">NULL</span>, client_recv, (<span class="keyword">void</span> *)sock);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">while</span> (<span class="number">1</span>)</span><br><span class="line"> {</span><br><span class="line"> input(buf);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (<span class="built_in">strcmp</span>(buf, <span class="string">">quit"</span>) == <span class="number">0</span>)</span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"退出成功!\n"</span>);</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span> (<span class="built_in">strncmp</span>(<span class="string">">chat"</span>, buf, <span class="number">5</span>) == <span class="number">0</span>)</span><br><span class="line"> {</span><br><span class="line"> send(sock, buf + <span class="number">6</span>, <span class="built_in">strlen</span>(buf + <span class="number">6</span>), <span class="number">0</span>);</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"消息发送成功!\n"</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span> (<span class="built_in">strncmp</span>(<span class="string">">send"</span>, buf, <span class="number">5</span>) == <span class="number">0</span>)</span><br><span class="line"> {</span><br><span class="line"> struct FileStruct f;</span><br><span class="line"> f.fileSize = getFileSize(buf + <span class="number">6</span>);</span><br><span class="line"> <span class="keyword">if</span>(f.fileSize==<span class="number">-1</span>){</span><br><span class="line"> <span class="built_in">cout</span><<<span class="string">"Error file name!\n"</span>;</span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">strcpy</span>(f.fileName, getFileName(buf + <span class="number">6</span>));</span><br><span class="line"> <span class="keyword">char</span> *File_pack = (<span class="keyword">char</span> *)<span class="built_in">malloc</span>(<span class="keyword">sizeof</span>(<span class="keyword">char</span>) * FILE_SIZE);</span><br><span class="line"> <span class="built_in">memcpy</span>(File_pack, &f, <span class="keyword">sizeof</span>(FileStruct));</span><br><span class="line"> FILE *tem_file = fopen(buf + <span class="number">6</span>, <span class="string">"r"</span>);</span><br><span class="line"> <span class="keyword">char</span> *content = (<span class="keyword">char</span> *)<span class="built_in">malloc</span>(f.fileSize);</span><br><span class="line"> fread(content, f.fileSize, <span class="number">1</span>, tem_file);</span><br><span class="line"> fclose(tem_file);</span><br><span class="line"> <span class="built_in">memcpy</span>(File_pack + <span class="keyword">sizeof</span>(FileStruct), content, f.fileSize);</span><br><span class="line"> send(sock, File_pack, <span class="keyword">sizeof</span>(FileStruct) + f.fileSize, <span class="number">0</span>);</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"文件发送成功!\n"</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span> (<span class="built_in">strncmp</span>(<span class="string">">rdir"</span>, buf, <span class="number">5</span>) == <span class="number">0</span>)</span><br><span class="line"> {</span><br><span class="line"> sem_wait(&my_semaphore);</span><br><span class="line"> <span class="built_in">strcpy</span>(dest_folder, buf + <span class="number">6</span>);</span><br><span class="line"> mp.clear();</span><br><span class="line"> sem_post(&my_semaphore);</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"文件夹路径已被修改!\n"</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> pthread_join(thread_handle, <span class="literal">NULL</span>);</span><br><span class="line"> close(sock); <span class="comment">// 关闭监听套接字</span></span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"按回车键继续..."</span>);</span><br><span class="line"> getchar(); <span class="comment">// 等待任意按键</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>服务器程序:</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><netdb.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><stdlib.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><sys/types.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><sys/socket.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><stdio.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><netinet/in.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><arpa/inet.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><unistd.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><string.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><error.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><pthread.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><semaphore.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><bits/stdc++.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> BUFLEN 20000 <span class="comment">// 缓冲区大小</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> FILE_SIZE 1001000</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> FILE_NAME_LEN 300</span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> <span class="built_in">std</span>;</span><br><span class="line"><span class="built_in">map</span><<span class="built_in">string</span>, <span class="keyword">int</span>> mp;</span><br><span class="line"><span class="keyword">char</span> dest_folder[<span class="number">100</span>]=<span class="string">"./new"</span>;</span><br><span class="line">ofstream out;</span><br><span class="line"><span class="keyword">sem_t</span> my_semaphore;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">FileStruct</span></span></span><br><span class="line"><span class="class">{</span></span><br><span class="line"> <span class="keyword">char</span> fileName[<span class="number">300</span>];</span><br><span class="line"> <span class="keyword">long</span> <span class="keyword">long</span> fileSize;</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">long</span> <span class="keyword">long</span> <span class="title">getFileSize</span><span class="params">(<span class="keyword">char</span> *fileName)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> FILE *fp = fopen(fileName, <span class="string">"r"</span>);</span><br><span class="line"> <span class="keyword">if</span>(fp==<span class="literal">NULL</span>)<span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line"> fseek(fp, <span class="number">0</span>, SEEK_END);</span><br><span class="line"> <span class="keyword">size_t</span> size = ftell(fp);</span><br><span class="line"> fclose(fp);</span><br><span class="line"> <span class="keyword">return</span> size;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">char</span> *<span class="title">getFileName</span><span class="params">(<span class="keyword">char</span> *pathName)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">char</span>* tem=pathName;</span><br><span class="line"> <span class="keyword">while</span> (*tem != <span class="string">'\0'</span>)</span><br><span class="line"> tem++;</span><br><span class="line"> <span class="keyword">while</span> (*tem != <span class="string">'/'</span> && tem!=pathName)</span><br><span class="line"> tem--;</span><br><span class="line"> <span class="keyword">return</span> tem==pathName?tem:tem+<span class="number">1</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">input</span><span class="params">(<span class="keyword">char</span> *buf)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> fgets(buf, BUFLEN, <span class="built_in">stdin</span>);</span><br><span class="line"> <span class="keyword">int</span> len = <span class="built_in">strlen</span>(buf);</span><br><span class="line"> buf[len - <span class="number">1</span>] = <span class="string">'\0'</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">Unpack</span><span class="params">(struct FileStruct *fileStruct, <span class="keyword">char</span> *file_content, <span class="keyword">char</span> *folder_name)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">char</span> Full_name[FILE_NAME_LEN];</span><br><span class="line"> <span class="built_in">sprintf</span>(Full_name, <span class="string">"%s/%s"</span>, folder_name, fileStruct->fileName);</span><br><span class="line"> <span class="comment">// printf("%s\n",Full_name);</span></span><br><span class="line"> FILE *file = fopen(Full_name, <span class="string">"wb"</span>);</span><br><span class="line"> fwrite(file_content, <span class="keyword">sizeof</span>(<span class="keyword">char</span>), fileStruct->fileSize, file);</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">add_suffix</span><span class="params">(<span class="keyword">char</span> *new_filename, <span class="keyword">int</span> occur_time, <span class="keyword">char</span> *old_filename)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">char</span> *tem = old_filename;</span><br><span class="line"> <span class="keyword">while</span> (*tem != <span class="string">'\0'</span>)</span><br><span class="line"> tem++;</span><br><span class="line"> <span class="keyword">while</span> (*tem != <span class="string">'.'</span> && tem != old_filename)</span><br><span class="line"> tem--;</span><br><span class="line"> <span class="keyword">if</span> (tem != old_filename)</span><br><span class="line"> {</span><br><span class="line"> *tem = <span class="string">'\0'</span>;</span><br><span class="line"> <span class="built_in">sprintf</span>(new_filename, <span class="string">"%s(%d).%s"</span>, old_filename, occur_time, tem + <span class="number">1</span>);</span><br><span class="line"> *tem = <span class="string">'.'</span>;</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">sprintf</span>(new_filename, <span class="string">"%s(%d)"</span>, old_filename, occur_time);</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> *<span class="title">client_recv</span><span class="params">(<span class="keyword">void</span> *in)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">int</span> my_sock = (<span class="keyword">long</span>)in;</span><br><span class="line"> <span class="keyword">char</span> *buf = (<span class="keyword">char</span> *)<span class="built_in">malloc</span>((BUFLEN + <span class="number">1</span>) * <span class="keyword">sizeof</span>(<span class="keyword">char</span>));</span><br><span class="line"> <span class="keyword">while</span> (<span class="number">1</span>)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> c1 = recv(my_sock, buf, BUFSIZ, <span class="number">0</span>);</span><br><span class="line"> <span class="keyword">if</span> (c1 == <span class="number">-1</span> || c1 == <span class="number">0</span>)</span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"接收消息错误!\n"</span>);</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">NULL</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (c1 <= <span class="number">300</span>)</span><br><span class="line"> {</span><br><span class="line"> buf[c1] = <span class="string">'\0'</span>;</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"收到消息:\n%s\n"</span>, buf);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">char</span> file_name[FILE_NAME_LEN];</span><br><span class="line"> <span class="keyword">char</span> full_file_name[FILE_NAME_LEN];</span><br><span class="line"> <span class="built_in">memcpy</span>(file_name, buf, FILE_NAME_LEN);</span><br><span class="line"><span class="comment">// printf("file name: %s",file_name);</span></span><br><span class="line"> sem_wait(&my_semaphore);</span><br><span class="line"> <span class="keyword">if</span> (mp.count(<span class="built_in">string</span>(file_name)))</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">char</span> new_file_name[FILE_NAME_LEN];</span><br><span class="line"> add_suffix(new_file_name, mp[<span class="built_in">string</span>(file_name)], file_name);</span><br><span class="line"> <span class="built_in">strcpy</span>(file_name, new_file_name);</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">sprintf</span>(full_file_name, <span class="string">"%s/%s"</span>, dest_folder, file_name);</span><br><span class="line"> mp[<span class="built_in">string</span>(file_name)]++;</span><br><span class="line"> sem_post(&my_semaphore);</span><br><span class="line"> out.open(full_file_name, ios::out);</span><br><span class="line"></span><br><span class="line"> out.write(buf + <span class="keyword">sizeof</span>(FileStruct), <span class="built_in">strlen</span>(buf + <span class="keyword">sizeof</span>(FileStruct)));</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"文件已经被写入到 %s!\n"</span>, full_file_name);</span><br><span class="line"> out.close();</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="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">(<span class="keyword">int</span> argc, <span class="keyword">char</span> *argv[])</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">const</span> <span class="keyword">char</span> *host = <span class="string">"127.0.0.1"</span>;</span><br><span class="line"> <span class="comment">// printf("%s", host);</span></span><br><span class="line"> <span class="keyword">char</span> *service = <span class="string">"50500"</span>; <span class="comment">/* server port to connect */</span></span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">sockaddr_in</span> <span class="title">sin</span>, <span class="title">fsin</span>;</span> <span class="comment">/* an Internet endpoint address */</span></span><br><span class="line"> <span class="keyword">char</span> buf[BUFLEN + <span class="number">1</span>]; <span class="comment">/* buffer for one line of text */</span></span><br><span class="line"> <span class="keyword">int</span> sock, ssock, alen; <span class="comment">/* socket descriptor */</span></span><br><span class="line"> <span class="keyword">int</span> cc; <span class="comment">/* recv character count */</span></span><br><span class="line"> <span class="keyword">pthread_t</span> thread_handle;</span><br><span class="line"> sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); <span class="comment">//创建套接字,参数:因特网协议簇(family),流套接字,TCP协议</span></span><br><span class="line"> <span class="comment">//返回:要监听套接字的描述符或INVALID_SOCKET</span></span><br><span class="line"> <span class="built_in">memset</span>(&<span class="built_in">sin</span>, <span class="number">0</span>, <span class="keyword">sizeof</span>(<span class="built_in">sin</span>)); <span class="comment">// 从&sin开始的长度为sizeof(sin)的内存清0</span></span><br><span class="line"> <span class="built_in">sin</span>.sin_family = AF_INET; <span class="comment">// 因特网地址簇</span></span><br><span class="line"> <span class="built_in">sin</span>.sin_addr.s_addr = inet_addr(host);</span><br><span class="line"> <span class="comment">// printf("%d\n",sin.sin_addr.s_addr); // 设置服务器IP地址(32位)</span></span><br><span class="line"> <span class="built_in">sin</span>.sin_port = htons((<span class="keyword">unsigned</span> short)atoi(service)); <span class="comment">// 设置服务器端口号</span></span><br><span class="line"></span><br><span class="line"> bind(sock, (struct sockaddr *)&<span class="built_in">sin</span>, <span class="keyword">sizeof</span>(<span class="built_in">sin</span>)); <span class="comment">// 绑定监听的IP地址和端口号</span></span><br><span class="line"></span><br><span class="line"> listen(sock, <span class="number">5</span>); <span class="comment">// 建立长度为5的连接请求队列,并把到来的连接请求加入队列等待处理。</span></span><br><span class="line"></span><br><span class="line"> ssock = accept(sock, (struct sockaddr *)&fsin, (<span class="keyword">socklen_t</span> *)&alen); <span class="comment">// 如果在连接请求队列中有连接请求,则接受连接请求并建立连接,返回该连接的套接字,否则,本语句被阻塞直到队列非空。fsin包含客户端IP地址和端口号</span></span><br><span class="line"></span><br><span class="line"> sem_init(&my_semaphore, <span class="number">0</span>, <span class="number">1</span>);</span><br><span class="line"> pthread_create(&thread_handle, <span class="literal">NULL</span>, client_recv, (<span class="keyword">void</span> *)ssock);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">while</span> (<span class="number">1</span>)</span><br><span class="line"> {</span><br><span class="line"> input(buf);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (<span class="built_in">strcmp</span>(buf, <span class="string">">quit"</span>) == <span class="number">0</span>)</span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"退出成功!\n"</span>);</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span> (<span class="built_in">strncmp</span>(<span class="string">">chat"</span>, buf, <span class="number">5</span>) == <span class="number">0</span>)</span><br><span class="line"> {</span><br><span class="line"> send(ssock, buf + <span class="number">6</span>, <span class="built_in">strlen</span>(buf + <span class="number">6</span>), <span class="number">0</span>);</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"消息发送成功!\n"</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span> (<span class="built_in">strncmp</span>(<span class="string">">send"</span>, buf, <span class="number">5</span>) == <span class="number">0</span>)</span><br><span class="line"> {</span><br><span class="line"> struct FileStruct f;</span><br><span class="line"> f.fileSize = getFileSize(buf + <span class="number">6</span>);</span><br><span class="line"> <span class="keyword">if</span>(f.fileSize==<span class="number">-1</span>){</span><br><span class="line"> <span class="built_in">cout</span><<<span class="string">"文件名错误!\n"</span>;</span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">strcpy</span>(f.fileName, getFileName(buf + <span class="number">6</span>));</span><br><span class="line"> <span class="keyword">char</span> *File_pack = (<span class="keyword">char</span> *)<span class="built_in">malloc</span>(<span class="keyword">sizeof</span>(<span class="keyword">char</span>) * FILE_SIZE);</span><br><span class="line"> <span class="built_in">memcpy</span>(File_pack, &f, <span class="keyword">sizeof</span>(FileStruct));</span><br><span class="line"> FILE *tem_file = fopen(buf + <span class="number">6</span>, <span class="string">"r"</span>);</span><br><span class="line"> <span class="keyword">char</span> *content = (<span class="keyword">char</span> *)<span class="built_in">malloc</span>(f.fileSize);</span><br><span class="line"> fread(content, f.fileSize, <span class="number">1</span>, tem_file);</span><br><span class="line"> fclose(tem_file);</span><br><span class="line"> <span class="built_in">memcpy</span>(File_pack + <span class="keyword">sizeof</span>(FileStruct), content, f.fileSize);</span><br><span class="line"> send(ssock, File_pack, <span class="keyword">sizeof</span>(FileStruct) + f.fileSize, <span class="number">0</span>);</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"文件发送成功!\n"</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span> (<span class="built_in">strncmp</span>(<span class="string">">rdir"</span>, buf, <span class="number">5</span>) == <span class="number">0</span>)</span><br><span class="line"> {</span><br><span class="line"> sem_wait(&my_semaphore);</span><br><span class="line"> <span class="built_in">strcpy</span>(dest_folder, buf + <span class="number">6</span>);</span><br><span class="line"> mp.clear();</span><br><span class="line"> sem_post(&my_semaphore);</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"文件夹路径已被修改!\n"</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> pthread_join(thread_handle, <span class="literal">NULL</span>);</span><br><span class="line"> close(sock); <span class="comment">// 关闭监听套接字</span></span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"按回车键继续..."</span>);</span><br><span class="line"> getchar(); <span class="comment">// 等待任意按键</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h4 id="服务器运行截屏"><a href="#服务器运行截屏" class="headerlink" title="服务器运行截屏"></a>服务器运行截屏</h4><p><img src="https://i.loli.net/2020/06/13/1txqygFRInASXGC.png" alt="image.png"><br>可以看到文件确实被写入到e盘了。<br><img src="https://i.loli.net/2020/06/13/2pLw8JSBtGHMnci.png" alt="image.png"></p>
<h4 id="客户端运行截屏"><a href="#客户端运行截屏" class="headerlink" title="客户端运行截屏"></a>客户端运行截屏</h4><p> <img src="https://i.loli.net/2020/06/13/daP5Z6nM7rxFfiC.png" alt="image.png"></p>
<h3 id="实验体会"><a href="#实验体会" class="headerlink" title="实验体会"></a>实验体会</h3><p>遇到的最大问题可能还是对套接字程序设计不够熟悉,有些函数只能照着之前的模板来用,导致程序里的很多代码都是复制粘贴的。还有就是ftp协议的send和recv是有点坑,服务器发送的消息长度比较短,对于大的文件一次传不完。<br>总的来说这次实验不是很难,掌握了原理之后完成起来比较简单。</p>
</div>
<footer class="post-footer">
<div class="post-eof"></div>
</footer>
</article>
<article itemscope itemtype="http://schema.org/Article" class="post-block home" lang="zh-CN">
<link itemprop="mainEntityOfPage" href="http://yoursite.com/2020/06/13/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E5%AE%9E%E9%AA%8C%E5%9B%9B_%E4%B8%AD%E6%96%AD%E6%8E%A7%E5%88%B6/">
<span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
<meta itemprop="image" content="/images/avatar.gif">
<meta itemprop="name" content="reeeeeeeeeein">
<meta itemprop="description" content="SYSU 计算机专业大二在读">
</span>
<span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
<meta itemprop="name" content="reeeeeeeeeein的博客">
</span>
<header class="post-header">
<h1 class="post-title" itemprop="name headline">
<a href="/2020/06/13/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E5%AE%9E%E9%AA%8C%E5%9B%9B_%E4%B8%AD%E6%96%AD%E6%8E%A7%E5%88%B6/" class="post-title-link" itemprop="url">操作系统实验四_中断控制</a>
</h1>
<div class="post-meta">
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="fa fa-calendar-o"></i>
</span>
<span class="post-meta-item-text">发表于</span>
<time title="创建时间:2020-06-13 18:20:29" itemprop="dateCreated datePublished" datetime="2020-06-13T18:20:29+08:00">2020-06-13</time>
</span>
</div>
</header>
<div class="post-body" itemprop="articleBody">
<h1 id="操作系统实验报告"><a href="#操作系统实验报告" class="headerlink" title="操作系统实验报告"></a>操作系统实验报告</h1><p>[toc]</p>
<h2 id="实验目的"><a href="#实验目的" class="headerlink" title="实验目的"></a>实验目的</h2><p>1、PC系统的中断机制和原理</p>
<p>2、理解操作系统内核对异步事件的处理方法</p>
<p>3、掌握中断处理编程的方法</p>
<p>4、掌握内核中断处理代码组织的设计方法</p>
<p>5、了解查询式I/O控制方式的编程方法</p>
<h2 id="实验要求"><a href="#实验要求" class="headerlink" title="实验要求"></a>实验要求</h2><p>1、知道PC系统的中断硬件系统的原理</p>
<p>2、掌握x86汇编语言对时钟中断的响应处理编程方法</p>
<p>3、重写和扩展实验三的的内核程序,增加时钟中断的响应处理和键盘中断响应。</p>
<p>4、编写实验报告,描述实验工作的过程和必要的细节,如截屏或录屏,以证实实验工作的真实性</p>
<h2 id="实验环境"><a href="#实验环境" class="headerlink" title="实验环境"></a>实验环境</h2><ul>
<li>Windows 10</li>
<li>WSL (Windows Subsystem for Linux) [Ubuntu 18.04.2 LTS]:WSL 是以软件的形式运行在 Windows 下的 Linux 子系统,是近些年微软推出来的新工具,可以在 Windows 系统上原生运行 Linux。</li>
<li>gcc version 7.5.0:C 语言程序编译器,Ubuntu 自带。</li>
<li>ld version 2.3.0: 链接器,Ubuntu自带</li>
<li>NASM version 2.13.02:汇编程序编译器,通过<code>sudo apt install nasm</code>安装在 WSL 上。</li>
<li>Oracle VM VirtualBox :轻量开源的虚拟机软件,安装在Windows下。</li>
<li>VSCode - Insiders v1.33.0:好用的文本编辑器,有丰富的插件,可以用它来打开WSL中的文件夹,用它自带的终端执行make命令。</li>
<li>GNU Make 4.1:安装在 Ubuntu 下,一键编译并连接代码,生成最终的文件。</li>
<li>Bochs 2.1.1:安装在Windows下,用于调试代码。</li>
</ul>
<h3 id="自制工具"><a href="#自制工具" class="headerlink" title="自制工具"></a>自制工具</h3><p>由于我的虚拟机和Bochs都安装在Windows下,所以需要将WSL中生成的文件写入至Windows的磁盘,这可以用我编写的工具 do 来解决,只需要执行</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">./do 文件名 写入的扇区</span><br></pre></td></tr></table></figure>
<p>就可以了。</p>
<h2 id="实验内容"><a href="#实验内容" class="headerlink" title="实验内容"></a>实验内容</h2><h3 id="概述"><a href="#概述" class="headerlink" title="概述"></a>概述</h3><p>由于<a href="https://reeeeeeeeeein.github.io/2020/05/15/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E5%AE%9E%E9%AA%8C%E4%B8%89_%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E5%86%85%E6%A0%B8/" target="_blank" rel="noopener">上次实验</a>已经写好了操作系统内核,这次只用在里面修改即可。首先学习x86中断系统,明白时钟中断的原理,然后用时间中断实现”风火轮“,用一个其他中断实现用户程序敲击键盘显示’OUCH!OUCH!’的功能。</p>
<h3 id="设置中断入口点"><a href="#设置中断入口点" class="headerlink" title="设置中断入口点"></a>设置中断入口点</h3><p>为了方便地使用中断,可以编写一个中断服务程序,再修改中断号对应的中断向量表。修改中断向量表的操作对不同中断是相似的,只是中断号和中断服务程序的地址不同而已,我们把这部分内容写成一个宏,放置在entry.asm里,如下所示:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line">%macro set_ivt 2</span><br><span class="line">;第一个参数表示第几号中断,第二个参数表示中断服务程序的位置</span><br><span class="line">push ax</span><br><span class="line">push es</span><br><span class="line">push bx</span><br><span class="line">push si</span><br><span class="line">push dx</span><br><span class="line"></span><br><span class="line">xor ax,ax</span><br><span class="line">mov es,ax</span><br><span class="line">mov ax,%1</span><br><span class="line">mov bx,4</span><br><span class="line">xor dx,dx</span><br><span class="line">mul bx;中断号*4后得到中断向量表中对应的地址</span><br><span class="line">mov si,ax</span><br><span class="line">xor dx,dx</span><br><span class="line">mov ax,%2</span><br><span class="line">mov bx,16;把位置除以16,得到偏移量和段地址</span><br><span class="line">div bx</span><br><span class="line">mov word [es:si],dx;前两个字节放偏移量</span><br><span class="line">mov word [es:si+2],ax;后两个字节放段地址</span><br><span class="line"></span><br><span class="line">pop dx</span><br><span class="line">pop si</span><br><span class="line">pop bx</span><br><span class="line">pop es</span><br><span class="line">pop ax</span><br><span class="line">%endmacro</span><br></pre></td></tr></table></figure>
<h3 id="编写时钟中断"><a href="#编写时钟中断" class="headerlink" title="编写时钟中断"></a>编写时钟中断</h3><p>x86系统会自动产生时钟中断,为了实现’’风火轮’的效果,我们可以修改中断向量表中0x08号中断对应的内容,让它指向我们编写的中断服务程序。中断服务程序很简单,只用在内存中放置一个变量表示当前是显示’-‘、’\‘还是’/‘即可。但值得注意的是开始时要关中断,返回前要开中断,且要加上</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">int 0x1c</span><br><span class="line">mov al,20h</span><br><span class="line">out 20h,al</span><br></pre></td></tr></table></figure>
<p>这几行代码,没有这些代码会出现莫名其妙的错误,一直找不到原因。</p>
<p>写完之后,在内核入口处加上一句:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">set_ivt 8h,_int_8h</span><br></pre></td></tr></table></figure>
<p>就可以修改中断向量表了。</p>
<h3 id="编写-33号中断"><a href="#编写-33号中断" class="headerlink" title="编写 33号中断"></a>编写 33号中断</h3><p>编写33号中断以实现在屏幕下方显示”OUCH!OUCH!”的功能,然后在用户程序中每次敲击键盘时调用33号中断。判断用户是否敲击键盘,只用调用0x16号中断即可,如下所示:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">int 16h</span><br><span class="line">jz do</span><br><span class="line">int 33</span><br></pre></td></tr></table></figure>
<p>同样,写完之后加上一句:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">set_ivt 33,_int_33</span><br></pre></td></tr></table></figure>
<p>就可以运行了。</p>
<h2 id="实验过程"><a href="#实验过程" class="headerlink" title="实验过程"></a>实验过程</h2><p>编写一个makefile文件,然后就可以在VSCode自带的终端里输入make完成大量的工作。这次的makefile与上次没有任何区别,不再赘述。</p>
<p>用bochs运行,可以看到风火轮的效果:<br><img src="https://i.loli.net/2020/06/12/FhemI2Kxtn9Du7c.png" alt="image-20200529153811786.png"></p>
<p><img src="https://i.loli.net/2020/06/12/B2jz3rXtkOyVm6Q.png" alt="image-20200529153848248.png"></p>
<p>进入用户程序,敲击键盘:</p>
<p><img src="https://i.loli.net/2020/06/12/pKMRmZtx73rEOhP.png" alt="image-20200529153920257.png"></p>
<p>可以看到显示了 ‘OUCH!OUCH!’,并且风火轮还在转动。</p>
<p>提交的文件夹中还附带了一个录屏视频,可以查看。</p>
<h2 id="实验总结"><a href="#实验总结" class="headerlink" title="实验总结"></a>实验总结</h2><p>在完成这次实验过程中遇到的主要困难有:</p>
<ol>
<li><p>编写完0x08号中断后,操作系统运行的时候经常莫名其妙地卡住,无法正常运行。找了半天我也没想明白问题出在哪。于是我只好把BIOS的0x08号中断 “扣” 出来,然后在它上面进行修改,然后就能正常运行了。</p>
</li>
<li><p>本来是打算在显示 “OUCH!OUCH!” 的时候顺便显示系统的时间的,但BOCHS的时间系统似乎比正常的要快很多,导致完全无法显示正常的时间,而用Virtual Box又无法正常执行,于是只能把那一段代码删掉。</p>
<p>总的来说,这次实验算比较简单了,只需要将原有的操作系统内核稍作修改即可。但又十分重要,毕竟操作系统的很多内容都要靠时钟中断来完成。我对这些内容掌握的还不够扎实,以后还要加强。</p>
</li>
</ol>
</div>
<footer class="post-footer">
<div class="post-eof"></div>
</footer>
</article>
<article itemscope itemtype="http://schema.org/Article" class="post-block home" lang="zh-CN">
<link itemprop="mainEntityOfPage" href="http://yoursite.com/2020/06/13/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E5%AE%9E%E9%AA%8C%E5%9B%9B_%E6%96%87%E4%BB%B6%E6%89%93%E5%8C%85%E5%AE%9E%E9%AA%8C/">
<span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
<meta itemprop="image" content="/images/avatar.gif">
<meta itemprop="name" content="reeeeeeeeeein">
<meta itemprop="description" content="SYSU 计算机专业大二在读">
</span>
<span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
<meta itemprop="name" content="reeeeeeeeeein的博客">
</span>
<header class="post-header">
<h1 class="post-title" itemprop="name headline">
<a href="/2020/06/13/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E5%AE%9E%E9%AA%8C%E5%9B%9B_%E6%96%87%E4%BB%B6%E6%89%93%E5%8C%85%E5%AE%9E%E9%AA%8C/" class="post-title-link" itemprop="url">计算机网络实验四_文件打包实验</a>
</h1>
<div class="post-meta">
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="fa fa-calendar-o"></i>
</span>
<span class="post-meta-item-text">发表于</span>
<time title="创建时间:2020-06-13 18:17:49" itemprop="dateCreated datePublished" datetime="2020-06-13T18:17:49+08:00">2020-06-13</time>
</span>
</div>
</header>
<div class="post-body" itemprop="articleBody">
<h1 id="文件打包实验"><a href="#文件打包实验" class="headerlink" title="文件打包实验"></a>文件打包实验</h1><h2 id="实验目的"><a href="#实验目的" class="headerlink" title="实验目的"></a>实验目的</h2><p>掌握文件打包的方法</p>
<h2 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h2><p>C语言字符串函数:<a href="http://msdn.microsoft.com/zh-cn/library/f0151s4x(v=vs.110).aspx" target="_blank" rel="noopener">http://msdn.microsoft.com/zh-cn/library/f0151s4x(v=vs.110).aspx</a><br>C语言程序设计:<a href="http://www.runoob.com/cprogramming/" target="_blank" rel="noopener">http://www.runoob.com/cprogramming/</a><br>C语言函数分类:<a href="http://msdn.microsoft.com/zh-cn/library/2aza74he(v=vs.110).aspx" target="_blank" rel="noopener">http://msdn.microsoft.com/zh-cn/library/2aza74he(v=vs.110).aspx</a></p>
<h2 id="实验环境"><a href="#实验环境" class="headerlink" title="实验环境"></a>实验环境</h2><p>WSL+ gcc</p>
<h2 id="实验内容"><a href="#实验内容" class="headerlink" title="实验内容"></a>实验内容</h2><h3 id="把输入的结构数据保存到文件中"><a href="#把输入的结构数据保存到文件中" class="headerlink" title="把输入的结构数据保存到文件中"></a>把输入的结构数据保存到文件中</h3><h4 id="实验要求"><a href="#实验要求" class="headerlink" title="实验要求"></a>实验要求</h4><p>循环输入员工(Person)的信息,每输入一个员工的信息,立即写入文件(Persons.stru),直到输入的姓名为exit时跳出循环。<br>Person的信息表示:</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">Person</span> {</span></span><br><span class="line"> <span class="keyword">char</span> username[USER_NAME_LEN]; <span class="comment">// 员工名</span></span><br><span class="line"> <span class="keyword">int</span> level; <span class="comment">// 工资级别</span></span><br><span class="line"> <span class="keyword">char</span> email[EMAIL_LEN]; <span class="comment">// email地址</span></span><br><span class="line"> DWORD sendtime; <span class="comment">// 发送时间</span></span><br><span class="line"> <span class="keyword">time_t</span> regtime; <span class="comment">// 注册时间</span></span><br><span class="line">};</span><br></pre></td></tr></table></figure>
<h4 id="完成后截屏运行结果"><a href="#完成后截屏运行结果" class="headerlink" title="完成后截屏运行结果"></a>完成后截屏运行结果</h4><p><img src="https://i.loli.net/2020/06/13/kaM6TqbwDrl2i8K.png" alt="image.png"></p>
<h4 id="源代码"><a href="#源代码" class="headerlink" title="源代码"></a>源代码</h4><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string"><time.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string"><stdio.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string"><stdlib.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string"><string.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string"><sys/stat.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><string.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> USER_NAME_LEN 100</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> EMAIL_LEN 100</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> BUF_LEN 100</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> TIME_BUF_LEN 100</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> PERSON_BUF_LEN 300</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">Person</span>{</span></span><br><span class="line"> <span class="keyword">char</span> userName[USER_NAME_LEN];</span><br><span class="line"> <span class="keyword">int</span> level;</span><br><span class="line"> <span class="keyword">char</span> email[EMAIL_LEN];</span><br><span class="line"> <span class="keyword">long</span> <span class="keyword">long</span> sendtime;</span><br><span class="line"> <span class="keyword">time_t</span> regtime;</span><br><span class="line">}person;</span><br><span class="line"></span><br><span class="line"><span class="keyword">char</span> text_buf[BUF_LEN];</span><br><span class="line"><span class="keyword">int</span> level_buf;</span><br><span class="line"><span class="keyword">char</span> pts[TIME_BUF_LEN];</span><br><span class="line"><span class="keyword">time_t</span> now;</span><br><span class="line"><span class="keyword">char</span> person_buf[PERSON_BUF_LEN];</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">(<span class="keyword">void</span>)</span></span>{</span><br><span class="line"> FILE* file=fopen(<span class="string">"Person.txt"</span>,<span class="string">"wb"</span>);</span><br><span class="line"> <span class="keyword">if</span>(file==<span class="literal">NULL</span>){</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"File open error!\n"</span>);</span><br><span class="line"> <span class="built_in">abort</span>();</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">while</span>(<span class="number">1</span>){</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"name:"</span>);</span><br><span class="line"> <span class="built_in">scanf</span>(<span class="string">"%s"</span>,text_buf);</span><br><span class="line"> <span class="keyword">if</span>(<span class="built_in">strcmp</span>(<span class="string">"exit"</span>,text_buf)==<span class="number">0</span>){</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"Exit input!\n"</span>);</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">strncpy</span>(person.userName,text_buf,USER_NAME_LEN);</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"level:"</span>);</span><br><span class="line"> <span class="built_in">scanf</span>(<span class="string">"%d"</span>,&level_buf);</span><br><span class="line"> person.level=level_buf;</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"email:"</span>);</span><br><span class="line"> <span class="built_in">scanf</span>(<span class="string">"%s"</span>,text_buf);</span><br><span class="line"> <span class="built_in">strncpy</span>(person.email,text_buf,EMAIL_LEN);</span><br><span class="line"> time(&now);</span><br><span class="line"> person.sendtime=(<span class="keyword">long</span> <span class="keyword">long</span>)now;</span><br><span class="line"> person.regtime=now;</span><br><span class="line"> <span class="built_in">memcpy</span>(person_buf,&person,<span class="keyword">sizeof</span>(struct Person));</span><br><span class="line"> <span class="keyword">if</span>(fwrite(person_buf,PERSON_BUF_LEN,<span class="number">1</span>,file)!=<span class="number">1</span>){</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"Write file error!\n"</span>);</span><br><span class="line"> <span class="built_in">abort</span>();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> fclose(file);</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h3 id="从文件读出结构数据并显示出来"><a href="#从文件读出结构数据并显示出来" class="headerlink" title="从文件读出结构数据并显示出来"></a>从文件读出结构数据并显示出来</h3><h4 id="完成后截屏运行结果-1"><a href="#完成后截屏运行结果-1" class="headerlink" title="完成后截屏运行结果"></a>完成后截屏运行结果</h4><p><img src="https://i.loli.net/2020/06/13/FNUq791M6cytlPu.png" alt="image.png"></p>
<h4 id="源代码-1"><a href="#源代码-1" class="headerlink" title="源代码"></a>源代码</h4><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string"><time.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string"><stdio.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string"><stdlib.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string"><string.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string"><sys/stat.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><string.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> USER_NAME_LEN 100</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> EMAIL_LEN 100</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> BUF_LEN 100</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> PERSON_BUF_LEN 300</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">Person</span>{</span></span><br><span class="line"> <span class="keyword">char</span> userName[USER_NAME_LEN];</span><br><span class="line"> <span class="keyword">int</span> level;</span><br><span class="line"> <span class="keyword">char</span> email[EMAIL_LEN];</span><br><span class="line"> <span class="keyword">long</span> <span class="keyword">long</span> sendtime;</span><br><span class="line"> <span class="keyword">time_t</span> regtime;</span><br><span class="line">}person;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">char</span> person_buf[PERSON_BUF_LEN];</span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">(<span class="keyword">void</span>)</span></span>{</span><br><span class="line"></span><br><span class="line"> FILE* file2=fopen(<span class="string">"Person.txt"</span>,<span class="string">"rb"</span>);</span><br><span class="line"> <span class="keyword">while</span>(fread(person_buf,PERSON_BUF_LEN,<span class="number">1</span>,file2)!=<span class="number">0</span>){</span><br><span class="line"><span class="comment">// printf("%s",person_buf);</span></span><br><span class="line"> <span class="built_in">memcpy</span>(&person,person_buf,PERSON_BUF_LEN);</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"姓名:%s 级别:%d 电子邮件:%s 发送时间%s 注册时间%s\n"</span>,person.userName,person.level,person.email,ctime(&person.sendtime),ctime(&person.regtime));</span><br><span class="line"> }</span><br><span class="line"> fclose(file2);</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h3 id="打包文件-FilePack-c"><a href="#打包文件-FilePack-c" class="headerlink" title="打包文件 (FilePack.c)"></a>打包文件 (FilePack.c)</h3><h4 id="实验要求-1"><a href="#实验要求-1" class="headerlink" title="实验要求"></a>实验要求</h4><p>(1) 先输入打包文件名(含路径);<br>(2) 循环输入要打包的文件名(含路径),每输入一个,就把该文件的文件名(最多300字节)、文件大小(long)和文件内容写入文件FileSet.pak中,当输入文件名为exit时跳出循环。<br>当前文件夹下有FilePack和FilePack.c等多个文件<br><img src="https://i.loli.net/2020/06/13/GM4pROQSgc5djvn.png" alt="image.png"></p>
<h4 id="运行程序"><a href="#运行程序" class="headerlink" title="运行程序"></a>运行程序</h4><p><img src="https://i.loli.net/2020/06/13/EtCqsHoPmU91iyQ.png" alt="image.png"><br>生成的dest文件:<br><img src="https://i.loli.net/2020/06/13/owWin5OECPtcKRq.png" alt="image.png"></p>
<h4 id="源代码-2"><a href="#源代码-2" class="headerlink" title="源代码"></a>源代码</h4><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string"><time.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string"><stdio.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string"><stdlib.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string"><string.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string"><sys/stat.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><string.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> BUF_LEN 100</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> PERSON_BUF_LEN 300</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> FILE_NAME_LEN 300</span></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">FileStruct</span> {</span></span><br><span class="line"> <span class="keyword">char</span> fileName[<span class="number">300</span>];</span><br><span class="line"> <span class="keyword">long</span> <span class="keyword">long</span> fileSize;</span><br><span class="line">};</span><br><span class="line"><span class="function"><span class="keyword">long</span> <span class="keyword">long</span> <span class="title">getFileSize</span><span class="params">(<span class="keyword">char</span> * fileName)</span></span>{</span><br><span class="line"> FILE* fp=fopen(fileName,<span class="string">"r"</span>);</span><br><span class="line"> fseek(fp, <span class="number">0</span>, SEEK_END);</span><br><span class="line"> <span class="keyword">size_t</span> <span class="built_in">size</span> = ftell(fp);</span><br><span class="line"> fclose(fp);</span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">size</span>;</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">char</span> * <span class="title">getFileName</span><span class="params">(<span class="keyword">char</span> *pathName)</span></span>{</span><br><span class="line"> <span class="keyword">while</span>(*pathName!=<span class="string">'\0'</span>)pathName++;</span><br><span class="line"> <span class="keyword">while</span>(*pathName!=<span class="string">'/'</span>)pathName--;</span><br><span class="line"> <span class="keyword">return</span> pathName+<span class="number">1</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">char</span> text_buf[BUF_LEN];</span><br><span class="line"><span class="keyword">time_t</span> now;</span><br><span class="line"><span class="keyword">char</span> person_buf[PERSON_BUF_LEN];</span><br><span class="line"><span class="keyword">char</span> file_NAME[FILE_NAME_LEN];</span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">(<span class="keyword">void</span>)</span></span>{</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"输入要目标文件名(含路径):"</span>);</span><br><span class="line"> <span class="built_in">scanf</span>(<span class="string">"%s"</span>,text_buf);</span><br><span class="line"> FILE* file3=fopen(text_buf,<span class="string">"wb"</span>);</span><br><span class="line"> <span class="keyword">int</span> now=<span class="number">0</span>;</span><br><span class="line"> <span class="keyword">while</span>(<span class="number">1</span>){</span><br><span class="line"> now++;</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"输入要打包的#%d文件(含路径):"</span>,now);</span><br><span class="line"> <span class="built_in">scanf</span>(<span class="string">"%s"</span>,text_buf);</span><br><span class="line"> <span class="keyword">if</span>(<span class="built_in">strcmp</span>(text_buf,<span class="string">"exit"</span>)==<span class="number">0</span>){</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"打包结束!\n"</span>);</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">FileStruct</span> <span class="title">f</span>;</span></span><br><span class="line"> f.fileSize=getFileSize(text_buf);</span><br><span class="line"> <span class="built_in">strcpy</span>(f.fileName,getFileName(text_buf));</span><br><span class="line"> <span class="keyword">int</span> a=fwrite(&f,<span class="keyword">sizeof</span>(struct FileStruct),<span class="number">1</span>,file3);</span><br><span class="line"> FILE* tem_file=fopen(text_buf,<span class="string">"r"</span>);</span><br><span class="line"> <span class="keyword">char</span>* content=(<span class="keyword">char</span>*)<span class="built_in">malloc</span>(f.fileSize);</span><br><span class="line"> fread(content,f.fileSize,<span class="number">1</span>,tem_file);</span><br><span class="line"> fclose(tem_file);</span><br><span class="line"> fwrite(content,f.fileSize,<span class="number">1</span>,file3);</span><br><span class="line"> }</span><br><span class="line"> fclose(file3);</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h3 id="解包文件-FileUnpack-c"><a href="#解包文件-FileUnpack-c" class="headerlink" title="解包文件 (FileUnpack.c)"></a>解包文件 (FileUnpack.c)</h3><h4 id="实验要求-2"><a href="#实验要求-2" class="headerlink" title="实验要求"></a>实验要求</h4><p>(1)输入解包路径<br>(2)输入打包文件名,然后解包其中每一个文件,有重名文件时文件名加上序号(从2开始)。</p>
<p>先把几个文件打包进dest文件中,然后解包.</p>
<p>运行结果:<br><img src="https://i.loli.net/2020/06/13/UCjz28hKyHmlagR.png" alt="image.png"><br>new文件夹的内容变为:<br><img src="https://i.loli.net/2020/06/13/PEgrhOMU2NFCVBu.png" alt="image.png"></p>
<p>五个文件均可打开,显示内容正常,字节数与源文件相同:<br><img src="https://i.loli.net/2020/06/13/spHRybxaojB6feG.png" alt="image.png"></p>
<h4 id="源代码-3"><a href="#源代码-3" class="headerlink" title="源代码"></a>源代码</h4><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string"><time.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string"><stdio.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string"><stdlib.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string"><string.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string"><sys/stat.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><string.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> BUF_LEN 100</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> PERSON_BUF_LEN 300</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> FILE_NAME_LEN 300</span></span><br><span class="line"><span class="comment">//#define FILE_CONTENT_LEN 100000</span></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">FileStruct</span> {</span></span><br><span class="line"> <span class="keyword">char</span> fileName[<span class="number">300</span>];</span><br><span class="line"> <span class="keyword">long</span> <span class="keyword">long</span> fileSize;</span><br><span class="line">};</span><br><span class="line"><span class="function"><span class="keyword">long</span> <span class="keyword">long</span> <span class="title">getFileSize</span><span class="params">(<span class="keyword">char</span> * fileName)</span></span>{</span><br><span class="line"> FILE* fp=fopen(fileName,<span class="string">"r"</span>);</span><br><span class="line"> fseek(fp, <span class="number">0</span>, SEEK_END);</span><br><span class="line"> <span class="keyword">size_t</span> <span class="built_in">size</span> = ftell(fp);</span><br><span class="line"> fclose(fp);</span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">size</span>;</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">char</span> * <span class="title">getFileName</span><span class="params">(<span class="keyword">char</span> *pathName)</span></span>{</span><br><span class="line"> <span class="keyword">while</span>(*pathName!=<span class="string">'\0'</span>)pathName++;</span><br><span class="line"> <span class="keyword">while</span>(*pathName!=<span class="string">'/'</span>)pathName--;</span><br><span class="line"> <span class="keyword">return</span> pathName+<span class="number">1</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">Unpack</span><span class="params">(struct FileStruct* fileStruct,<span class="keyword">char</span>* file_content,<span class="keyword">char</span>* folder_name)</span></span>{</span><br><span class="line"> <span class="keyword">char</span>* Full_name[FILE_NAME_LEN];</span><br><span class="line"> <span class="built_in">sprintf</span>(Full_name,<span class="string">"%s/%s"</span>,folder_name,fileStruct->fileName);</span><br><span class="line"><span class="comment">// printf("%s\n",Full_name);</span></span><br><span class="line"> FILE* file=fopen(Full_name,<span class="string">"wb"</span>);</span><br><span class="line"> fwrite(file_content,<span class="keyword">sizeof</span>(<span class="keyword">char</span>),fileStruct->fileSize,file);</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">add_suffix</span><span class="params">(<span class="keyword">char</span>* new_filename,<span class="keyword">int</span> occur_time,<span class="keyword">char</span>* old_filename)</span></span>{</span><br><span class="line"> <span class="keyword">char</span>* tem=old_filename;</span><br><span class="line"> <span class="keyword">while</span>(*tem!=<span class="string">'\0'</span>)tem++;</span><br><span class="line"> <span class="keyword">while</span>(*tem!=<span class="string">'.'</span>&&tem!=old_filename)tem--;</span><br><span class="line"> <span class="keyword">if</span>(tem!=old_filename){</span><br><span class="line"> *tem=<span class="string">'\0'</span>;</span><br><span class="line"> <span class="built_in">sprintf</span>(new_filename,<span class="string">"%s(%d).%s"</span>,old_filename,occur_time,tem+<span class="number">1</span>);</span><br><span class="line"> *tem=<span class="string">'.'</span>;</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span>{</span><br><span class="line"> <span class="built_in">sprintf</span>(new_filename,<span class="string">"%s(%d)"</span>,old_filename,occur_time);</span><br><span class="line"> <span class="keyword">return</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"><span class="keyword">char</span> text_buf[BUF_LEN];</span><br><span class="line"><span class="keyword">char</span> person_buf[PERSON_BUF_LEN];</span><br><span class="line"><span class="keyword">char</span> file_NAME[FILE_NAME_LEN];</span><br><span class="line"><span class="keyword">char</span> dest_folder[FILE_NAME_LEN];</span><br><span class="line"><span class="keyword">char</span>* file_content;</span><br><span class="line"><span class="keyword">char</span> file_names[BUF_LEN][FILE_NAME_LEN];</span><br><span class="line"><span class="keyword">int</span> occur_times[BUF_LEN];</span><br><span class="line"><span class="keyword">int</span> file_name_count=<span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">(<span class="keyword">void</span>)</span></span>{</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"输入要目标文件夹:"</span>);</span><br><span class="line"> <span class="built_in">scanf</span>(<span class="string">"%s"</span>,dest_folder);</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"输入要解压的文件:"</span>);</span><br><span class="line"> <span class="built_in">scanf</span>(<span class="string">"%s"</span>,file_NAME);</span><br><span class="line"> FILE* f=fopen(file_NAME,<span class="string">"rb"</span>);</span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">FileStruct</span> <span class="title">fileStruct</span>;</span></span><br><span class="line"> <span class="keyword">while</span>(fread(&fileStruct,<span class="keyword">sizeof</span>(struct FileStruct),<span class="number">1</span>,f)!=<span class="number">0</span>){</span><br><span class="line"> file_content=(<span class="keyword">char</span>*)<span class="built_in">malloc</span>(fileStruct.fileSize);</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%d"</span>,fileStruct.fileSize);</span><br><span class="line"> fread(file_content,<span class="keyword">sizeof</span>(<span class="keyword">char</span>),fileStruct.fileSize,f);</span><br><span class="line"> <span class="keyword">int</span> ok=<span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">0</span>;i<file_name_count;i++){</span><br><span class="line"> <span class="keyword">if</span>(<span class="built_in">strcmp</span>(file_names[i],fileStruct.fileName)==<span class="number">0</span>){</span><br><span class="line"> occur_times[i]++;</span><br><span class="line"> <span class="keyword">int</span> occur_time=occur_times[i];</span><br><span class="line"> add_suffix(file_NAME,occur_time,fileStruct.fileName);</span><br><span class="line"> <span class="built_in">strcpy</span>(fileStruct.fileName,file_NAME);</span><br><span class="line"> ok=<span class="number">1</span>;</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span>(ok==<span class="number">0</span>){</span><br><span class="line"> <span class="built_in">strcpy</span>(file_names[file_name_count],fileStruct.fileName);</span><br><span class="line"> occur_times[file_name_count++]++;</span><br><span class="line"> }</span><br><span class="line"> Unpack(&fileStruct,file_content,dest_folder);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h3 id="与同学互测并截屏运行结果"><a href="#与同学互测并截屏运行结果" class="headerlink" title="与同学互测并截屏运行结果"></a>与同学互测并截屏运行结果</h3><p>对同学发过来的这个文件进行解包:<br><img src="https://i.loli.net/2020/06/13/v39SGnLaDsRVrKZ.png" alt="image.png"><br>解包正常:<br><img src="https://i.loli.net/2020/06/13/lQrjKA6Xvik7PIe.png" alt="image.png"><br><img src="https://i.loli.net/2020/06/13/PgRAF8jXKC1qyBM.png" alt="image.png"><br>把我的dest文件发给同学后,解包结果如下:<br><img src="https://i.loli.net/2020/06/13/Az5Zb1d6rvpytV4.png" alt="image.png"><br>结果正常,证明不同操作系统的打包文件也可以被互相解包。</p>
<h3 id="实验体会"><a href="#实验体会" class="headerlink" title="实验体会"></a>实验体会</h3><p>这次实验算很简单了,并没有用到计算机网络中的什么知识,唯一比较难的是对文件的读写操作,通过查阅资料也能解决。借着这次实验复习了一下c语言中的各种基础知识,也算是一个不错的收获吧。</p>
</div>
<footer class="post-footer">
<div class="post-eof"></div>
</footer>
</article>
<article itemscope itemtype="http://schema.org/Article" class="post-block home" lang="zh-CN">
<link itemprop="mainEntityOfPage" href="http://yoursite.com/2020/06/13/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E5%AE%9E%E9%AA%8C%E4%B8%89_%E5%BA%94%E7%94%A8%E5%B1%82%E5%AE%9E%E9%AA%8C/">
<span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
<meta itemprop="image" content="/images/avatar.gif">
<meta itemprop="name" content="reeeeeeeeeein">
<meta itemprop="description" content="SYSU 计算机专业大二在读">
</span>
<span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
<meta itemprop="name" content="reeeeeeeeeein的博客">
</span>
<header class="post-header">
<h1 class="post-title" itemprop="name headline">
<a href="/2020/06/13/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E5%AE%9E%E9%AA%8C%E4%B8%89_%E5%BA%94%E7%94%A8%E5%B1%82%E5%AE%9E%E9%AA%8C/" class="post-title-link" itemprop="url">计算机网络实验三_应用层实验</a>
</h1>
<div class="post-meta">
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="fa fa-calendar-o"></i>
</span>
<span class="post-meta-item-text">发表于</span>
<time title="创建时间:2020-06-13 17:59:15" itemprop="dateCreated datePublished" datetime="2020-06-13T17:59:15+08:00">2020-06-13</time>
</span>
</div>
</header>
<div class="post-body" itemprop="articleBody">
<h1 id="应用层实验"><a href="#应用层实验" class="headerlink" title="应用层实验"></a>应用层实验</h1><h2 id="实验目的"><a href="#实验目的" class="headerlink" title="实验目的"></a>实验目的</h2><p>掌握应用层的基本工作原理和实现方法</p>
<h2 id="实验工具"><a href="#实验工具" class="headerlink" title="实验工具"></a>实验工具</h2><p>telnet,WSL</p>
<h2 id="实验内容"><a href="#实验内容" class="headerlink" title="实验内容"></a>实验内容</h2><h3 id="HTTP协议的实验"><a href="#HTTP协议的实验" class="headerlink" title="HTTP协议的实验"></a>HTTP协议的实验</h3><h4 id="从学校网站(www-sysu-edu-cn)找一个网页下载"><a href="#从学校网站(www-sysu-edu-cn)找一个网页下载" class="headerlink" title="从学校网站(www.sysu.edu.cn)找一个网页下载"></a>从学校网站(<a href="http://www.sysu.edu.cn)找一个网页下载" target="_blank" rel="noopener">www.sysu.edu.cn)找一个网页下载</a></h4><p>http请求:</p>
<figure class="highlight http"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">GET</span> <span class="string">/2012/cn/index.htm</span> HTTP/1.1</span><br><span class="line"><span class="attribute">Connection</span>: keep-alive</span><br><span class="line"><span class="attribute">Host</span>: www.sysu.edu.cn</span><br></pre></td></tr></table></figure>
<figure class="highlight http"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">GET</span> <span class="string">/2012/cn/index.htm</span> HTTP/1.1</span><br><span class="line"><span class="attribute">Host</span>: www.sysu.edu.cn</span><br></pre></td></tr></table></figure>
<p>http响应:</p>
<p><img src="https://i.loli.net/2020/06/12/fc8tQs7VDFN2Azb.png" alt="image.png"></p>
<h4 id="从学校网站(www-sysu-edu-cn)找一个图片下载"><a href="#从学校网站(www-sysu-edu-cn)找一个图片下载" class="headerlink" title="从学校网站(www.sysu.edu.cn)找一个图片下载"></a>从学校网站(<a href="http://www.sysu.edu.cn)找一个图片下载" target="_blank" rel="noopener">www.sysu.edu.cn)找一个图片下载</a></h4><p>http请求:</p>
<figure class="highlight http"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">GET</span> <span class="string">/2012/images/content/2020-02/20200202145357635528.jpg</span> HTTP/1.1</span><br><span class="line"><span class="attribute">Host</span>: www.sysu.edu.cn</span><br></pre></td></tr></table></figure>
<p>http响应:<br><img src="https://i.loli.net/2020/06/12/xadvFyCmpj5ZQ1U.png" alt="image.png"></p>
<h4 id="在http请求的头部行中加入If-Modified-Since-Sat-16-May-2020-14-57-17-GMT从学校网站下载-2-的图片"><a href="#在http请求的头部行中加入If-Modified-Since-Sat-16-May-2020-14-57-17-GMT从学校网站下载-2-的图片" class="headerlink" title="在http请求的头部行中加入If-Modified-Since: Sat, 16 May 2020 14:57:17 GMT从学校网站下载(2)的图片"></a>在http请求的头部行中加入If-Modified-Since: Sat, 16 May 2020 14:57:17 GMT从学校网站下载(2)的图片</h4><p>http请求:</p>
<figure class="highlight http"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">GET</span> <span class="string">/2012/images/content/2020-02/20200202145357635528.jpg</span> HTTP/1.1</span><br><span class="line"><span class="attribute">If-Modified-Since</span>: Sat, 16 May 2020 14:57:17 GMT</span><br><span class="line"><span class="attribute">Host</span>: www.sysu.edu.cn</span><br></pre></td></tr></table></figure>
<p>http响应:<br><img src="https://i.loli.net/2020/06/12/FZI987nMwqS1kly.png" alt="image.png"><br>没有修改</p>
<h4 id="用流水线方式实现前面(1)(2),即把它们的请求拷贝到一起后发送出去(可能太长,第一部分可以只有看到末尾)。注意:connection都要是keep-alive"><a href="#用流水线方式实现前面(1)(2),即把它们的请求拷贝到一起后发送出去(可能太长,第一部分可以只有看到末尾)。注意:connection都要是keep-alive" class="headerlink" title="用流水线方式实现前面(1)(2),即把它们的请求拷贝到一起后发送出去(可能太长,第一部分可以只有看到末尾)。注意:connection都要是keep-alive"></a>用流水线方式实现前面(1)(2),即把它们的请求拷贝到一起后发送出去(可能太长,第一部分可以只有看到末尾)。注意:connection都要是keep-alive</h4><p>http请求:</p>
<figure class="highlight http"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">GET</span> <span class="string">/2012/cn/index.htm</span> HTTP/1.1</span><br><span class="line"><span class="attribute">Connection</span>: keep-alive</span><br><span class="line"><span class="attribute">Host</span>: www.sysu.edu.cn</span><br><span class="line"></span><br><span class="line"><span class="keyword">GET</span> <span class="string">/2012/images/content/2020-02/20200202145357635528.jpg</span> HTTP/1.1</span><br><span class="line"><span class="attribute">Connection</span>: keep-alive</span><br><span class="line"><span class="attribute">Host</span>: www.sysu.edu.cn</span><br></pre></td></tr></table></figure>
<p>http响应:</p>
<p><img src="https://i.loli.net/2020/06/12/9HFT6bqkSwU2ZJX.png" alt="image.png"><br><img src="https://i.loli.net/2020/06/12/zgjC4bKplyZfP8d.png" alt="image.png"></p>
<h4 id="用(1)的地址取回网页的一部分-100-200-400"><a href="#用(1)的地址取回网页的一部分-100-200-400" class="headerlink" title="用(1)的地址取回网页的一部分(100-200,400-)"></a>用(1)的地址取回网页的一部分(100-200,400-)</h4><p>http请求:</p>
<figure class="highlight http"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">GET</span> <span class="string">/2012/cn/index.htm</span> HTTP/1.1</span><br><span class="line"><span class="attribute">Connection</span>: keep-alive</span><br><span class="line">Range:bytes=100-200,400-</span><br><span class="line"><span class="attribute">Host</span>: www.sysu.edu.cn</span><br></pre></td></tr></table></figure>
<p>http响应:<br><img src="https://i.loli.net/2020/06/12/rqLnHle6ON9vahC.png" alt="image.png"></p>
<h3 id="FTP协议的实验"><a href="#FTP协议的实验" class="headerlink" title="FTP协议的实验"></a>FTP协议的实验</h3><p>FTP服务器:IP地址为103.26.79.35,端口号为 21 (用户名:net,密码:123456)</p>
<h4 id="上传用学号命名的一个文本文件-学号-txt"><a href="#上传用学号命名的一个文本文件-学号-txt" class="headerlink" title="上传用学号命名的一个文本文件(学号.txt)"></a>上传用学号命名的一个文本文件(学号.txt)</h4><p>控制连接的请求响应信息:<br><img src="https://i.loli.net/2020/06/12/PWFYa3yUe6iAsIp.png" alt="image.png"></p>
<p>数据连接的截屏:<br><img src="https://i.loli.net/2020/06/12/qo5dxYUXb14OncS.png" alt="image.png"></p>
<h4 id="查看当前目录内容-太多则选择一些-,并标注出-1-中自己上传的文件"><a href="#查看当前目录内容-太多则选择一些-,并标注出-1-中自己上传的文件" class="headerlink" title="查看当前目录内容(太多则选择一些),并标注出(1)中自己上传的文件"></a>查看当前目录内容(太多则选择一些),并标注出(1)中自己上传的文件</h4><p>控制连接的请求响应信息:<br><img src="https://i.loli.net/2020/06/12/NlTCaqWweoUxYP9.png" alt="image.png"><br>数据连接的截屏:<br><img src="https://i.loli.net/2020/06/12/6cigMTpH9Yf8ZGz.png" alt="image.png"></p>
<h4 id="下载-1-中自己上传的文本文件"><a href="#下载-1-中自己上传的文本文件" class="headerlink" title="下载(1)中自己上传的文本文件"></a>下载(1)中自己上传的文本文件</h4><p>控制连接的请求响应信息:<br><img src="https://i.loli.net/2020/06/12/mpTiJE269bklfB3.png" alt="image.png"><br>数据连接的截屏:<br><img src="https://i.loli.net/2020/06/12/1HvXrUNtFSlw5kn.png" alt="image.png"></p>
<h4 id="下载-ebook下的一个二进制文件-例如,-pdf文件"><a href="#下载-ebook下的一个二进制文件-例如,-pdf文件" class="headerlink" title="下载/ebook下的一个二进制文件(例如,.pdf文件)"></a>下载/ebook下的一个二进制文件(例如,.pdf文件)</h4><p>控制连接的请求响应信息:<br><img src="https://i.loli.net/2020/06/12/FuVImgrxpcSaWRn.png" alt="image.png"><br>数据连接的截屏:<br><img src="https://i.loli.net/2020/06/12/DrEndlhq8gpuxKm.png" alt="image.png"></p>
<h4 id="采用断点续传下载一个-text下的一个文本文件的一部分"><a href="#采用断点续传下载一个-text下的一个文本文件的一部分" class="headerlink" title="采用断点续传下载一个/text下的一个文本文件的一部分"></a>采用断点续传下载一个/text下的一个文本文件的一部分</h4><p>控制连接的请求响应信息:<br><img src="https://i.loli.net/2020/06/12/U4q9VatxmWEXpZR.png" alt="image.png"><br>数据连接的截屏:<br><img src="https://i.loli.net/2020/06/12/Y96GhpoX2aHBTkC.png" alt="image.png"></p>
<h4 id="分两次上传一个文本文件-(使用APPE命令)"><a href="#分两次上传一个文本文件-(使用APPE命令)" class="headerlink" title="分两次上传一个文本文件 (使用APPE命令)"></a>分两次上传一个文本文件 (使用APPE命令)</h4><p>控制连接的请求响应信息:<br><img src="https://i.loli.net/2020/06/12/n7pk4x8IoPFDuq2.png" alt="image.png"></p>
<p>第一次数据连接的截屏<br> <img src="https://i.loli.net/2020/06/12/CB4MkDntdXWKo1w.png" alt="image.png"><br>第一次ftp目录的截屏(包含上传文件):<br> <img src="https://i.loli.net/2020/06/12/VjeiDKMav8R4nqU.png" alt="image.png"><br>第二次数据连接的截屏<br> <img src="https://i.loli.net/2020/06/12/BZvNxW2V8JLkMeg.png" alt="image.png"><br>第二次ftp目录的截屏(包含上传文件):<br> <img src="https://i.loli.net/2020/06/12/a6LcYAVPBD28zm1.png" alt="image.png"><br>修改时间改变了。</p>
<h3 id="SMTP协议的实验"><a href="#SMTP协议的实验" class="headerlink" title="SMTP协议的实验"></a>SMTP协议的实验</h3><h4 id="通过我的QQ邮箱发一封没有附件的邮件到我的中大邮箱"><a href="#通过我的QQ邮箱发一封没有附件的邮件到我的中大邮箱" class="headerlink" title="通过我的QQ邮箱发一封没有附件的邮件到我的中大邮箱"></a>通过我的QQ邮箱发一封没有附件的邮件到我的中大邮箱</h4><p>请求和响应信息:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">HELO 1347453756</span><br><span class="line">AUTH LOGIN</span><br><span class="line">*******</span><br><span class="line">*******</span><br><span class="line">MAIL FROM:<1347453756@qq.com></span><br><span class="line">RCPT TO:<zhangjr35@mail2.sysu.edu.cn></span><br><span class="line">data</span><br><span class="line">Date:Sat, 16 May 2020 21:52:50 +0800</span><br><span class="line">From: "1347453756" <1347453756@qq.com></span><br><span class="line">To: "zhangjr35"<zhangjr35@sysu.edu.cn></span><br><span class="line">Subject: I am zjr</span><br><span class="line">This a mail from zjr to zjr</span><br><span class="line">.</span><br><span class="line">QUIT</span><br></pre></td></tr></table></figure>
<p><img src="https://i.loli.net/2020/06/12/rQmARxzFNJK1sPn.png" alt="image.png"><br>打开中大邮箱,发现确实可以收到:<br><img src="https://i.loli.net/2020/06/12/RvhTS1JioGKjP9w.png" alt="image.png"></p>
<h4 id="通过我的QQ邮箱发一封带附件-二进制文件-的邮件-MIME-txt-到我的中大邮箱"><a href="#通过我的QQ邮箱发一封带附件-二进制文件-的邮件-MIME-txt-到我的中大邮箱" class="headerlink" title="通过我的QQ邮箱发一封带附件(二进制文件)的邮件(MIME.txt)到我的中大邮箱"></a>通过我的QQ邮箱发一封带附件(二进制文件)的邮件(MIME.txt)到我的中大邮箱</h4><p>请求和响应信息:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">HELO 1347453756</span><br><span class="line">AUTH LOGIN</span><br><span class="line">******</span><br><span class="line">******</span><br><span class="line">MAIL FROM:<1347453756@qq.com></span><br><span class="line">RCPT TO:<zhangjr35@mail2.sysu.edu.cn></span><br></pre></td></tr></table></figure>
<p>邮件内容:<br><img src="https://i.loli.net/2020/06/13/F4IDPiYUErxkmJy.png" alt="image.png"><br>收到结果:<br><img src="https://i.loli.net/2020/06/13/UwXPdqLKjSC2nhR.png" alt="image.png"></p>
<h4 id="通过中大邮箱发送另一个带附件的邮件给QQ邮箱。可以先给你自己发一封带附件的邮件-再通过查看源码截取该响应报文的一部分,参见MIME-txt"><a href="#通过中大邮箱发送另一个带附件的邮件给QQ邮箱。可以先给你自己发一封带附件的邮件-再通过查看源码截取该响应报文的一部分,参见MIME-txt" class="headerlink" title="通过中大邮箱发送另一个带附件的邮件给QQ邮箱。可以先给你自己发一封带附件的邮件,再通过查看源码截取该响应报文的一部分,参见MIME.txt"></a>通过中大邮箱发送另一个带附件的邮件给QQ邮箱。可以先给你自己发一封带附件的邮件,再通过查看源码截取该响应报文的一部分,参见MIME.txt</h4><p>找了半天也没有找到查看源码的地方在哪。。。。。。只能放弃了。</p>
<h4 id="从你的邮箱发一份邮件到同学的邮箱"><a href="#从你的邮箱发一份邮件到同学的邮箱" class="headerlink" title="从你的邮箱发一份邮件到同学的邮箱"></a>从你的邮箱发一份邮件到同学的邮箱</h4><p>请求和响应信息:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">HELO 1347453756</span><br><span class="line">AUTH LOGIN</span><br><span class="line">******</span><br><span class="line">******</span><br><span class="line">MAIL FROM:<1347453756@qq.com></span><br><span class="line">RCPT TO:zhanghb55@mail2.sysu.edu.cn</span><br></pre></td></tr></table></figure>
<p>邮件内容:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line">data</span><br><span class="line">Date: Thu, 17 Apr 2014 20:30:07 +0800</span><br><span class="line">From: =?utf-8?B?zjr?= <1347453756@qq.com></span><br><span class="line">To: zhanghb55 <zhanghb55@mail2.sysu.edu.cn></span><br><span class="line">Subject: hbnb</span><br><span class="line">Mime-Version: 1.0</span><br><span class="line">Content-Type: multipart/mixed;</span><br><span class="line"> boundary="----=_001_NextPart061116676577_=----"</span><br><span class="line"></span><br><span class="line">This is a multi-part message in MIME format.</span><br><span class="line"></span><br><span class="line">------=_001_NextPart061116676577_=----</span><br><span class="line">Content-Type: multipart/alternative;</span><br><span class="line"> boundary="----=_002_NextPart640832068374_=----"</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">------=_002_NextPart640832068374_=----</span><br><span class="line">Content-Type: text/plain;charset="GB2312"</span><br><span class="line">Content-Transfer-Encoding: base64</span><br><span class="line"></span><br><span class="line">aGJuYmhibmI=</span><br><span class="line"></span><br><span class="line">------=_002_NextPart640832068374_=------</span><br><span class="line"></span><br><span class="line">------=_001_NextPart061116676577_=------</span><br><span class="line">.</span><br></pre></td></tr></table></figure>
<p>实验结果:<br><img src="https://i.loli.net/2020/06/13/WALJP5sdqBV6UGN.png" alt="image.png"><br>好像时间不对。。。为了避免麻烦同学就没改了。</p>
<h3 id="POP3协议"><a href="#POP3协议" class="headerlink" title="POP3协议"></a>POP3协议</h3><h4 id="查看我的QQ邮箱中每个邮件大小"><a href="#查看我的QQ邮箱中每个邮件大小" class="headerlink" title="查看我的QQ邮箱中每个邮件大小"></a>查看我的QQ邮箱中每个邮件大小</h4><p>请求和响应信息:<br><img src="https://i.loli.net/2020/06/13/PaQbJpXNz4CHEqF.png" alt="image.png"></p>
<h4 id="取回我的QQ邮箱的最后一封邮件的邮件唯一标识符"><a href="#取回我的QQ邮箱的最后一封邮件的邮件唯一标识符" class="headerlink" title="取回我的QQ邮箱的最后一封邮件的邮件唯一标识符"></a>取回我的QQ邮箱的最后一封邮件的邮件唯一标识符</h4><p>请求和响应信息:<br>用 UIDL 命令即可<br> <img src="https://i.loli.net/2020/06/13/TBsv5m1RZiCpVO9.png" alt="image.png"></p>
<h4 id="取回zsureceiver5-sina-com最后一封邮件"><a href="#取回zsureceiver5-sina-com最后一封邮件" class="headerlink" title="取回zsureceiver5@sina.com最后一封邮件"></a>取回<a href="mailto:zsureceiver5@sina.com">zsureceiver5@sina.com</a>最后一封邮件</h4><p>请求和响应信息:<br>用RETR命令即可<br> <img src="https://i.loli.net/2020/06/13/krUMFTZn6vVHDez.png" alt="image.png"></p>
<h4 id="取回三-1-中发到你邮箱的邮件"><a href="#取回三-1-中发到你邮箱的邮件" class="headerlink" title="取回三(1)中发到你邮箱的邮件"></a>取回三(1)中发到你邮箱的邮件</h4><p>请求和响应信息:<br>先用list命令看一下有多少封,取出最后一封即可。<br><img src="https://i.loli.net/2020/06/13/ujNOFE6DytKpcZz.png" alt="image.png"></p>
<p>五、mytelent源代码</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* client2.c */</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string"><netdb.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string"><stdlib.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><sys/types.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><sys/socket.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><stdio.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><netinet/in.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><arpa/inet.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><unistd.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><string.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><error.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><pthread.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> BUFLEN 20000 <span class="comment">// 缓冲区大小</span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">input</span><span class="params">(<span class="keyword">char</span>* buf)</span></span>{</span><br><span class="line"> fgets(buf,BUFLEN,<span class="built_in">stdin</span>);</span><br><span class="line"> <span class="keyword">int</span> len=<span class="built_in">strlen</span>(buf);</span><br><span class="line"> buf[len<span class="number">-1</span>]=<span class="string">'\r'</span>,buf[len]=<span class="string">'\n'</span>,buf[++len]=<span class="string">'\0'</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span>* <span class="title">client_recv</span><span class="params">(<span class="keyword">void</span>* in)</span></span>{</span><br><span class="line"> <span class="keyword">int</span> my_sock=(<span class="keyword">long</span>)in;</span><br><span class="line"> <span class="keyword">char</span>* buf=(<span class="keyword">char</span>*)<span class="built_in">malloc</span>((BUFLEN+<span class="number">1</span>)*<span class="keyword">sizeof</span>(<span class="keyword">char</span>));</span><br><span class="line"> <span class="keyword">while</span>(<span class="number">1</span>){</span><br><span class="line"> <span class="keyword">int</span> c1=recv(my_sock,buf,BUFSIZ,<span class="number">0</span>);</span><br><span class="line"> <span class="keyword">if</span>(c1==<span class="number">0</span>){</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">NULL</span>;</span><br><span class="line"> }</span><br><span class="line"> buf[c1]=<span class="string">'\0'</span>;</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%s\n"</span>,buf);</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="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">(<span class="keyword">int</span> argc,<span class="keyword">char</span>* argv[])</span></span>{</span><br><span class="line"> <span class="keyword">char</span>* ptr,**pptr;</span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">hostent</span>* <span class="title">hptr</span>;</span></span><br><span class="line"> <span class="keyword">char</span> str[<span class="number">32</span>];</span><br><span class="line"> ptr=argv[<span class="number">1</span>];</span><br><span class="line"> <span class="keyword">if</span>((hptr=gethostbyname(ptr))==<span class="literal">NULL</span>){</span><br><span class="line"> perror(<span class="string">"gethostbyname"</span>);</span><br><span class="line"> <span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line"> }</span><br><span class="line"> pptr=hptr->h_addr_list;</span><br><span class="line"> <span class="keyword">const</span> <span class="keyword">char</span>* host=inet_ntop(hptr->h_addrtype,*pptr,str,<span class="keyword">sizeof</span>(str));</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%s"</span>,host);</span><br><span class="line"> <span class="keyword">char</span> *service = argv[<span class="number">2</span>]; <span class="comment">/* server port to connect */</span></span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">sockaddr_in</span> <span class="title">sin</span>;</span> <span class="comment">/* an Internet endpoint address */</span></span><br><span class="line"> <span class="keyword">char</span> buf[BUFLEN+<span class="number">1</span>]; <span class="comment">/* buffer for one line of text */</span></span><br><span class="line"> <span class="keyword">int</span> sock; <span class="comment">/* socket descriptor */</span></span><br><span class="line"> <span class="keyword">int</span> cc; <span class="comment">/* recv character count */</span></span><br><span class="line"> <span class="keyword">pthread_t</span> thread_handle;</span><br><span class="line"> sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); <span class="comment">//创建套接字,参数:因特网协议簇(family),流套接字,TCP协议</span></span><br><span class="line"> <span class="comment">//返回:要监听套接字的描述符或INVALID_SOCKET</span></span><br><span class="line"> <span class="built_in">memset</span>(&<span class="built_in">sin</span>, <span class="number">0</span>, <span class="keyword">sizeof</span>(<span class="built_in">sin</span>)); <span class="comment">// 从&sin开始的长度为sizeof(sin)的内存清0</span></span><br><span class="line"> <span class="built_in">sin</span>.sin_family = AF_INET; <span class="comment">// 因特网地址簇</span></span><br><span class="line"> <span class="built_in">sin</span>.sin_addr.s_addr = inet_addr(host);</span><br><span class="line"><span class="comment">// printf("%d\n",sin.sin_addr.s_addr); // 设置服务器IP地址(32位)</span></span><br><span class="line"> <span class="built_in">sin</span>.sin_port = htons((<span class="keyword">unsigned</span> short)atoi(service)); <span class="comment">// 设置服务器端口号</span></span><br><span class="line"> <span class="keyword">int</span> ret=<span class="built_in">connect</span>(sock, (struct sockaddr *)&<span class="built_in">sin</span>, <span class="keyword">sizeof</span>(<span class="built_in">sin</span>)); <span class="comment">// 连接到服务器,第二个参数指向存放服务器地址的结构,第三个参数为该结构的大小,返回值为0时表示无错误发生,</span></span><br><span class="line"> pthread_create(&thread_handle,<span class="literal">NULL</span>,client_recv,(<span class="keyword">void</span>*)sock);</span><br><span class="line"> <span class="keyword">while</span>(<span class="number">1</span>){</span><br><span class="line"> input(buf);</span><br><span class="line"> <span class="keyword">if</span>(<span class="built_in">strcmp</span>(buf,<span class="string">"exit"</span>)==<span class="number">0</span>){</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"退出成功!\n"</span>);</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">int</span> c1=send(sock,buf,<span class="built_in">strlen</span>(buf),<span class="number">0</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="built_in">close</span>(sock); <span class="comment">// 关闭监听套接字</span></span><br><span class="line"></span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"按回车键继续..."</span>);</span><br><span class="line"> getchar(); <span class="comment">// 等待任意按键</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h3 id="实验体会"><a href="#实验体会" class="headerlink" title="实验体会"></a>实验体会</h3><p>这次实验内容很多,我花了很长时间才完成。遇到的困难主要有:<br>1.windows系统下Telnet用不了,并不清楚为什么。折腾了一番之后只能在wsl(一个能在windows下跑的linux子系统)下用telnet。不过后来看到实验要自己写一个telnet,就又写了一个。<br>2.在写Telnet的过程中也遇到了很多问题,一个是不知道怎么把域名转为ip地址,后来在一篇博客上找到了相关的函数。第二个问题是连接网页的时候总是报 400 错误,找了半天发现是回车符的问题,把所有的\n改为\r\n后就解决了。其他的部分就简单了,我一开始以为要写很久,后来发现只要把实验二的客户端代码改一下就完成了。<br>3.对MIME格式文件不是很熟悉,看了很久才看明白(可能是上课听讲不认真)。<br>总的来说这次实验还是很有价值的,一方面锻炼了编程能力,另一方面也学到了很多应用层的相关知识,期待下一个实验的到来。</p>
</div>
<footer class="post-footer">
<div class="post-eof"></div>
</footer>
</article>
<article itemscope itemtype="http://schema.org/Article" class="post-block home" lang="zh-CN">
<link itemprop="mainEntityOfPage" href="http://yoursite.com/2020/06/06/%E6%97%B6%E9%97%B4%E5%BA%8F%E5%88%97%E7%9B%B8%E4%BC%BC%E5%BA%A6/">
<span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
<meta itemprop="image" content="/images/avatar.gif">
<meta itemprop="name" content="reeeeeeeeeein">
<meta itemprop="description" content="SYSU 计算机专业大二在读">
</span>
<span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
<meta itemprop="name" content="reeeeeeeeeein的博客">
</span>
<header class="post-header">
<h1 class="post-title" itemprop="name headline">
<a href="/2020/06/06/%E6%97%B6%E9%97%B4%E5%BA%8F%E5%88%97%E7%9B%B8%E4%BC%BC%E5%BA%A6/" class="post-title-link" itemprop="url">时间序列相似度</a>
</h1>
<div class="post-meta">
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="fa fa-calendar-o"></i>
</span>
<span class="post-meta-item-text">发表于</span>
<time title="创建时间:2020-06-06 21:55:02" itemprop="dateCreated datePublished" datetime="2020-06-06T21:55:02+08:00">2020-06-06</time>
</span>
</div>
</header>
<div class="post-body" itemprop="articleBody">
<h1 id="时间序列相似度度量标准实现"><a href="#时间序列相似度度量标准实现" class="headerlink" title="时间序列相似度度量标准实现"></a>时间序列相似度度量标准实现</h1><h2 id="预备知识:样本相似度度量标准"><a href="#预备知识:样本相似度度量标准" class="headerlink" title="预备知识:样本相似度度量标准"></a>预备知识:样本相似度度量标准</h2><h3 id="基础类型"><a href="#基础类型" class="headerlink" title="基础类型"></a>基础类型</h3><h4 id="距离型"><a href="#距离型" class="headerlink" title="距离型"></a>距离型</h4><p>以差值为基础的相似度计算方法,通常值越小越相似。</p>
<h5 id="例子1:-欧式距离"><a href="#例子1:-欧式距离" class="headerlink" title="例子1: 欧式距离"></a>例子1: 欧式距离</h5><p>假设时间序列 $X={x_1,x_2……x_n},Y={y_1,y_2……y_n}$,则可以定义它们之间的欧式距离:</p>
<p>$d_{L^p}=(\sum\limits_{k=1}^{n}\left\vert x_k-y_k \right\vert^p)^{\frac 1p}$</p>
<p>当 $p=1$ 时,距离为 $d_{L^1}=(\sum\limits_{k=1}^{n}\left\vert x_k-y_k \right\vert)$,也称为曼哈顿距离。</p>
<p>当 $p=2$ 时,距离为 $d_{L^2}=(\sum\limits_{k=1}^{n}\left\vert x_k-y_k \right\vert^2)^{\frac 12}$,也称为欧几里得距离</p>
<p>当 $p\rightarrow \infin$ 时,距离为 $d_{L^\infin}=\max\limits_{1\le k \le n}\left\vert x_k-y_k \right\vert$</p>
<h5 id="例子2:马氏距离(可以看成欧式距离使用协方差矩阵达成的标准化形式)"><a href="#例子2:马氏距离(可以看成欧式距离使用协方差矩阵达成的标准化形式)" class="headerlink" title="例子2:马氏距离(可以看成欧式距离使用协方差矩阵达成的标准化形式)"></a>例子2:马氏距离(可以看成欧式距离使用协方差矩阵达成的标准化形式)</h5><p>两个向量的马氏距离为:</p>
<p>$$d(\vec x,\vec y)=\sqrt{(\vec x-\vec y)^{T}\sum^{-1}(\vec x-\vec y)}$$</p>
<p>其中,$\sum$ 为 $\vec x$ 和 $\vec y$ 的协方差矩阵。</p>
<p>为什么要用马氏距离?欧式距离不行吗?考虑下面这个例子:</p>
<p><img src="https://i.loli.net/2020/06/06/3b2wpQVOKTmXFaG.png" alt="image-20200602210843484.png"></p>
<p>上图中,红圆圈是数据点的均值,绿色的×和红色的×到均值的欧式距离是相等的,但我们可以明显地看到,绿色的×应该属于这个分布,红色的×不属于。这是因为</p>
<ol>
<li><p>不同维度(x轴,y轴)之间存在相关性(在这里表现为x轴与y轴存在正相关)。</p>
</li>
<li><p>不同方向上变化幅度不同,把图顺时针旋转45度,可以看到横向上变化较大,竖向上变化较小(有些资料把这一点称为量纲不同和方差不同)。</p>
</li>
</ol>
<p>用马氏距离就可以消除这种差别,它相当于把欧式距离进行了标准化。</p>
<h4 id="夹角型"><a href="#夹角型" class="headerlink" title="夹角型"></a>夹角型</h4><p>以乘积为基础的相似度计算方法,通常值越大越相似。可以通过取相反数达成值越小越相似。</p>
<h5 id="例子1:夹角余弦"><a href="#例子1:夹角余弦" class="headerlink" title="例子1:夹角余弦"></a>例子1:夹角余弦</h5><p>假设时间序列 $X={x_1,x_2……x_n},Y={y_1,y_2……y_n}$,则可以定义它们之间的夹角 $\theta$ 满足:</p>
<p>$cos\theta=\frac{\sum\limits_{k=1}^{n}x_k<em>y_k}{\sqrt{\sum\limits_{k=1}^{n}x_k^2}</em>\sqrt{\sum\limits_{k=1}^{n}y_k^2}}$</p>
<h5 id="例子2:相关系数(其实也可以看成夹角余弦通过每个特征减均值达成的标准化形式)"><a href="#例子2:相关系数(其实也可以看成夹角余弦通过每个特征减均值达成的标准化形式)" class="headerlink" title="例子2:相关系数(其实也可以看成夹角余弦通过每个特征减均值达成的标准化形式)"></a>例子2:相关系数(其实也可以看成夹角余弦通过每个特征减均值达成的标准化形式)</h5><p>假设时间序列 $X={x_1,x_2……x_n},Y={y_1,y_2……y_n}$,则可以定义它们之间的Pearson相关系数 $cor(X,Y)$ 满足:</p>
<p>$cor(X,Y)=\frac{\sum\limits_{k=1}^{n}(x_k-\bar x)<em>(y_k-\bar y)}{\sqrt{\sum\limits_{k=1}^{n}(x_k-\bar x)^2}</em>\sqrt{\sum\limits_{k=1}^{n}(x_k-\bar x)^2}}$</p>
<h2 id="针对特殊结构数据"><a href="#针对特殊结构数据" class="headerlink" title="针对特殊结构数据"></a>针对特殊结构数据</h2><h3 id="时间序列"><a href="#时间序列" class="headerlink" title="时间序列"></a>时间序列</h3><p>核心需要:对齐</p>
<p>什么是对齐:样本特征的互相配对。</p>
<p>为什么要对齐:样本的相似度是根据样本特征的相似度累加/平均的,结构化数据的特征直接对齐了,但时间序列的每一时刻值可能没有天然强对齐关系。</p>
<p>得到样本相似度度量的实际处理:不同对齐策略下的相似度度量最值</p>
<p>不同对齐策略指对对齐的搜索空间的不同约束,搜索空间的大小会导致不同的复杂度。</p>
<p>时间序列对齐策略的潜在需求:</p>
<p>保序性(单调性):例如T1:a, b, c; T2:x, y, z,无论怎么配对,T1配对出的匹配序列T2‘顺序满足y不会在x前面,z不会再x,y前面。</p>
<h4 id="保端点型对齐策略"><a href="#保端点型对齐策略" class="headerlink" title="保端点型对齐策略"></a>保端点型对齐策略</h4><p>可以一对多,需要全部点(时间序列各个时刻的值)都找到配对(从而开始点一定配对开始点,结束点一定配对结束点,也满足连续性)</p>
<p>比较适合的场景:语音相似度识别</p>
<h5 id="典型例子:DTW(-Dynamic-Time-Warping,动态时间规整):保端点型对齐策略下的距离型度量"><a href="#典型例子:DTW(-Dynamic-Time-Warping,动态时间规整):保端点型对齐策略下的距离型度量" class="headerlink" title="典型例子:DTW([Dynamic Time Warping,动态时间规整):保端点型对齐策略下的距离型度量"></a>典型例子:DTW([Dynamic Time Warping,动态时间规整):保端点型对齐策略下的距离型度量</h5><p><img src="https://pic4.zhimg.com/v2-343ad369c65bd575f40d17f10ae523ef_b.jpg" alt="img"></p>
<p>上图就是DTW对齐策略的一个例子。</p>
<p>最基本的DTW可以用动态规划(dp)来实现。具体的,假设时间序列 $X={x_1,x_2……x_m},Y={y_1,y_2……y_n}$ ,用 $dp[i][j] ,i\le m,j\le n$ 来表示 $X$ 的前 $i$ 个点和 $Y$ 的前 $j$ 个点能取得的最小距离,定义状态转移方程为:</p>
<p> $$dp[i][j]=\begin{cases} dist(1,1),i=1,j=1 \ dp[i-1][j]+dist(i,1),i>1,j=1 \ dp[i][j-1]+dist(1,j),i=1,j>1\min(dp[i-1][j-1],dp[i][j-1],dp[i-1][j-1])+dist(i,j),i>1,j>1 \end{cases}$$</p>
<p>其中 $dist(i,j)=(X[i]-Y[j])^2$ 。</p>
<p>为了将结果可视化,可以将距离矩阵(即 dist )绘制出来,如 $X=[3,6,8],Y=[2,4,8,7]$ 时,距离矩阵如下所示:</p>
<p><img src="https://i.loli.net/2020/06/06/7BRvN3TzMlkayhE.png" alt="image-20200604221146644.png"></p>
<p>要达到一个最小距离,相当于从左上角走到右下角,且每次只允许往右、往下或者往右下走,使得走过的数字的和最小。显然在这个图里应该这样走:</p>
<p><img src="https://i.loli.net/2020/06/06/TBKFsEo1PH26Cqk.png" alt="image-20200604221539941.png"></p>
<h6 id="DTW的优点"><a href="#DTW的优点" class="headerlink" title="DTW的优点"></a>DTW的优点</h6><p>DTW能处理长度不同的时间序列,这是它比传统的距离算法强的地方。而且对很多时间序列,用DTW进行距离计算明显更合理。</p>
<h6 id="DTW的缺点"><a href="#DTW的缺点" class="headerlink" title="DTW的缺点"></a>DTW的缺点</h6><p>用距离来度量相似度的算法的时间复杂度是 $O(n)$ ,空间复杂度是 $O(1)$ 的 ,而DTW算法在时间和空间上都是 $O(nm)$ 的。对于较长的时间序列,直接进行计算显然开销太大,于是要引进一些优化的方法。</p>
<p>以下的变种是基于缩减搜索空间得到的变种。</p>
<h5 id="DTW变种1:greedy-DTW"><a href="#DTW变种1:greedy-DTW" class="headerlink" title="DTW变种1:greedy-DTW"></a>DTW变种1:greedy-DTW</h5><p>来自论文《Time2Graph: Revisiting Time Series Modeling with Dynamic Shapelets》的附录A.1的Algorithm 5</p>
<p>这种算法是用贪心的思想,即每次选择所有能走的点里代价最小的点。为了避免出现沿着边缘走的情况,设置一个窗口 $w$ ,规定走到的位置 $x,y$ 满足 $|x-y|\le w$ 。比如说,对时间序列 $X=[2,3,5,7,1],Y=[4,2,8,6,4]$,dist矩阵和走过的路线是这样子的:</p>
<p><img src="https://i.loli.net/2020/06/06/jBuzlAnGoPLRsEt.png" alt="image-20200605171339497.png"> </p>
<h6 id="greedy-DTW的优点"><a href="#greedy-DTW的优点" class="headerlink" title="greedy-DTW的优点"></a>greedy-DTW的优点</h6><p>它最大的优点是速度快,只需要 $O(n+m)$ 的时间复杂度就可以完成计算。</p>
<h6 id="greedy-DTW的缺点"><a href="#greedy-DTW的缺点" class="headerlink" title="greedy-DTW的缺点"></a>greedy-DTW的缺点</h6><p>缺点也很明显,贪心算法无法保证取得全局最优解,容易”误入歧途”。</p>
<h5 id="DTW变种2:Fast-DTW"><a href="#DTW变种2:Fast-DTW" class="headerlink" title="DTW变种2:Fast-DTW"></a>DTW变种2:Fast-DTW</h5><p>来自论文《FastDTW: Toward Accurate Dynamic Time Warping in Linear Time and Space》</p>
<p>可参考<a href="https://www.cnblogs.com/kemaswill/archive/2013/04/18/3029078.html" target="_blank" rel="noopener">https://www.cnblogs.com/kemaswill/archive/2013/04/18/3029078.html</a></p>
<p>这种方法的基本策略是递归。FastDTW 算法如下:</p>
<p>对于两个时间序列 $X=[1,2,3,4],Y=[3,4,5,6]$,首先将它们的长度缩短为一半,变成 $X’=[1.5,3.5],Y’=[3.5,5.5]$ ,相对应的,矩阵从 4×4 变成了 2×2,如下图所示:</p>
<p><img src="https://i.loli.net/2020/06/06/2DJK9mwILQdhzRv.png" alt="image-20200606011018301.png"></p>
<p>然后,对压缩后的时间序列递归地应用 FastDTW找到一条路径(由于这里的时间序列长度只有2,就可以直接找到不用递归),如下所示:</p>
<p><img src="https://i.loli.net/2020/06/06/PZmMsNckqW7uLiw.png" alt="image-20200606011233288.png"></p>
<p>在原来的矩阵中给这条路径经过的块打上标记,如下所示:</p>
<p><img src="https://i.loli.net/2020/06/06/D5UwZMiRAbcaQKo.png" alt="image-20200606011749696.png"></p>
<p>为了增大搜索范围,对路径以 $r$ 为半径拓展,即将与路径的距离小于等于 $r$ 的路径打上标记。$r=1$ 时,如下所示:</p>
<p><img src="https://i.loli.net/2020/06/06/gxuzD853QrbXlkT.png" alt="image-20200606012002821.png"></p>
<p>这样,就得到了我们的搜索路径,然后只用在这条路径里找就可以了。看起来,搜索路径并不比原来的矩阵小多少,但当时间序列长度足够大时,搜索路径会很小,因为它是 $O(n*r)$ 的,证明略。</p>
<h6 id="Fast-DTW的优点"><a href="#Fast-DTW的优点" class="headerlink" title="Fast-DTW的优点"></a>Fast-DTW的优点</h6><p>最大的优点显然是速度快,如下图所示(顺便吐槽一句,04年的时候执行一个 $n=1000$ 的 $O(n^2)$ 算法竟然要0.92秒,而今天的计算机可能不用0.01秒,看来计算机领域的发展还是很快的):</p>
<p><img src="https://i.loli.net/2020/06/06/J91Eogx3DBsAKqh.png" alt="image-20200606012512919.png"></p>
<p><img src="https://i.loli.net/2020/06/06/Dz9jpLuveJbEXVK.png" alt="image-20200606012619988.png"></p>
<p>对于 $N=1000$ 左右的时间序列,用 $r=20$ 的 Fast-DTW 会比 DTW 快了 4-5倍。当 $N$ 不断增大时,加速效果还会更明显。</p>
<h6 id="Fast-DTW的缺点"><a href="#Fast-DTW的缺点" class="headerlink" title="Fast-DTW的缺点"></a>Fast-DTW的缺点</h6><p>由于这种方法得到的是较优解,因此我们有必要关注它的误差。定义误差如下所示:</p>
<p><img src="https://i.loli.net/2020/06/06/6OEouycJ5bAe72W.png" alt="image-20200606013024726.png"></p>
<p>经过试验得到误差大小:</p>
<p><img src="https://i.loli.net/2020/06/06/DsCXq1VcRS74I9a.png" alt="image-20200606013005315.png"></p>
<p>可以看到,当 $r=20$ 时,平均误差已经小于 $1%$ 。虽然误差仍然存在,但已经基本可以忽略。</p>
<p>还有一个缺点是编程难度较DTW大。</p>
<h5 id="DTW变种3:constrained-DTW"><a href="#DTW变种3:constrained-DTW" class="headerlink" title="DTW变种3:constrained DTW"></a>DTW变种3:constrained DTW</h5><p>来自论文《Searching and mining trillions of time series subsequences under dynamic time warping》</p>
<p>这篇文章对几种已有的剪枝策略进行了讨论,对它们的下界和时间复杂度进行了比较进行了比较,如下图所示:</p>
<p><img src="https://i.loli.net/2020/06/06/XqjekxGlUFdMbVJ.png" alt="image-20200606141816713.png"></p>
<p>一般认为在虚线下方的剪枝策略是没用的,因为至少存在一种下界更高且时间复杂度更低的策略。</p>
<p>最终作者决定用这种策略:先用 $LB_{Kim}FL$ ,如果不能大于 $Best_so_far$ ,则再用 $LB_{Keogh}EQ$ ,还是不行就用 $LB_{Keogh}EC$,再不行就用 $Early_abandoning_DTW$ 。</p>
<p>至于cDTW,似乎这篇论文并没有提到,查了其他的资料,大概就是把DTW的路径限制在对角线旁边的样子。</p>
<h4 id="平移型对齐策略"><a href="#平移型对齐策略" class="headerlink" title="平移型对齐策略"></a>平移型对齐策略</h4><p>只可一对一,允许两边边界的点(端点及端点附近点)找不到配对,满足连续性。</p>
<p>比较适合的场景:时钟不共享而有一定偏差的两条时间序列</p>
<h5 id="典型例子:cross-correlation:平移型对齐策略下的夹角型度量"><a href="#典型例子:cross-correlation:平移型对齐策略下的夹角型度量" class="headerlink" title="典型例子:cross-correlation:平移型对齐策略下的夹角型度量"></a>典型例子:cross-correlation:平移型对齐策略下的夹角型度量</h5><p>可参考论文<<k-Shape: Efficient and Accurate Clustering of Time Series>>的3.1节的介绍</p>
<p>cross-correlation的定义与卷积类似,对于函数 $f(x)$ 和 $g(x)$ ,它们的 cross-correlation 定义为 </p>
<p>$$h(x)=\int_{-\infin}^{+\infin}f(t)g(x+t)dt$$。事实上,把 + 号改为 - 号就是卷积了。两个已经标准化了的时间序列 $\vec x=(x_1,…,x_m)$ 和 $\vec y=(y_1,…,y_m)$ 的 cross-correlation 可以这样定义:$CC(\vec x,\vec y)=(c_1,c_2,…,c_{2*m-1})$</p>
<p>其中:$c_{k+m}=\begin{cases}\sum\limits_{l=1}^{m-k}x_{l+k}y_l,k>0\ \vec x · \vec y ,k=0 \ \sum\limits_{l=1-k}^{m}x_{l+k}y_l,k<0 \end{cases}$</p>
<p>然后在 $CC(\vec x,\vec y)$ 中找到一个最大的,记为 $CC_w(\vec x,\vec y)$,定义 $NCC_c(\vec x,\vec y)=\frac{CC_w(\vec x,\vec y)}{\sqrt{R_0(\vec x,\vec x)·R_0(\vec y,\vec y)}}$。这样就把距离归化到 $[-1,1]$。再定义 $SBD(\vec x,\vec y)=1-NCC_c(\vec x,\vec y)$ ,则得到 向量 $\vec x$ 和向量 $\vec y$ 的 SBD(Shape-based distance)距离,对于形状接近的时间序列,这个值接近于0,否则接近于2。</p>
<p>值得注意的是,直接计算两个长为 $m$ 的时间序列的SBD距离是 $O(m^2)$ 的,但我们知道两个序列的卷积可以 $O(mlogm)$ 地计算,而)卷积只用把 $\vec x$ 翻转一下就变成了 $CC(\vec x,\vec y)$,因此,计算 SBD 距离也是 $O(mlogm)$ 的。这会比 $O(m^2)$ 的 DTW 算法快很多。</p>
<p>以下的变种是基于不同标准化思路得到的变种。</p>
<p><<k-Shape: Efficient and Accurate Clustering of Time Series>>的3.1节的公式8的3个变种</p>
<p>定义 $NCC_b(\vec x,\vec y)=\frac{CC_w(\vec x,\vec y)}{m}$ 这样的结果并不会归一化到一个区间,有啥规律我也看不出来…</p>
<p>定义 $NCC_u(\vec x,\vec y)=\frac{CC_w(\vec x,\vec y)}{w-|w-m|}$,这样的结果是上面有多少项相乘,则结果就除以多少。</p>
</div>
<footer class="post-footer">
<div class="post-eof"></div>
</footer>
</article>
<article itemscope itemtype="http://schema.org/Article" class="post-block home" lang="zh-CN">
<link itemprop="mainEntityOfPage" href="http://yoursite.com/2020/05/15/%E5%B9%B6%E8%A1%8C%E4%B8%8E%E5%88%86%E5%B8%83%E5%BC%8F%E8%AE%A1%E7%AE%97%E4%BD%9C%E4%B8%9A3/">
<span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
<meta itemprop="image" content="/images/avatar.gif">
<meta itemprop="name" content="reeeeeeeeeein">
<meta itemprop="description" content="SYSU 计算机专业大二在读">
</span>
<span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
<meta itemprop="name" content="reeeeeeeeeein的博客">
</span>
<header class="post-header">
<h1 class="post-title" itemprop="name headline">
<a href="/2020/05/15/%E5%B9%B6%E8%A1%8C%E4%B8%8E%E5%88%86%E5%B8%83%E5%BC%8F%E8%AE%A1%E7%AE%97%E4%BD%9C%E4%B8%9A3/" class="post-title-link" itemprop="url">并行与分布式计算作业3</a>
</h1>
<div class="post-meta">
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="fa fa-calendar-o"></i>
</span>
<span class="post-meta-item-text">发表于</span>
<time title="创建时间:2020-05-15 16:14:54" itemprop="dateCreated datePublished" datetime="2020-05-15T16:14:54+08:00">2020-05-15</time>
</span>
</div>
</header>
<div class="post-body" itemprop="articleBody">
<h1 id="并行与分布式计算作业3"><a href="#并行与分布式计算作业3" class="headerlink" title="并行与分布式计算作业3"></a>并行与分布式计算作业3</h1><h2 id="题目要求"><a href="#题目要求" class="headerlink" title="题目要求"></a>题目要求</h2><p> 利用LLVM (C、C++)或者Soot (Java)等工具检测多线程程序中潜在的数据竞争以及是否存在不可重入函数,给出案例程序并提交分析报告。</p>
<h2 id="概述"><a href="#概述" class="headerlink" title="概述"></a>概述</h2><p> 用pthreads编写一个简单的并行程序,用附带了ThreadSanitizer的clang对代码进行编译,在终端运行,查看数据竞争情况。再根据ThreadSanitizer的输出结果对代码进行修改,通过忙等待、互斥量和信号量等方法对临界区加锁,消除数据竞争。</p>
<p> 编写一个检测程序中是否存在不可重入函数的程序,它读取一个IR文件,判断其中的每一个函数是否是不可重入的。</p>
<h2 id="检测数据竞争"><a href="#检测数据竞争" class="headerlink" title="检测数据竞争"></a>检测数据竞争</h2><p> 根据<br> $$\pi=4<em>(\sum_{n=1}^{\infty}(-1)^{n-1}</em>\frac{1}{2n-1})$$</p>
<p> 编写一个计算$\pi$值的并行程序,代码见code1.c:</p>
<p> 通过命令行参数得到线程数量和要计算的范围。在第33行创建多个线程,每个线程负责计算一部分内容,把结果累加到全局变量sum上。由于多个线程是并行执行的,且会对sum进行修改,所以会出现问题。不用ThreadSanitizer时,程序运行结果如下:</p>
<p><img src="https://i.loli.net/2020/05/15/yzVAJMmTWxp6ihv.png" alt="image-20200424185518501.png"></p>
<p> 可以看到,每次运行结果都不一样,有时偏大有时偏小,说明数据竞争现象确实存在。</p>
<p> 用ThreadSanitizer检测,结果如下:</p>
<p><img src="https://i.loli.net/2020/05/15/RvzdrZ8S3Im7VEh.png" alt="image-20200424190726679.png"></p>
<p> 可以看到,运行结果显示存在data race,在第21行,刚好就是:</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sum+=factor/(<span class="number">2</span>*i+<span class="number">1</span>);</span><br></pre></td></tr></table></figure>
<p> 一个很自然的想法是,给每个线程创建一个局部变量,把要计算的值加到这个局部变量上,最后再对所有线程求一次和。只需将Thread_sum函数修改为这样:</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">void</span>* <span class="title">Thread_sum</span><span class="params">(<span class="keyword">void</span>* rank)</span></span>{</span><br><span class="line"> <span class="keyword">long</span> my_rank=(<span class="keyword">long</span>)rank;</span><br><span class="line"> <span class="keyword">double</span> my_sum=<span class="number">0</span>;</span><br><span class="line"> <span class="keyword">double</span> factor;</span><br><span class="line"> <span class="keyword">long</span> <span class="keyword">long</span> i;</span><br><span class="line"> <span class="keyword">long</span> <span class="keyword">long</span> my_n=n/thread_count;</span><br><span class="line"> <span class="keyword">long</span> <span class="keyword">long</span> my_first_i=my_n*my_rank;</span><br><span class="line"> <span class="keyword">long</span> <span class="keyword">long</span> my_last_i=my_first_i+my_n;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span>(my_first_i%<span class="number">2</span>==<span class="number">0</span>){</span><br><span class="line"> factor=<span class="number">1.0</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span> factor=<span class="number">-1.0</span>;</span><br><span class="line"> <span class="keyword">for</span>(i = my_first_i;i<my_last_i;i++,factor=-factor){</span><br><span class="line"> my_sum+=factor/(<span class="number">2</span>*i+<span class="number">1</span>);</span><br><span class="line"> }</span><br><span class="line"> sum+=my_sum;</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">NULL</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p> 这样看似正常,但运行后发现,第24行仍然是多个线程同时修改一个全局变量,仍然存在数据竞争现象:</p>
<p><img src="https://i.loli.net/2020/05/15/hL9vPbIAzw6tsuG.png" alt="image-20200424194846838.png"></p>
<h2 id="解决数据竞争"><a href="#解决数据竞争" class="headerlink" title="解决数据竞争"></a>解决数据竞争</h2><p> 尝试用忙等待、互斥量和信号量来解决数据竞争问题。</p>
<h3 id="忙等待"><a href="#忙等待" class="headerlink" title="忙等待"></a>忙等待</h3><p> 忙等待就是设置一个标记变量,用于指明临界区可以被哪个线程执行,该执行完之后修改这个标记变量,而不能执行临界区的线程必须一直处于忙等待状态。</p>
<p> 这只用定义一个flag,再对上面的第24行修改为:</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">while</span>(flag!=my_rank);</span><br><span class="line">sum+=my_sum;</span><br><span class="line">flag=(flag+<span class="number">1</span>)%thread_count;</span><br></pre></td></tr></table></figure>
<p> 完整代码保存在code2.c</p>
<p> ThreadSanitizer似乎不支持用忙等待的方法对临界区加锁:</p>
<p><img src="https://i.loli.net/2020/05/15/hIrN26FVJad5EDu.png" alt="image-20200424221456398.png"></p>
<h3 id="互斥量"><a href="#互斥量" class="headerlink" title="互斥量"></a>互斥量</h3><p> 互斥量能保证同一时间只有一个线程在执行临界区的代码,其他线程只能等待。等当前线程执行完之后,会从等待的线程中随机选一个进入临界区。</p>
<p> 这只用定义一个互斥量mutex,再将临界区代码修改为:</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">pthread_mutex_lock(&mutex);</span><br><span class="line">sum+=my_sum;</span><br><span class="line">pthread_mutex_unlock(&mutex);</span><br></pre></td></tr></table></figure>
<p> 完整代码保存在code3.c</p>
<p> 用ThreadSanitizer测试,结果正常,没有warning:<br><img src="https://i.loli.net/2020/05/15/eZdkjpxIVoaWmLY.png" alt="image-20200424220329505.png"></p>
<h3 id="信号量"><a href="#信号量" class="headerlink" title="信号量"></a>信号量</h3><p> 信号量(semaphore)可以认为是一种特殊类型的unsigned int,它的类型是sem_t。信号量可以赋值为0,1,……。大多数情况下,我们只用0和1两个值。这种只有0和1值的信号量也称为二元信号量。0对应上了锁的互斥量,1对应没上锁的互斥量。</p>
<p> 如果我们要用信号量来解决临界区问题,可以先创建一个全局信号量,初始值为1。在临界区前调用sem_wait()函数,这个函数的意义是:如果信号量为0则阻塞;如果是非0值则减1然后进入临界区。临界区执行完之后,调用sem_post()函数将信号量置为1。<del>好像跟互斥量没啥区别</del></p>
<p> 这也只用定义一个信号量my_semaphore,在main函数里初始化,再将临界区代码修改为:</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">sem_wait(&my_semaphore);</span><br><span class="line">sum+=my_sum;</span><br><span class="line">sem_post(&my_semaphore);</span><br></pre></td></tr></table></figure>
<p> 完整代码见code4.c</p>
<p> 测试一下,也很正常:</p>
<p><img src="https://i.loli.net/2020/05/15/BVSGmTND7Hr42ke.png" alt="image-20200424221059782.png"></p>
<h2 id="检测不可重入函数"><a href="#检测不可重入函数" class="headerlink" title="检测不可重入函数"></a>检测不可重入函数</h2><p> 利用clang可以生成c语言程序对应的中间表示,下面这个函数:</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">C</span><span class="params">(<span class="keyword">int</span> a)</span></span>{</span><br><span class="line"> B(<span class="number">1</span>);</span><br><span class="line"> val=<span class="number">1</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p> 会被转化为</p>
<figure class="highlight routeros"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">define void @C(i32) #0 {</span><br><span class="line"> %2 = alloca i32,<span class="built_in"> align </span>4</span><br><span class="line"> store i32 %0, i32* %2,<span class="built_in"> align </span>4</span><br><span class="line"> call void @B(i32 1)</span><br><span class="line"> store i32 1, i32* @val,<span class="built_in"> align </span>4</span><br><span class="line"> ret void</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p> 我们不关心其他的内容,只需要知道:</p>
<ol>
<li><p>函数定义以“define”开始,这一行的第一个 ‘@’ 和 ‘(‘ 之间的字符串是函数的名字。</p>
</li>
<li><p>调用一个其他函数会以 “call” 开始, 这一行的第一个 ‘@’ 和 ‘(‘ 之间的字符串是被调用函数的名字。</p>
</li>
<li><p>访问一个全局变量时会用到 ‘@’ ,访问其他变量会用到 ‘%’ 。</p>
<p>此外,被其他函数调用但没有在程序中定义的函数,像printf()函数等,都默认为不可重入函数。</p>
</li>
</ol>
<p> 知道了这些,就可以写一个程序来检测程序中的不可重入函数了。做法很简单,把函数理解为一个点,把调用关系理解为边,A调用了B就连一条B->A的边。然后将访问了全局变量的函数和在程序中没有给出定义的函数标记为不可重入函数,从这些 “原生的” 不可重入函数开始进行深度优先搜索,凡是访问到的点都是不可重入函数。深度优先搜索的示例代码如下:</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">dfs</span><span class="params">(<span class="keyword">int</span> u)</span></span>{</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> i=head[u];i;i=e[i].next){<span class="comment">//用链式前向星的方法存边。这里是遍历u节点的每一条出边。</span></span><br><span class="line"> <span class="keyword">int</span> v=e[i].to;</span><br><span class="line"> <span class="keyword">if</span>(!vis[v]){<span class="comment">//如果这个节点没有被访问过</span></span><br><span class="line"> vis[v]=<span class="literal">true</span>;</span><br><span class="line"> <span class="keyword">if</span>(bkcr[v]!=<span class="number">-1</span>)bkcr[v]=<span class="number">1</span>;<span class="comment">//-1代表的是"原生的" 不可重入函数,1是由于调用了不可重入函数而成为不可重入函数的函数</span></span><br><span class="line"> dfs(v);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p> 完整代码见code5.cpp</p>
<h3 id="测试"><a href="#测试" class="headerlink" title="测试"></a>测试</h3><p> 编写一个test.c,里面有几个函数调用来调用去,如下图所示:</p>
<p><img src="https://i.loli.net/2020/05/15/WJbH2ApZY98dwGE.png" alt="image-20200504124549947.png"></p>
<p> 用clang生成中间代码:</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">clang -O0 -S -emit-llvm ./<span class="built_in">test</span>/test.c -o input.ll</span><br></pre></td></tr></table></figure>
<p> 进行检测,输出如下:</p>
<p><img src="https://i.loli.net/2020/05/15/NiJcqHf8RXYGzL5.png" alt="image-20200504124714169.png"></p>
<p> 结果符合预期。</p>
<h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p> 用ThreadSanitizer可以方便地检测多线程中存在的数据竞争问题,检测到临界区后,可以用互斥量和信号量对它进行加锁。利用llvm可以生成程序的中间代码,然后可以检测其中是否有不可重入函数。</p>
<p> 这次实验完成的比较简单,主要是因为之前学过一点pthread,还写了篇<a href="https://reeeeeeeeeein.github.io/2020/04/21/Pthread%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B02/" target="_blank" rel="noopener">学习笔记</a>,于是直接把代码和博客的内容拿过来用了(<del>抄自己的博客不算抄吧</del>)。检测不可重入函数稍微有点复杂,不过只要对llvm的中间代码有了基本的了解,学过一些图论算法,解决起来也不算困难。</p>
<p> 一个比较大的收获是学会了使用ThreadSanitizer来检查数据竞争,大大方便了以后编写多线程程序。</p>
</div>
<footer class="post-footer">
<div class="post-eof"></div>
</footer>
</article>
<article itemscope itemtype="http://schema.org/Article" class="post-block home" lang="zh-CN">
<link itemprop="mainEntityOfPage" href="http://yoursite.com/2020/05/15/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E5%AE%9E%E9%AA%8C%E4%B8%89_%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E5%86%85%E6%A0%B8/">
<span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
<meta itemprop="image" content="/images/avatar.gif">
<meta itemprop="name" content="reeeeeeeeeein">
<meta itemprop="description" content="SYSU 计算机专业大二在读">
</span>
<span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
<meta itemprop="name" content="reeeeeeeeeein的博客">
</span>
<header class="post-header">
<h1 class="post-title" itemprop="name headline">
<a href="/2020/05/15/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E5%AE%9E%E9%AA%8C%E4%B8%89_%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E5%86%85%E6%A0%B8/" class="post-title-link" itemprop="url">操作系统实验三_操作系统内核</a>
</h1>
<div class="post-meta">
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="fa fa-calendar-o"></i>
</span>
<span class="post-meta-item-text">发表于</span>
<time title="创建时间:2020-05-15 15:10:51" itemprop="dateCreated datePublished" datetime="2020-05-15T15:10:51+08:00">2020-05-15</time>
</span>
</div>
</header>
<div class="post-body" itemprop="articleBody">
<h1 id="操作系统实验三-操作系统内核"><a href="#操作系统实验三-操作系统内核" class="headerlink" title="操作系统实验三_操作系统内核"></a>操作系统实验三_操作系统内核</h1><p>[toc]</p>
<h2 id="实验目的"><a href="#实验目的" class="headerlink" title="实验目的"></a>实验目的</h2><p>1、加深理解操作系统内核概念<br>2、了解操作系统开发方法<br>3、掌握汇编语言与高级语言混合编程的方法<br>4、掌握独立内核的设计与加载方法<br>5、加强磁盘空间管理工作</p>
<h2 id="实验要求"><a href="#实验要求" class="headerlink" title="实验要求"></a>实验要求</h2><p>1、知道独立内核设计的需求<br>2、掌握一种x86汇编语言与一种C高级语言混合编程的规定和要求<br>3、设计一个程序,以汇编程序为主入口模块,调用一个C语言编写的函数处理汇编模块定义的数据,然后再由汇编模块完成屏幕输出数据,将程序生成COM格式程序,在DOS或虚拟环境运行。<br>4、汇编语言与高级语言混合编程的方法,重写和扩展实验二的的监控程序,从引导程序分离独立,生成一个COM格式程序的独立内核。<br>5、再设计新的引导程序,实现独立内核的加载引导,确保内核功能不比实验二的监控程序弱,展示原有功能或加强功能可以工作。<br>6、编写实验报告,描述实验工作的过程和必要的细节,如截屏或录屏,以证实实验工作的真实性</p>
<h2 id="实验环境"><a href="#实验环境" class="headerlink" title="实验环境"></a>实验环境</h2><ul>
<li>Windows 10</li>
<li>WSL (Windows Subsystem for Linux) [Ubuntu 18.04.2 LTS]:WSL 是以软件的形式运行在 Windows 下的 Linux 子系统,是近些年微软推出来的新工具,可以在 Windows 系统上原生运行 Linux。</li>
<li>gcc version 7.5.0:C 语言程序编译器,Ubuntu 自带。</li>
<li>ld version 2.3.0: 链接器,Ubuntu自带</li>
<li>NASM version 2.13.02:汇编程序编译器,通过<code>sudo apt install nasm</code>安装在 WSL 上。</li>
<li>Oracle VM VirtualBox :轻量开源的虚拟机软件,安装在Windows下。</li>
<li>VSCode - Insiders v1.33.0:好用的文本编辑器,有丰富的插件,可以用它来打开WSL中的文件夹,用它自带的终端执行make命令。</li>
<li>GNU Make 4.1:安装在 Ubuntu 下,一键编译并连接代码,生成最终的文件。</li>
<li>Bochs 2.1.1:安装在Windows下,用于调试代码。</li>
</ul>
<h3 id="自制工具"><a href="#自制工具" class="headerlink" title="自制工具"></a>自制工具</h3><p> 由于我的虚拟机和Bochs都安装在Windows下,所以需要将WSL中生成的文件写入至Windows的磁盘,这可以用我编写的工具 do 来解决,只需要执行</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">./do 文件名 写入的扇区</span><br></pre></td></tr></table></figure>
<p> 就可以了。</p>
<h2 id="实验内容"><a href="#实验内容" class="headerlink" title="实验内容"></a>实验内容</h2><h3 id="概述"><a href="#概述" class="headerlink" title="概述"></a>概述</h3><p> 首先了解c语言程序与汇编语言程序混合编译的方法,再开发操作系统内核,它具有两个主要功能:</p>
<ul>
<li><p>提供加载用户程序的方法,用户可以将程序写入磁盘,然后让操作系统执行这些用户程序。</p>
</li>
<li><p>控制键盘输入和屏幕输出,使得用户可以与操作系统交互。</p>
</li>
</ul>
<p> 再将上一次实验的4个程序放进磁盘,让操作系统执行它们,查看执行结果是否正确。</p>
<h3 id="c与汇编混合编译"><a href="#c与汇编混合编译" class="headerlink" title="c与汇编混合编译"></a>c与汇编混合编译</h3><p> 由于操作系统内核非常复杂,只用汇编语言是很难完成的,因此需要使用c语言和汇编语言的混合编译,生成可执行的二进制文件。</p>
<p> 可以用gcc将一个c语言程序编译生成汇编语言文件,如对下面这个test.c:</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">f</span><span class="params">(<span class="keyword">int</span> val)</span></span>{</span><br><span class="line"> <span class="keyword">return</span> val+<span class="number">1</span>;</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span></span>{</span><br><span class="line"> f(<span class="number">3</span>);</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p> 执行</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">gcc -march=i386 -m16 -ffreestanding -fno-PIE -masm=intel -S test.c -o test.asm</span><br></pre></td></tr></table></figure>
<p> 会生成一个x86格式的汇编语言文件test.asm。它的内容很复杂,但我们只用关注一些关键的地方:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">main:</span><br><span class="line">.LFB1:</span><br><span class="line"> .cfi_startproc</span><br><span class="line"> push ebp;函数开始时,总要push ebp,保护这个寄存器</span><br><span class="line"> .cfi_def_cfa_offset 8</span><br><span class="line"> .cfi_offset 5, -8</span><br><span class="line"> mov ebp, esp</span><br><span class="line"> .cfi_def_cfa_register 5</span><br><span class="line"> push 3 ;传递参数用push,把参数压到栈里,被调用的函数就能发现</span><br><span class="line"> call f ;这里调用了f这个函数,用的是call指令</span><br><span class="line"> add esp, 4 ;由于前面的ret和pop指令,现在esp指向的值就是3,也就是刚才传的参数,所以把esp+=3,会让栈恢复到函数调用之前的状态</span><br><span class="line"> nop</span><br><span class="line"> leave</span><br><span class="line"> .cfi_restore 5</span><br><span class="line"> .cfi_def_cfa 4, 4</span><br><span class="line"> ret ;返回只用一条ret指令就可以了。由于我的test.c文件没有return 0,所以gcc帮我补上了一条ret指令</span><br><span class="line"> .cfi_endproc</span><br></pre></td></tr></table></figure>
<p> f 函数是这样的:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">f:</span><br><span class="line">.LFB0:</span><br><span class="line"> .cfi_startproc</span><br><span class="line"> push ebp ;这里也是要push ebp</span><br><span class="line"> .cfi_def_cfa_offset 8</span><br><span class="line"> .cfi_offset 5, -8</span><br><span class="line"> mov ebp, esp</span><br><span class="line"> .cfi_def_cfa_register 5</span><br><span class="line"> mov eax, DWORD PTR [ebp+8] ;main函数用了call指令,esp要减4;前面push 了 ebp ,esp又要减4,所以esp+8才是我们传递给f函数的参数。</span><br><span class="line"> inc eax ;返回一个值,可以把它放在eax里</span><br><span class="line"> pop ebp ;这里把ebp pop 掉,esp+=4</span><br><span class="line"> .cfi_restore 5</span><br><span class="line"> .cfi_def_cfa 4, 4</span><br><span class="line"> ret ;这里返回,esp+=4</span><br><span class="line"> .cfi_endproc</span><br></pre></td></tr></table></figure>
<p> 看来c语言生成的汇编程序也不算神秘,除了一些奇奇怪怪的指令,跟我们写的汇编程序也没有很大差别。通过上述分析,我们对函数调用和传递参数过程有了更深入的了解。</p>
<p> 接着,我们编写一个汇编程序(msg.asm)和c程序(count.c)混合编程实例。汇编模块中定义一个字符串(为了方便,假设它以’\n’结尾),调用C语言的函数,统计其中某个字符出现的次数,汇编模块显示统计结果。</p>
<p> c程序如下:</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">count</span><span class="params">(<span class="keyword">char</span>* str)</span></span>{</span><br><span class="line"> <span class="keyword">int</span> i=<span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span>(;*str!=<span class="string">'\n'</span>;str++){</span><br><span class="line"> <span class="keyword">if</span>(*str==<span class="string">'e'</span>)i++;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> i;</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">(<span class="keyword">void</span>)</span></span>{</span><br><span class="line"> count(<span class="number">0</span>);</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p> 其中,汇编程序调用c程序的函数的过程如下:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">push 0</span><br><span class="line">push string; string 是一个标号,占2个字节,但c语言的指针是4个字节,于是要把前两个字节置为0,就在上面多push一个0</span><br><span class="line">push 0;call会压栈2个字节,但c语言中默认的是压栈4个字节,如果我们不压栈4个字节,c程序中栈的位置会错乱</span><br><span class="line">call count</span><br></pre></td></tr></table></figure>
<p> 函数返回会把返回值放在eax寄存器,然后汇编程序可以调用 10h 号中断把它显示出来。</p>
<p> 编写makefile文件(makefile2)如下:</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="section">kernel:msg.o count.o my_mbr</span></span><br><span class="line"> ld -m elf_i386 -N --oformat binary -Ttext 0x7e00 msg.o count.o -o kernel</span><br><span class="line"> <span class="comment">#ld 用于将汇编程序生成的二进制文件和c程序生成的二进制文件链接起来, -Ttest用于指定程序的起始位置为0x7e00处</span></span><br><span class="line"> ./do kernel 1 <span class="comment"># 将kernel文件写入磁盘的第一个扇区</span></span><br><span class="line"> ./do my_mbr 0 <span class="comment"># my_mbr是引导扇区程序,它会将kernel文件加载到0x7e00处</span></span><br><span class="line"><span class="section">msg.o:msg.asm</span></span><br><span class="line"> nasm -felf msg.asm -o msg.o <span class="comment"># 如果不加 -felf 参数好像就不能调用c程序中的函数</span></span><br><span class="line"> nm msg.o > tem.txt <span class="comment">#用 nm 命令来分析符号表,输出重定向到tem.txt文件</span></span><br><span class="line"><span class="section">count.o:count.asm</span></span><br><span class="line"> gcc -march=i386 -m16 -mpreferred-stack-boundary=2 -ffreestanding -fno-PIE -masm=intel -c count.c -o count.o</span><br><span class="line"> <span class="comment">#这里跟上文的编译方式基本一样,不同的是 -c 参数指定生成 .o 文件</span></span><br><span class="line"> nm count.o >> tem.txt <span class="comment">#用 nm 命令来分析符号表,输出重定向到tem.txt文件的末端</span></span><br><span class="line"><span class="section">my_mbr:my_mbr.asm</span></span><br><span class="line"> nasm my_mbr.asm -o my_mbr</span><br></pre></td></tr></table></figure>
<p> 在VSCode自带终端中输入:</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">make -f makefile2</span><br></pre></td></tr></table></figure>
<p> 就完成了编译、链接和写入磁盘的工作,非常方便。得到的符号表如下:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">0000001a t _end #因为msg.asm里将_start声明为全局变量,_end没有,所以这一行是 小写字母t 表示这是局部变量</span><br><span class="line">00000000 T _start #这一行是大写字母T表示全局变量</span><br><span class="line"> U count</span><br><span class="line">0000001c t string</span><br><span class="line">00000000 T count</span><br><span class="line">0000003f T main</span><br></pre></td></tr></table></figure>
<p> 用bochs运行,结果如下:</p>
<p><img src="https://i.loli.net/2020/05/15/BiZqJkC7Qdv3Ueu.png" alt="image-20200509142152549.png"></p>
<p> 运行结果正常。</p>
<h3 id="开发操作系统内核"><a href="#开发操作系统内核" class="headerlink" title="开发操作系统内核"></a>开发操作系统内核</h3><p> 理论上来说,用纯C语言开发内核也是可以的,但要用到很多内嵌汇编,会使程序看起来令人不适。为此,我把 C 程序中需要用到的大量汇编语言代码放置在entry.asm中,c程序只需要执行</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">call 标号</span><br></pre></td></tr></table></figure>
<p> 就可以调用entry.asm 里的各种过程。</p>
<h4 id="汇编程序部分"><a href="#汇编程序部分" class="headerlink" title="汇编程序部分"></a>汇编程序部分</h4><p> 这部分的内容在entry.asm这个文件中,主要分为三部分。从第6行到第13行是第一部分,主要负责将控制权交给C程序中的main函数,当main函数返回时停机。</p>
<p> 从第15行到第71行_load_program过程,用于加载用户程序。将程序从磁盘加载到内存可以调用 16h 号中断来实现,但我一调用就会出bug,于是我只能用《x86汇编语言:从实模式到保护模式》这本书里提供的代码。</p>
<p> 调用这个过程之前要将用户程序被加载到的位置放置在dx中,用户程序在磁盘中的起始扇区放置在si中,用户程序的所占扇区数放置在bx中。</p>
<p> 从第73行到第111行是clear过程,用于将屏幕清空。这个过程十分简单,不必赘述。</p>
<h4 id="C程序部分"><a href="#C程序部分" class="headerlink" title="C程序部分"></a>C程序部分</h4><p> main.c这个文件中的内容是操作系统内核的主要部分。它包括基础I/O操作、工具函数和各种用户交互命令。</p>
<h5 id="I-O-操作"><a href="#I-O-操作" class="headerlink" title="I/O 操作"></a>I/O 操作</h5><p> 为了方便输入输出,我首先编写了getchar()、putchar()、getline()、put()这4个函数。</p>
<p> 第23行到第32行的内容是 getchar() 函数,它通过调用 16h 号中断来得到一个输入字符。如果这个字符的值是13(回车符的键盘码),则返回 ‘\n’ 。</p>
<p> 第34行到第86行的内容是putchar() 函数,它接受一个字符类型的参数,将字符打印到屏幕上。打印的位置由locr 、 locc 这两个全局变量来决定。</p>
<p> 当要打印的字符是一个普通的字符时,调用 10h 号中断在当前光标处输出这个字符,并调整locr 和 locc 两个变量的值;</p>
<p> 当要打印的字符是回车符时,将locc置0,将locr++,调用 10h 号中断设置光标的位置为 locc 和 locr 指定的位置;</p>
<p> 当要打印的字符是退格符时,首先修改 locc 和 locr 两个变量的值,保证这两个值始终都是下一次打印的字符在的屏幕上的位置。然后调用10h号中断修改当前光标的位置为为 locc 和 locr 指定的位置,将这个位置的值清0。</p>
<p> getline()函数接受一个字符类型的指针,不断调用getchar(),把读进来的字符存到字符串里,读到回车符就终止,给字符串加上一个 ‘\0’ 。</p>
<p> put()函数接受一个字符类型的指针,不断调用putchar()输出它,遇到 ‘\0’ 就终止。</p>
<h5 id="工具函数"><a href="#工具函数" class="headerlink" title="工具函数"></a>工具函数</h5><p> 为了方便,我编写了 int_to_str () , str_to_int () 和 strcmp () 这几个函数。意思很明显,内容也缺乏技术含量,不再赘述。</p>
<h5 id="用户交互"><a href="#用户交互" class="headerlink" title="用户交互"></a>用户交互</h5><p> 程序会不断循环,每次都用getline读取用户输入的命令,并进行交互,共有clear、help、load 和 quit 4种交互命令。</p>
<p> clear命令会将屏幕清空,这只需调用前面说过的entry.asm里的_clear过程就可以了。</p>
<p> help命令会打印提示信息。</p>
<p> quit命令会终止操作系统内核的执行。</p>
<p> load命令是最重要的命令。设计这个命令的初衷是,假设用户有一块装有我的操作系统内核的硬盘,但他完全不懂电脑,只会将程序写入硬盘。这个命令可以让他将程序加载到内存中并运行,而完全不需要修改操作系统的代码。</p>
<p> load命令会打印一条提示信息提示,提示用户输入程序在磁盘中的起始位置,再打印一条提示信息,提示用户输入程序在磁盘中占用的扇区数。然后调用 _load_program 过程将程序加载进内存0xa000处,设置es、ds寄存器的值,并将控制权交给用户程序。用户程序运行结束后,操作系统会将es、ds寄存器的值清0,并清空屏幕。</p>
<h2 id="实验过程"><a href="#实验过程" class="headerlink" title="实验过程"></a>实验过程</h2><p> 编写一个makefile文件,然后就可以在VSCode自带的终端里输入make完成大量的工作:</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line">user_programs=user_program_1 user_program_2 user_program_3 user_program_4</span><br><span class="line"><span class="section">all: kernel my_mbr <span class="variable">$(user_programs)</span></span></span><br><span class="line"> ./do kernel 1 <span class="comment"># kernel 文件是生成的操作系统内核二进制文件</span></span><br><span class="line"> ./do my_mbr 0 <span class="comment"># my_mbr 是引导扇区程序</span></span><br><span class="line"><span class="section">kernel:entry.o main.o </span></span><br><span class="line"> ld -m elf_i386 -N --oformat binary -Ttext 0x7e00 entry.o main.o -o kernel</span><br><span class="line"> <span class="comment"># 这里将 entry.o 和 main.o 链接成kernel文件,参数在上文介绍过了,不再赘述</span></span><br><span class="line"> nm entry.o > symbol_table.txt <span class="comment">#分析符号表,结果在 symbol_table.txt</span></span><br><span class="line"> nm main.o >> symbol_table.txt</span><br><span class="line"><span class="section">entry.o:entry.asm</span></span><br><span class="line"> nasm -felf <span class="variable">$<</span> -o <span class="variable">$@</span></span><br><span class="line"><span class="section">main.o:main.c</span></span><br><span class="line"> gcc -march=i386 -m16 -mpreferred-stack-boundary=2 -ffreestanding -fno-PIE -masm=intel -c <span class="variable">$<</span> -o <span class="variable">$@</span> <span class="comment">#参数在上文已经介绍过了,不再赘述</span></span><br><span class="line"><span class="section">my_mbr:my_mbr.asm</span></span><br><span class="line"> nasm my_mbr.asm -o my_mbr</span><br><span class="line"><span class="section">user_program_1:user_program_1.asm # user_program是一些用户程序,把它们分别写入到第10,20,30,40个扇区,然后可以在操作系统中加载它们</span></span><br><span class="line"> nasm <span class="variable">$<</span> -o <span class="variable">$@</span></span><br><span class="line"> ./do <span class="variable">$@</span> 10</span><br><span class="line"><span class="section">user_program_2:user_program_2.asm</span></span><br><span class="line"> nasm <span class="variable">$<</span> -o <span class="variable">$@</span></span><br><span class="line"> ./do <span class="variable">$@</span> 20</span><br><span class="line"><span class="section">user_program_3:user_program_3.asm</span></span><br><span class="line"> nasm <span class="variable">$<</span> -o <span class="variable">$@</span></span><br><span class="line"> ./do <span class="variable">$@</span> 30</span><br><span class="line"><span class="section">user_program_4:user_program_4.asm</span></span><br><span class="line"> nasm <span class="variable">$<</span> -o <span class="variable">$@</span></span><br><span class="line"> ./do <span class="variable">$@</span> 40</span><br></pre></td></tr></table></figure>
<p> 用bochs运行,依次输入load,10,1(第一个用户程序在磁盘的第10个扇区,大小为1个扇区):</p>
<p><img src="https://i.loli.net/2020/05/15/W6c7UZwH2i3zbQ5.png" alt="image-20200509201901481.png"></p>
<p> 效果拨群:</p>
<p><img src="https://i.loli.net/2020/05/15/82qvaxiGgCT6WH1.png" alt="image-20200509202009328.png"></p>
<p> 按下Ctrl+C,返回操作系统:</p>
<p><img src="https://i.loli.net/2020/05/15/qVfBGdirO8TMtHz.png" alt="image-20200509202136463.png"></p>
<p> 再依次输入load,20,2 加载第二个程序:</p>
<p><img src="https://i.loli.net/2020/05/15/pB162ZyeUJmLlri.png" alt="image-20200509205136902.png"></p>
<p> 效果如下:</p>
<p><img src="https://i.loli.net/2020/05/15/pUdtYiPCSu12Ff4.png" alt="image-20200509205234324.png"></p>
<p> 输入 load 40 4 后效果如下:</p>
<p><img src="https://i.loli.net/2020/05/15/p8iS1qwUP7LyH3X.png" alt="image-20200509205342547.png"></p>
<p> 输入load 30 3 后效果如下:</p>
<p><img src="https://i.loli.net/2020/05/15/h4wkFUQot7C6lSY.png" alt="image-20200509205446870.png"></p>
<p> 输入help打印提示信息:</p>
<p><img src="https://i.loli.net/2020/05/15/8FmgjUR9kdExCrw.png" alt="image-20200509205640183.png"></p>
<p> 输入clear清空:</p>
<p><img src="https://i.loli.net/2020/05/15/oRcXPSM4mfpLC13.png" alt="image-20200509205739629.png"></p>
<p><img src="https://i.loli.net/2020/05/15/krx9MFn3uqolZsK.png" alt="image-20200510163248587.png"></p>
<p> 输入quit可以退出操作系统:</p>
<p><img src="https://i.loli.net/2020/05/15/Ap3aekdBQ1SIJXP.png" alt="image-20200509205827461.png"></p>
<h2 id="实验总结"><a href="#实验总结" class="headerlink" title="实验总结"></a>实验总结</h2><p> 这次实验算得上是很硬核了,用到了很多x86汇编的知识,还要用 ld 这种完全不熟的工具,用gcc里各种奇奇怪怪的参数,甚至为了方便我还学了一下makefile <del>(好像早就该学了吧)</del> ,遇到的困难也有很多,主要有:</p>
<ul>
<li><p> 对汇编语言不够了解。主要是函数调用和传参那里,非常麻烦,之前从没有深入了解过。而且C语言程序编译生成的汇编代码跟自己写的在风格上有很大差别,让我很不适应。一开始的时候只能看懂一些关键的语句的意思,好在我看多了之后还是克服了心中的 “恐惧感” 。</p>
</li>
<li><p> debug实在是太麻烦了。虽然我会使用bochs调试程序,但很多bug非常隐蔽,包括但不限于:</p>
<ol>
<li><p>在键盘中输入alt+tab切换屏幕,导致后面的输入无法被bochs读入。至今我都没想到解决的办法,好在不影响我写程序。</p>
</li>
<li><p>向c语言的函数传字符串常量会出错。这个问题好像不止我一个遇到,其他的同学和网上的<a href="https://wu-kan.cn/_posts/2019-03-28-%E7%94%A8%E6%B1%87%E7%BC%96%E4%B8%8EC%E8%AF%AD%E8%A8%80%E5%BC%80%E5%8F%91%E7%8B%AC%E7%AB%8B%E5%86%85%E6%A0%B8/" target="_blank" rel="noopener">博客</a>也有这样的问题。我至今也没找到原因,只能把字符串常量改为char*类型。</p>
</li>
<li><p>向指向int类型的指针传short类型变量的地址。我声明了一个short变量,调用 str_to_int (char* s,int* val) 函数的时候把它的地址传了进去,本来我觉得反正都会进行类型转换,没啥问题。可是我执行了</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">*val=<span class="number">0</span>;</span><br></pre></td></tr></table></figure>
<p>之后,问题就来了: short类型变量是2个字节,但 val 指针是int类型的指针,上面的操作会把内存中4个字节全部置为0。更要命的是,由于第一个参数先压栈,第二个字符后压栈,val指向的后面两个字节刚好就是 s 字符串的前两个字节,于是这个函数就不会得到正确的结果。当我想到这个问题时,我不禁为这世上有如此巧妙的bug而感到震惊。</p>
</li>
</ol>
</li>
</ul>
<p><img src="https://i.loli.net/2020/05/15/QxwsYLrkB8vln9G.png" alt="image-20200509000616841.png"></p>
<p> <img src="https://i.loli.net/2020/05/15/PwOi6rSZyXVCknb.png" alt="image-20200509000427794.png"></p>
<ol start="3">
<li><p>int 16h 读键盘会导致光标位置出错。这是一个很奇怪的bug,不调用int 16h时,用int 10h 中断(ah=3)来读取光标位置可以正常运行,当我用 int 16h 读键盘输入后,用int 10h 中断(ah=03)就完全得不到正确结果,但在光标处打印字符却没有问题。我最终也没整明白这其中的缘由,只能放弃使用int 10h 中断来读取光标位置,改用 locc locr 这两个变量。</p>