浏览代码

-p is now reuired.

Joshua Rutschmann 7 年前
父节点
当前提交
cfe8df0d90
共有 5 个文件被更改,包括 390 次插入8 次删除
  1. 2
    1
      hw9/task2/Cargo.toml
  2. 32
    0
      hw9/task2/src/cli.yml
  3. 48
    2
      hw9/task2/src/main.rs
  4. 2
    0
      hw9/task2/srv-commands/Cargo.toml
  5. 306
    5
      hw9/task2/srv-commands/src/lib.rs

+ 2
- 1
hw9/task2/Cargo.toml 查看文件

@@ -4,7 +4,8 @@ version = "0.1.0"
4 4
 authors = ["Joshua Rutschmann <joshua.rutschmann@gmx.de>"]
5 5
 
6 6
 [dependencies]
7
-srv-commands = { path = "srv-commands" }                                                                                                                                                                                  
7
+clap = {version = "~2.29.0", features = ["yaml"]}
8
+srv-commands = { path = "srv-commands" }
8 9
 srv-config = { path = "srv-config" } 
9 10
 
10 11
 [workspace]

+ 32
- 0
hw9/task2/src/cli.yml 查看文件

@@ -0,0 +1,32 @@
1
+name: "Multi Hash Server 0.1"
2
+author: "Lorenz Bung & Joshua Rutschmann"
3
+about: "Does awesome things to find a hash with specific pattern"
4
+args:
5
+    - verbose:
6
+        short: "v"
7
+        help: "Prints help information"
8
+        multiple: true
9
+        required: false
10
+
11
+    - address:
12
+        short: "a"
13
+        long: "address"
14
+        value_name: "ADDRESS"
15
+        help: "the address, where the server can be reached (127.0.0.1 is default)"
16
+        takes_value: true 
17
+	required: false
18
+
19
+    - port:
20
+        short: "p"
21
+        long: "port"
22
+        value_name: "PORT"
23
+        help: "the port, where the server can be reached (7878 is default)"
24
+        takes_value: true
25
+	required: true
26
+
27
+subcommands:
28
+    - test:
29
+        about: "controls testing features"
30
+        version: "1.0"
31
+        author: "Lorenz Bung & Joshua Rutschmann"
32
+

+ 48
- 2
hw9/task2/src/main.rs 查看文件

@@ -1,3 +1,49 @@
1
-fn main() {
2
-    println!("Hello, world!");
1
+#[macro_use]
2
+extern crate clap;
3
+
4
+use clap::App;
5
+use std::net::{TcpListener, TcpStream};
6
+
7
+fn handle_client(stream: TcpStream) {
8
+    // ...
9
+}
10
+
11
+pub fn main() {
12
+    // Lade Commandline Einstellungen aus YAML-Datei
13
+    let yaml = load_yaml!("cli.yml");
14
+    let matches = App::from_yaml(yaml).get_matches();
15
+    let address = matches.value_of("address").unwrap_or("127.0.0.1");
16
+    let port = matches.value_of("port").unwrap_or("7878");
17
+    let verbosity = matches.occurrences_of("verbose");
18
+    let mut testing = false;
19
+
20
+    // Falls das Unterkommando timings angegeben wurde aktiviere die Zeitmessung.
21
+    if let Some(ref sub_command) = matches.subcommand {
22
+        if sub_command.name.eq("test") {
23
+            testing = true;
24
+        }
25
+    }
26
+
27
+    if verbosity > 0 {
28
+        println!("Starting Multi Hash Server 0.1:");
29
+        println!("verbosity: {} | address: {} | port: {} | test-mode: {}", verbosity, address, port, testing);
30
+    }
31
+
32
+    let host = format!("{}:{}", address, port);
33
+    match TcpListener::bind(host) {
34
+        Ok(listener) => {
35
+            // accept connections and process them serially
36
+            for stream in listener.incoming() {
37
+                match stream {
38
+                    Ok(stream) => {
39
+                        println!("new client!");
40
+                    }
41
+                    Err(e) => { /* connection failed */ }
42
+                }
43
+            }
44
+        }
45
+        Err(_) => {
46
+            println!("Error starting server.");
47
+        }
48
+    }
3 49
 }

+ 2
- 0
hw9/task2/srv-commands/Cargo.toml 查看文件

@@ -4,3 +4,5 @@ version = "0.1.0"
4 4
 authors = ["Joshua Rutschmann <joshua.rutschmann@gmx.de>"]
5 5
 
6 6
 [dependencies]
7
+sha2 = "0.7.0"
8
+time = "0.1"

+ 306
- 5
hw9/task2/srv-commands/src/lib.rs 查看文件

@@ -1,7 +1,308 @@
1
-#[cfg(test)]
2
-mod tests {
3
-    #[test]
4
-    fn it_works() {
5
-        assert_eq!(2 + 2, 4);
1
+extern crate sha2;
2
+extern crate time;
3
+
4
+#[cfg(feature = "SHA2")]
5
+use self::sha2::Sha256;
6
+use std::thread;
7
+use std::sync::Arc;
8
+use std::sync::atomic::AtomicBool;
9
+use std::sync::atomic::Ordering::Relaxed;
10
+use std::sync::mpsc::{Sender, channel};
11
+use time::{Duration, get_time};
12
+
13
+
14
+pub struct Sha256;
15
+
16
+pub trait Hasher {
17
+    type Output: HashResult;
18
+    fn hash(input: &[u8]) -> Self::Output;
19
+}
20
+
21
+pub trait HashResult {
22
+    /// Get the output in hex notation.
23
+    fn hex(&self) -> String;
24
+    /// Size of the output in bytes.
25
+    fn size() -> usize;
26
+}
27
+
28
+impl Hasher for Sha256 {
29
+    type Output = [u8; 32];
30
+
31
+    fn hash(input: &[u8]) -> Self::Output {
32
+        use self::sha2::*;
33
+        let mut tmp = Sha256::new();
34
+        tmp.input(input);
35
+        let r = tmp.result().as_slice().to_vec();
36
+        [
37
+            r[0],
38
+            r[1],
39
+            r[2],
40
+            r[3],
41
+            r[4],
42
+            r[5],
43
+            r[6],
44
+            r[7],
45
+            r[8],
46
+            r[9],
47
+            r[10],
48
+            r[11],
49
+            r[12],
50
+            r[13],
51
+            r[14],
52
+            r[15],
53
+            r[16],
54
+            r[17],
55
+            r[18],
56
+            r[19],
57
+            r[20],
58
+            r[21],
59
+            r[22],
60
+            r[23],
61
+            r[24],
62
+            r[25],
63
+            r[26],
64
+            r[27],
65
+            r[28],
66
+            r[29],
67
+            r[30],
68
+            r[31],
69
+        ]
70
+    }
71
+}
72
+
73
+impl HashResult for [u8; 32] {
74
+    fn hex(&self) -> String {
75
+        const HEX: [char; 16] = [
76
+            '0',
77
+            '1',
78
+            '2',
79
+            '3',
80
+            '4',
81
+            '5',
82
+            '6',
83
+            '7',
84
+            '8',
85
+            '9',
86
+            'a',
87
+            'b',
88
+            'c',
89
+            'd',
90
+            'e',
91
+            'f',
92
+        ];
93
+        let mut tmp = String::with_capacity(32 * 2);
94
+        for byte in self.iter() {
95
+            tmp.push(HEX[*byte as usize / 16]);
96
+            tmp.push(HEX[*byte as usize % 16]);
97
+        }
98
+        tmp
99
+    }
100
+
101
+    fn size() -> usize {
102
+        32
103
+    }
104
+}
105
+
106
+#[derive(Debug, PartialEq)]
107
+pub struct Solution {
108
+    pub number: usize,
109
+    pub hash: String,
110
+}
111
+
112
+/// Überprüft ob *base* und *number* auf einen Hash abbilden,
113
+/// der mit der übergebenen *difficulty* übereinstimmt.
114
+/// Falls ja, kommt eine `Solution` in der Option mit den Ergebnissen zurück.
115
+/// Falls nein, steht None im Optional
116
+pub fn verify_product(base: usize, number: usize, difficulty: &String) -> Option<Solution> {
117
+    let sol = base * number;
118
+    let input = sol.to_string();
119
+    let bytes = input.as_bytes();
120
+
121
+    let hash = Sha256::hash(bytes).hex();
122
+
123
+    if hash.ends_with(difficulty) {
124
+        return Some(Solution {
125
+            number: number,
126
+            hash: hash,
127
+        });
128
+    }
129
+
130
+    None
131
+}
132
+
133
+/// Sucht nach einem Hash für die angegebene Basis und die Schwierigkeit.
134
+/// Wenn `total` > 1 ist, dann hat jeder Aufruf mit einem anderen `start`-Wert (von 0 - total)
135
+/// eine disjunkte Zahlenmenge für die Suche zur Auswahl.
136
+fn search_hash(
137
+    hash: &String,
138
+    base: usize,
139
+    start: usize,
140
+    total: usize,
141
+    sync: bool,
142
+    found: Arc<AtomicBool>,
143
+    special: usize,
144
+    solution_tx: Sender<Solution>,
145
+    timing_tx: Sender<(Duration, usize)>,
146
+    measure: bool,
147
+) {
148
+    let max = <usize>::max_value();
149
+    let mut n = start;
150
+
151
+    let thread_start = get_time();
152
+    while n < max {
153
+
154
+        // Der special Parameter begrenzt die Anzahl der load()-Aufrufe auf jeden n.ten Loop.
155
+        if n % special == 0 && found.load(Relaxed) {
156
+            // Anderer Thread hat eine Lösung gefunden (sync ist aktiviert). Beende Suche.
157
+            break;
158
+        }
159
+
160
+        if let Some(solution) = verify_product(base, n, hash) {
161
+            if sync {
162
+                found.store(true, Relaxed);
163
+            }
164
+            // Sende gefundene Solution an den Consumer.
165
+            let _ = solution_tx.send(solution);
166
+            // Beende Suche.
167
+            break;
168
+        }
169
+        n += total;
170
+    }
171
+
172
+    // Falls measure aktiviert ist Sende Zeitdauer und Anzahl Loops an den Consumer.
173
+    if measure {
174
+        let thread_end = get_time();
175
+        let _ = timing_tx.send((thread_end - thread_start, (n / total)));
176
+    }
177
+}
178
+
179
+/// Teilt, wenn nötig, die Suche nach dem Hash auf mehrere Threads auf.
180
+/// Gibt ggf. die Solution (für die Tests) zurück.
181
+pub fn search_with_threads(
182
+    threads: usize,
183
+    diff_string: String,
184
+    with_base: usize,
185
+    time_measurement: bool,
186
+    verbosity: u64,
187
+    sync: Option<usize>,
188
+    wait: bool,
189
+) -> Option<Solution> {
190
+
191
+    let diff = Arc::new(diff_string);
192
+    let mut children = vec![];
193
+    let mut solution = None;
194
+
195
+    let (solution_tx, solution_rx) = channel();
196
+    let (timing_tx, timing_rx) = channel();
197
+
198
+    let found = Arc::new(AtomicBool::new(false));
199
+    let m = time_measurement && verbosity > 0;
200
+
201
+    let total_start = get_time();
202
+    if threads > 1 {
203
+
204
+        if verbosity > 0 {
205
+            println!("Searching with {} threads", threads);
206
+        }
207
+
208
+        // Erstellt Anzahl angeforderter Threads.
209
+        // Klont für jeden Thread die Referenz auf die gemeinsamen Variablen.
210
+        for i in 0..threads {
211
+            let diff = diff.clone();
212
+            let solution_tx = solution_tx.clone();
213
+            let timing_tx = timing_tx.clone();
214
+            let found = found.clone();
215
+
216
+            children.push(thread::spawn(move || {
217
+
218
+                // Suche in jedem der Threads.
219
+                search_hash(
220
+                    &diff,
221
+                    with_base,
222
+                    i,
223
+                    threads,
224
+                    sync.is_some(),
225
+                    found,
226
+                    sync.unwrap_or(1),
227
+                    solution_tx,
228
+                    timing_tx,
229
+                    m,
230
+                );
231
+
232
+                if verbosity > 1 {
233
+                    println!("[DEBUG] Thread {} exited", i);
234
+                }
235
+            }));
236
+        }
237
+    } else {
238
+        // Suche auf dem Main-Thread.
239
+        search_hash(
240
+            &diff,
241
+            with_base,
242
+            0,
243
+            1,
244
+            sync.is_some(),
245
+            found,
246
+            sync.unwrap_or(1),
247
+            solution_tx,
248
+            timing_tx,
249
+            m,
250
+        );
251
+
252
+        if verbosity > 1 {
253
+            println!("[DEBUG] Finished search on main thread.");
254
+        }
255
+    }
256
+
257
+    // Empfängt die Lösung von einem der Producer.
258
+    match solution_rx.recv() {
259
+        Ok(sol) => {
260
+            solution = Some(Solution {
261
+                number: sol.number,
262
+                hash: sol.hash.clone(),
263
+            });
264
+            let total_end = get_time();
265
+            println!("Number: {} --> hash: {}", sol.number, sol.hash);
266
+            if time_measurement && verbosity == 0 {
267
+                let diff = total_end - total_start;
268
+                let s = diff.num_seconds();
269
+                let ms = diff.num_milliseconds();
270
+                let us = diff.num_microseconds().unwrap_or(ms * 1000);
271
+                println!("(Duration {}s / {}ms / {}us)", s, ms, us);
272
+            }
273
+        }
274
+        Err(_) => {}
275
+    }
276
+
277
+    let mut sum_loops = 0usize;
278
+    let mut sum_time: Duration = Duration::zero();
279
+
280
+    for child in children {
281
+
282
+        if time_measurement && verbosity > 0 {
283
+            // Warte auf Zeitstatistik-Nachricht von jedem Thread auf dem zweiten MPSC Channel.
284
+            if let Ok(stats) = timing_rx.recv() {
285
+                // Addiere Werte dieses threads zu der Summe.
286
+                sum_time = sum_time + stats.0;
287
+                sum_loops += stats.1;
288
+            }
289
+        }
290
+
291
+        // Falls *wait* wahr ist, warte auf aktuellen thread (child)
292
+        if wait {
293
+            let _ = child.join();
294
+        }
295
+    }
296
+
297
+    // Gebe die Gesamtergebnisse der Threads aus.
298
+    if time_measurement && verbosity > 0 {
299
+        println!("Sum Loops in Producers:       {}", sum_loops);
300
+        let s = sum_time.num_seconds();
301
+        let ms = sum_time.num_milliseconds();
302
+        let us = sum_time.num_microseconds().unwrap_or(ms * 1000);
303
+        println!("Sum Duration in Producers:    {}s / {}ms / {}us", s, ms, us);
6 304
     }
305
+
306
+    // Gebe die Option einer Solution zurück.
307
+    solution
7 308
 }

正在加载...
取消
保存