-
-
Notifications
You must be signed in to change notification settings - Fork 224
Expand file tree
/
Copy pathsockets.po
More file actions
755 lines (692 loc) · 40.2 KB
/
sockets.po
File metadata and controls
755 lines (692 loc) · 40.2 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
# Copyright (C) 2001-2024, Python Software Foundation
# This file is distributed under the same license as the Python package.
#
# Translators:
msgid ""
msgstr ""
"Project-Id-Version: Python 3.11\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-09-03 11:11+0800\n"
"PO-Revision-Date: 2023-08-12 15:16+0800\n"
"Last-Translator: Jay <weijay0804@gmail.com>\n"
"Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-"
"tw)\n"
"Language: zh_TW\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
"X-Generator: Poedit 3.3.2\n"
#: ../../howto/sockets.rst:5
msgid "Socket Programming HOWTO"
msgstr "Socket 程式設計指南"
#: ../../howto/sockets.rst:0
msgid "Author"
msgstr "作者"
#: ../../howto/sockets.rst:7
msgid "Gordon McMillan"
msgstr "Gordon McMillan"
#: ../../howto/sockets.rst:-1
msgid "Abstract"
msgstr "摘要"
#: ../../howto/sockets.rst:12
msgid ""
"Sockets are used nearly everywhere, but are one of the most severely "
"misunderstood technologies around. This is a 10,000 foot overview of "
"sockets. It's not really a tutorial - you'll still have work to do in "
"getting things operational. It doesn't cover the fine points (and there are "
"a lot of them), but I hope it will give you enough background to begin using "
"them decently."
msgstr ""
"Sockets 在各處都被廣泛使用,但卻是一項被誤解最嚴重的技術之一。這是一篇對 "
"sockets 的概論介紹。這並不是一個完整的教學指南 - 你還需要做許多準備才能讓 "
"sockets 正常運作。這篇文章也沒有包含細節(其中有非常多的細節),但我希望這篇"
"文章能夠讓你有足夠的背景知識,以便開始正確的使用 sockets 程式設計。"
#: ../../howto/sockets.rst:20
msgid "Sockets"
msgstr "Sockets"
#: ../../howto/sockets.rst:22
msgid ""
"I'm only going to talk about INET (i.e. IPv4) sockets, but they account for "
"at least 99% of the sockets in use. And I'll only talk about STREAM (i.e. "
"TCP) sockets - unless you really know what you're doing (in which case this "
"HOWTO isn't for you!), you'll get better behavior and performance from a "
"STREAM socket than anything else. I will try to clear up the mystery of what "
"a socket is, as well as some hints on how to work with blocking and non-"
"blocking sockets. But I'll start by talking about blocking sockets. You'll "
"need to know how they work before dealing with non-blocking sockets."
msgstr ""
"我只會討論關於 INET(例如:IPv4)的 sockets,但它們涵蓋了幾乎 99% 的 sockets "
"使用場景。而我也將僅討論關於 STREAM(比如:TCP)類型的 sockets - 除非你真的知"
"道你在做什麼(在這種情況下,這份指南可能不適合你),使用 STREAM 類型的 "
"socket 會獲得比其他 sockets 類型更好的表現和性能。我將會嘗試解釋 socket 是什"
"麼,以及如何使用阻塞 (blocking) 和非阻塞 (non-blocking) sockets 的一些建議。"
"但首先我會先談論阻塞 sockets。在處理非阻塞 sockets 之前,你需要了解它們的工作"
"原理。"
#: ../../howto/sockets.rst:31
msgid ""
"Part of the trouble with understanding these things is that \"socket\" can "
"mean a number of subtly different things, depending on context. So first, "
"let's make a distinction between a \"client\" socket - an endpoint of a "
"conversation, and a \"server\" socket, which is more like a switchboard "
"operator. The client application (your browser, for example) uses \"client\" "
"sockets exclusively; the web server it's talking to uses both \"server\" "
"sockets and \"client\" sockets."
msgstr ""
"要理解這些東西的困難點之一在於 \"scoket\" 可以代表多種具有些微差異的東西,這"
"主要取決於上下文。所以首先,讓我們先區分「用戶端 (client)」socket 和「伺服器"
"端 (server)」socket 的差別,「用戶端」socket 表示通訊的一端,「伺服器端」"
"socket 更像是一個電話總機接線員。用戶端應用程式(例如:你的瀏覽器)只能使用"
"「用戶端」socket; 它所連接的網路伺服器則同時使用「伺服器端」socket 和 「用戶"
"端」socket 來進行通訊。"
#: ../../howto/sockets.rst:40
msgid "History"
msgstr "歷史"
#: ../../howto/sockets.rst:42
msgid ""
"Of the various forms of :abbr:`IPC (Inter Process Communication)`, sockets "
"are by far the most popular. On any given platform, there are likely to be "
"other forms of IPC that are faster, but for cross-platform communication, "
"sockets are about the only game in town."
msgstr ""
"在各種形式的 :abbr:`IPC (Inter Process Communication)` 中,sockets 是最受歡迎"
"的。在任何特定的平台上,可能會存在其他更快速的 IPC 形式,但對於跨平台通訊來"
"說,sockets 是唯一的選擇。"
#: ../../howto/sockets.rst:47
msgid ""
"They were invented in Berkeley as part of the BSD flavor of Unix. They "
"spread like wildfire with the internet. With good reason --- the combination "
"of sockets with INET makes talking to arbitrary machines around the world "
"unbelievably easy (at least compared to other schemes)."
msgstr ""
"Sockets 作為 Unix 的 BSD 分支的一部分在 Berkeley 被發明出來。它們隨著網際網路"
"的普及而迅速蔓延開來。這是有很好的理由 — sockets 和 INET 的結合讓世界各地任何"
"的機器之間的通訊變得非常簡單(至少與其它方案相比是如此)。"
#: ../../howto/sockets.rst:54
msgid "Creating a Socket"
msgstr "建立一個 Socket"
#: ../../howto/sockets.rst:56
msgid ""
"Roughly speaking, when you clicked on the link that brought you to this "
"page, your browser did something like the following::"
msgstr ""
"大致上來說,當你點擊了帶你來到這個頁面的連結時,你的瀏覽器做了以下的操作: ::"
#: ../../howto/sockets.rst:59
msgid ""
"# create an INET, STREAMing socket\n"
"s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\n"
"# now connect to the web server on port 80 - the normal http port\n"
"s.connect((\"www.python.org\", 80))"
msgstr ""
#: ../../howto/sockets.rst:64
msgid ""
"When the ``connect`` completes, the socket ``s`` can be used to send in a "
"request for the text of the page. The same socket will read the reply, and "
"then be destroyed. That's right, destroyed. Client sockets are normally only "
"used for one exchange (or a small set of sequential exchanges)."
msgstr ""
"當 ``connect`` 完成時,這個 socket ``s`` 可以用來發送請求來取得頁面的文本。同"
"一個 socket 也會讀取回傳值,然後再被銷毀。是的,會被銷毀。用戶端 socket 通常"
"只用來做一次交換(或是一小組連續交換)。"
#: ../../howto/sockets.rst:70
msgid ""
"What happens in the web server is a bit more complex. First, the web server "
"creates a \"server socket\"::"
msgstr ""
"網路伺服器 (web server) 的運作就稍微複雜一點。首先,網路伺服器會建立一個「伺"
"服器端 socket」: ::"
#: ../../howto/sockets.rst:73
msgid ""
"# create an INET, STREAMing socket\n"
"serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\n"
"# bind the socket to a public host, and a well-known port\n"
"serversocket.bind((socket.gethostname(), 80))\n"
"# become a server socket\n"
"serversocket.listen(5)"
msgstr ""
#: ../../howto/sockets.rst:80
msgid ""
"A couple things to notice: we used ``socket.gethostname()`` so that the "
"socket would be visible to the outside world. If we had used ``s."
"bind(('localhost', 80))`` or ``s.bind(('127.0.0.1', 80))`` we would still "
"have a \"server\" socket, but one that was only visible within the same "
"machine. ``s.bind(('', 80))`` specifies that the socket is reachable by any "
"address the machine happens to have."
msgstr ""
"有幾件事需要注意:我們使用了 ``socket.gethostname()``,這樣 socket 才能對外部"
"網路可見。如果我們使用了 ``s.bind(('localhost', 80))`` 或 ``s."
"bind(('127.0.0.1', 80))``,我們會得到一個「伺服器端」socket,但是只能在同一台"
"機器內可見。``s.bind(('', 80))`` 指定 socket 可以透過機器的任何地址存取。"
#: ../../howto/sockets.rst:87
msgid ""
"A second thing to note: low number ports are usually reserved for \"well "
"known\" services (HTTP, SNMP etc). If you're playing around, use a nice high "
"number (4 digits)."
msgstr ""
"第二個要注意的是:數字小的連接埠 (port) 通常保留給「廣為人知的」服務(HTTP、"
"SNMP等)。如果你只是想執行程式,可以使用一個數字較大的連接埠(4 位數字)。"
#: ../../howto/sockets.rst:91
msgid ""
"Finally, the argument to ``listen`` tells the socket library that we want it "
"to queue up as many as 5 connect requests (the normal max) before refusing "
"outside connections. If the rest of the code is written properly, that "
"should be plenty."
msgstr ""
"最後,``listen`` 引數告訴 socket 函式庫 (library),我們希望在佇列 (queue) 中"
"累積達 5 個(正常的最大值)連線請求後再拒絕外部連線。如果其餘的程式碼編寫正"
"確,這應該足夠了。"
#: ../../howto/sockets.rst:95
msgid ""
"Now that we have a \"server\" socket, listening on port 80, we can enter the "
"mainloop of the web server::"
msgstr ""
"現在我們有一個監聽 80 連接埠的「伺服器端」socket 了,我們可以進入網路伺服器的"
"主迴圈了: ::"
#: ../../howto/sockets.rst:98
msgid ""
"while True:\n"
" # accept connections from outside\n"
" (clientsocket, address) = serversocket.accept()\n"
" # now do something with the clientsocket\n"
" # in this case, we'll pretend this is a threaded server\n"
" ct = client_thread(clientsocket)\n"
" ct.run()"
msgstr ""
#: ../../howto/sockets.rst:106
msgid ""
"There's actually 3 general ways in which this loop could work - dispatching "
"a thread to handle ``clientsocket``, create a new process to handle "
"``clientsocket``, or restructure this app to use non-blocking sockets, and "
"multiplex between our \"server\" socket and any active ``clientsocket``\\ s "
"using ``select``. More about that later. The important thing to understand "
"now is this: this is *all* a \"server\" socket does. It doesn't send any "
"data. It doesn't receive any data. It just produces \"client\" sockets. Each "
"``clientsocket`` is created in response to some *other* \"client\" socket "
"doing a ``connect()`` to the host and port we're bound to. As soon as we've "
"created that ``clientsocket``, we go back to listening for more connections. "
"The two \"clients\" are free to chat it up - they are using some dynamically "
"allocated port which will be recycled when the conversation ends."
msgstr ""
"事實上,有三種方法可以讓這個迴圈運作 - 分配一個執行緒 (thread) 來處理 "
"``clientsocket`` 、建立一個新行程 (process) 來處理 ``clientsocket``,或者將這"
"個程式重新改寫成使用非阻塞 socket,並使用 ``select`` 在我們的「伺服器端」"
"socket 和任何有效的 ``clientsocket`` 之間進行多工處理。稍後將會更詳細的介紹。"
"現在最重要的是理解:這就是「伺服器端」socket 做的\\ *所有* \\事情。它不會發送"
"任何資料、也不接收任何資料,它只會建立「伺服器端」socket。每個 "
"``clientsocket`` 都是為了回應某些\\ *其他* \\ ``connect()`` 到我們綁定的主機"
"上的「用戶端」socket。一但 ``clientsocket`` 建立完成,就會繼續監聽更多的連線"
"請求。兩個「用戶端」可以隨意的通訊 - 它們使用的是一些動態分配的連接埠,會在通"
"訊結束的時候被回收並重新利用。"
#: ../../howto/sockets.rst:121
msgid "IPC"
msgstr "IPC"
#: ../../howto/sockets.rst:123
msgid ""
"If you need fast IPC between two processes on one machine, you should look "
"into pipes or shared memory. If you do decide to use AF_INET sockets, bind "
"the \"server\" socket to ``'localhost'``. On most platforms, this will take "
"a shortcut around a couple of layers of network code and be quite a bit "
"faster."
msgstr ""
"如果你需要在一台機器上的兩個行程間進行快速的行程間通訊 (IPC),你應該考慮使用"
"管道 (pipes) 或共享記憶體 (shared memory)。如果你確定要使用 AF_INET sockets,"
"請將「伺服器端」socket 綁定到 ``'localhost'``。在大多數平台上,這樣將會繞過幾"
"個網路程式碼層,並且速度會更快一些。"
#: ../../howto/sockets.rst:129
msgid ""
"The :mod:`multiprocessing` integrates cross-platform IPC into a higher-level "
"API."
msgstr ":mod:`multiprocessing` 將跨平台行程間通訊整合到更高層的 API 中。"
#: ../../howto/sockets.rst:134
msgid "Using a Socket"
msgstr "使用一個 Socket"
#: ../../howto/sockets.rst:136
msgid ""
"The first thing to note, is that the web browser's \"client\" socket and the "
"web server's \"client\" socket are identical beasts. That is, this is a "
"\"peer to peer\" conversation. Or to put it another way, *as the designer, "
"you will have to decide what the rules of etiquette are for a conversation*. "
"Normally, the ``connect``\\ ing socket starts the conversation, by sending "
"in a request, or perhaps a signon. But that's a design decision - it's not a "
"rule of sockets."
msgstr ""
"首先需要注意,網頁瀏覽器的「用戶端」socket 和網路伺服器的「用戶端」socket 是"
"非常類似的。也就是說,這是一個「點對點 (peer to peer)」的通訊方式,或者也可以"
"說\\ *作為設計者,你必須決定通訊的規則*。通常情況下,``connect`` 的 socket 會"
"通過發送一個請求或者信號來開始一次通訊。但這屬於設計決策,而不是 socket 的規"
"則。"
#: ../../howto/sockets.rst:143
msgid ""
"Now there are two sets of verbs to use for communication. You can use "
"``send`` and ``recv``, or you can transform your client socket into a file-"
"like beast and use ``read`` and ``write``. The latter is the way Java "
"presents its sockets. I'm not going to talk about it here, except to warn "
"you that you need to use ``flush`` on sockets. These are buffered \"files\", "
"and a common mistake is to ``write`` something, and then ``read`` for a "
"reply. Without a ``flush`` in there, you may wait forever for the reply, "
"because the request may still be in your output buffer."
msgstr ""
"現在有兩組可供通訊使用的動詞。你可以使用 ``send`` 和 ``recv``,或者可以將用戶"
"端 socket 轉換成類似檔案的形式,並使用 ``read`` 和 ``write``。後者是 Java 中"
"呈現 socket 的方式。我不打算在這裡討論它,只是提醒你需要在 socket 上使用 "
"``flush``。這些是緩衝的「檔案」,一個常見的錯誤是使用 ``write`` 寫入某些內"
"容,然後直接 ``read`` 回覆。如果不使用 ``flush``,你可能會一直等待這個回覆,"
"因為請求可能還在你的輸出緩衝中。"
#: ../../howto/sockets.rst:152
msgid ""
"Now we come to the major stumbling block of sockets - ``send`` and ``recv`` "
"operate on the network buffers. They do not necessarily handle all the bytes "
"you hand them (or expect from them), because their major focus is handling "
"the network buffers. In general, they return when the associated network "
"buffers have been filled (``send``) or emptied (``recv``). They then tell "
"you how many bytes they handled. It is *your* responsibility to call them "
"again until your message has been completely dealt with."
msgstr ""
"現在我們來到 sockets 的主要障礙 - ``send`` 和 ``recv`` 操作的是網路緩衝區。他"
"們不一定會處理你提供給它們的所有位元組(或者是你期望它處理的位元組),因為它"
"們主要的重點是處理網路緩衝區。一般來說,它們會在關聯的網路衝區已滿 "
"(``send``) 或已清空 (``recv``) 時回傳,然後告訴你它們處理了多少位元組。*你* "
"\\的責任是一直呼叫它們直到你所有的訊息處理完成。"
#: ../../howto/sockets.rst:160
msgid ""
"When a ``recv`` returns 0 bytes, it means the other side has closed (or is "
"in the process of closing) the connection. You will not receive any more "
"data on this connection. Ever. You may be able to send data successfully; "
"I'll talk more about this later."
msgstr ""
"當 ``recv`` 回傳「零位元組 (0 bytes)」時,就表示另一端已經關閉(或著正在關"
"閉)連線。你再也不能從這個連線上取得任何資料了。你可能還是可以成功發送資料;"
"我稍後會對此進行更詳細的解釋。"
#: ../../howto/sockets.rst:165
msgid ""
"A protocol like HTTP uses a socket for only one transfer. The client sends a "
"request, then reads a reply. That's it. The socket is discarded. This means "
"that a client can detect the end of the reply by receiving 0 bytes."
msgstr ""
"像 HTTP 這樣的協定只使用一個 socket 進行一次傳輸,用戶端發送一個請求,然後讀"
"取一個回覆。就這樣,然後這個 socket 就會被銷毀。這表示者用戶端可以通過接收"
"「零位元組」來檢測回覆的結束。"
#: ../../howto/sockets.rst:169
msgid ""
"But if you plan to reuse your socket for further transfers, you need to "
"realize that *there is no* :abbr:`EOT (End of Transfer)` *on a socket.* I "
"repeat: if a socket ``send`` or ``recv`` returns after handling 0 bytes, the "
"connection has been broken. If the connection has *not* been broken, you "
"may wait on a ``recv`` forever, because the socket will *not* tell you that "
"there's nothing more to read (for now). Now if you think about that a bit, "
"you'll come to realize a fundamental truth of sockets: *messages must either "
"be fixed length* (yuck), *or be delimited* (shrug), *or indicate how long "
"they are* (much better), *or end by shutting down the connection*. The "
"choice is entirely yours, (but some ways are righter than others)."
msgstr ""
"但是如果你打算在之後的傳輸中重新利用 socket 的話,你需要明白\\ *socket 中是不"
"存在* \\ :abbr:`EOT (傳輸結束)`。重申一次:如果一個 socket 的 ``send`` 或 "
"``recv`` 處理了「零位元組」後回傳,表示連線已經斷開。如果連線\\ *沒有* \\斷"
"開,你可能會永遠處於等待 ``recv`` 的狀態,因為(就目前來說)socket *不會* "
"\\告訴你沒有更多資料可以讀取了。現在,如果你稍微思考一下,你就會意識到 "
"socket 的一個基本事實:*訊息要麼是一個固定的長度(不好的做法),要麼是可以被"
"分隔的(普通的做法),要麼是指定其長度(更好地做法),要麼通過關閉連線來結"
"束。*\\ 完全由你來決定要使用哪種方式(但有些方法比其他方法來的更好)。"
#: ../../howto/sockets.rst:180
msgid ""
"Assuming you don't want to end the connection, the simplest solution is a "
"fixed length message::"
msgstr "假設你不想結束連線,最簡單的方式就是使用固定長度的訊息: ::"
#: ../../howto/sockets.rst:183
msgid ""
"class MySocket:\n"
" \"\"\"demonstration class only\n"
" - coded for clarity, not efficiency\n"
" \"\"\"\n"
"\n"
" def __init__(self, sock=None):\n"
" if sock is None:\n"
" self.sock = socket.socket(\n"
" socket.AF_INET, socket.SOCK_STREAM)\n"
" else:\n"
" self.sock = sock\n"
"\n"
" def connect(self, host, port):\n"
" self.sock.connect((host, port))\n"
"\n"
" def mysend(self, msg):\n"
" totalsent = 0\n"
" while totalsent < MSGLEN:\n"
" sent = self.sock.send(msg[totalsent:])\n"
" if sent == 0:\n"
" raise RuntimeError(\"socket connection broken\")\n"
" totalsent = totalsent + sent\n"
"\n"
" def myreceive(self):\n"
" chunks = []\n"
" bytes_recd = 0\n"
" while bytes_recd < MSGLEN:\n"
" chunk = self.sock.recv(min(MSGLEN - bytes_recd, 2048))\n"
" if chunk == b'':\n"
" raise RuntimeError(\"socket connection broken\")\n"
" chunks.append(chunk)\n"
" bytes_recd = bytes_recd + len(chunk)\n"
" return b''.join(chunks)"
msgstr ""
#: ../../howto/sockets.rst:217
msgid ""
"The sending code here is usable for almost any messaging scheme - in Python "
"you send strings, and you can use ``len()`` to determine its length (even if "
"it has embedded ``\\0`` characters). It's mostly the receiving code that "
"gets more complex. (And in C, it's not much worse, except you can't use "
"``strlen`` if the message has embedded ``\\0``\\ s.)"
msgstr ""
"發送部分的程式碼幾乎可用於任何訊息的傳送方式 - 在 Python 中你發送一個字串,可"
"以用 ``len()`` 來確認他的長度(即使字串包含了 ``\\0`` 字元)。在這裡,主要是"
"接收的程式碼變得更複雜一些。(在 C 語言中,情況沒有變得更糟,只是如果訊息中包"
"含了 ``\\0`` 字元,你就不能使用 ``strlen`` 函式。)"
#: ../../howto/sockets.rst:223
msgid ""
"The easiest enhancement is to make the first character of the message an "
"indicator of message type, and have the type determine the length. Now you "
"have two ``recv``\\ s - the first to get (at least) that first character so "
"you can look up the length, and the second in a loop to get the rest. If you "
"decide to go the delimited route, you'll be receiving in some arbitrary "
"chunk size, (4096 or 8192 is frequently a good match for network buffer "
"sizes), and scanning what you've received for a delimiter."
msgstr ""
"最簡單的改進方法是將訊息的第一個字元表示訊息的類型,並根據訊息的類型來決定訊"
"息的長度。現在你需要使用兩次 ``recv`` - 第一次用於接收(至少)第一個字元來得"
"知長度,第二次用於在迴圈中接收剩下的訊息。如果你決定使用分隔符號的方式,你將"
"會以某個任意的區塊大小進行接收(4096 或 8192 通常是網路緩衝區大小的良好選"
"擇),並在收到的內容中掃描分隔符號。"
#: ../../howto/sockets.rst:231
msgid ""
"One complication to be aware of: if your conversational protocol allows "
"multiple messages to be sent back to back (without some kind of reply), and "
"you pass ``recv`` an arbitrary chunk size, you may end up reading the start "
"of a following message. You'll need to put that aside and hold onto it, "
"until it's needed."
msgstr ""
"需要注意的一個複雜情況是,如果你的通訊協定允許連續發送多個訊息(沒有任何回"
"應),並且你傳遞給 ``recv`` 函式一個任意的區塊大小,最後有可能讀取到下一條訊"
"息的開頭。你需要將其放在一旁並保留下來,直到需要使用的時候。"
#: ../../howto/sockets.rst:237
msgid ""
"Prefixing the message with its length (say, as 5 numeric characters) gets "
"more complex, because (believe it or not), you may not get all 5 characters "
"in one ``recv``. In playing around, you'll get away with it; but in high "
"network loads, your code will very quickly break unless you use two ``recv`` "
"loops - the first to determine the length, the second to get the data part "
"of the message. Nasty. This is also when you'll discover that ``send`` does "
"not always manage to get rid of everything in one pass. And despite having "
"read this, you will eventually get bit by it!"
msgstr ""
"使用長度作為訊息的前綴(例如,使用 5 個數字字元表示)會變得更複雜,因為(信不"
"信由你)你可能無法在一次 ``recv`` 中獲得所有 5 個字元。在一般使用下,可能不會"
"有這個狀況,但在高負載的網路下,除非使用兩個 ``recv`` (第一個用於確定長度,"
"第二個用於取得訊息的資料部分),否則你的程式碼很快就會出現錯誤。這令人非常頭"
"痛。同樣的情況也會讓你發現 ``send`` 並不總能在一次傳輸中完全清除所有內容。儘"
"管已經閱讀了這篇文章,但最終還是無法解決!"
#: ../../howto/sockets.rst:246
msgid ""
"In the interests of space, building your character, (and preserving my "
"competitive position), these enhancements are left as an exercise for the "
"reader. Lets move on to cleaning up."
msgstr ""
"為了節省篇幅、培養你的技能(並保持我的競爭優勢),這些改進方法留給讀者自行練"
"習。現在讓我們開始進行清理工作。"
#: ../../howto/sockets.rst:252
msgid "Binary Data"
msgstr "二進位資料"
#: ../../howto/sockets.rst:254
msgid ""
"It is perfectly possible to send binary data over a socket. The major "
"problem is that not all machines use the same formats for binary data. For "
"example, `network byte order <https://en.wikipedia.org/wiki/"
"Endianness#Networking>`_ is big-endian, with the most significant byte "
"first, so a 16 bit integer with the value ``1`` would be the two hex bytes "
"``00 01``. However, most common processors (x86/AMD64, ARM, RISC-V), are "
"little-endian, with the least significant byte first - that same ``1`` would "
"be ``01 00``."
msgstr ""
"使用 socket 傳輸二進位資料完全是可行的。最主要的問題在於不同機器使用不同的二"
"進位資料格式。例如,`網路二進位順序 <https://en.wikipedia.org/wiki/"
"Endianness#Networking>`_ 採用的是「大端序 big-endian」,所以一個值為 ``1`` "
"的 16 位元整數會表示成兩個 16 進位的位元組 ``00 01``。然而大多數常見的處理器 "
"(x86/AMD64,ARM,RISC-V) 採用的是「小端序 little-endian」,所以相同的 ``1`` "
"會被表示成 ``01 00``。(譯者注:將一個多位數的低位放在較小的位址處,高位放在"
"較大的位址處,則稱小端序;反之則稱大端序。)"
#: ../../howto/sockets.rst:262
msgid ""
"Socket libraries have calls for converting 16 and 32 bit integers - ``ntohl, "
"htonl, ntohs, htons`` where \"n\" means *network* and \"h\" means *host*, "
"\"s\" means *short* and \"l\" means *long*. Where network order is host "
"order, these do nothing, but where the machine is byte-reversed, these swap "
"the bytes around appropriately."
msgstr ""
"Socket 函式庫提供了用於轉換 16 位元和 32 位元整數的函式 - ``ntohl, htonl, "
"ntohs, htons``,其中 \"n\" 表示 *network*,\"h\" 表示 *host*,\"s\" 表示 "
"*short*,\"l\" 表示 *long*。當網路的位元組順序和主機位元組順序相同時,這些函"
"式不會做任何操作,但當主機的位元組順序相反時,這些函式會適當的交換位元組順"
"序。"
#: ../../howto/sockets.rst:268
msgid ""
"In these days of 64-bit machines, the ASCII representation of binary data is "
"frequently smaller than the binary representation. That's because a "
"surprising amount of the time, most integers have the value 0, or maybe 1. "
"The string ``\"0\"`` would be two bytes, while a full 64-bit integer would "
"be 8. Of course, this doesn't fit well with fixed-length messages. "
"Decisions, decisions."
msgstr ""
"在現今的 64 位元機器中,二進位資料的 ASCII 表示通常會比二進位表示要小,這是因"
"為在很多情況下,大多數整數的值為 0 或者 1。例如,字串形式的 ``\"0\"`` 是兩個"
"位元組,而完整的 64 位元整數則是 8 個位元組。當然,這對固定長度的訊息來說不太"
"適合,需要自行決定。"
#: ../../howto/sockets.rst:277
msgid "Disconnecting"
msgstr "結束連線"
#: ../../howto/sockets.rst:279
msgid ""
"Strictly speaking, you're supposed to use ``shutdown`` on a socket before "
"you ``close`` it. The ``shutdown`` is an advisory to the socket at the "
"other end. Depending on the argument you pass it, it can mean \"I'm not "
"going to send anymore, but I'll still listen\", or \"I'm not listening, good "
"riddance!\". Most socket libraries, however, are so used to programmers "
"neglecting to use this piece of etiquette that normally a ``close`` is the "
"same as ``shutdown(); close()``. So in most situations, an explicit "
"``shutdown`` is not needed."
msgstr ""
"嚴格來說,在關閉 socket 前,你應該使用 ``shutdown`` 函式。``shutdown`` 函式是"
"發送給 socket 另一端的一個提醒。根據你傳遞的引數,它可以表示「我不會再發送任"
"何訊息了,但我仍然會持續監聽」,或者是「我不會再繼續監聽了,真讚!」。然而,"
"大多數的 socket 函式庫或程式設計師都習慣忽略這種禮節,因為通常情況下 "
"``close`` 跟 ``shutdown(); close()`` 是一樣的。所以在大多數情況下,不需要再特"
"地使用 ``shutdown`` 了。"
#: ../../howto/sockets.rst:287
msgid ""
"One way to use ``shutdown`` effectively is in an HTTP-like exchange. The "
"client sends a request and then does a ``shutdown(1)``. This tells the "
"server \"This client is done sending, but can still receive.\" The server "
"can detect \"EOF\" by a receive of 0 bytes. It can assume it has the "
"complete request. The server sends a reply. If the ``send`` completes "
"successfully then, indeed, the client was still receiving."
msgstr ""
"有效使用 ``shutdown`` 的一種方式是在類似 HTTP 的交換中,用戶端發送請求後,然"
"後使用 ``shutdown(1)``。這告訴伺服器「這個用戶端已經發送完成,但仍可以接"
"收」。伺服器可以通過接收「零位元組」來檢測 \"EOF\"。這樣它就可以確定已經接收"
"到完整的請求。伺服器發送回覆,如果 ``send`` 成功完成,那麼用戶端確實在持續接"
"收。"
#: ../../howto/sockets.rst:294
msgid ""
"Python takes the automatic shutdown a step further, and says that when a "
"socket is garbage collected, it will automatically do a ``close`` if it's "
"needed. But relying on this is a very bad habit. If your socket just "
"disappears without doing a ``close``, the socket at the other end may hang "
"indefinitely, thinking you're just being slow. *Please* ``close`` your "
"sockets when you're done."
msgstr ""
"Python 更進一步地採取自動關閉的步驟,並且當 socket 被垃圾回收機制回收時,如果"
"需要的話,他會自動執行 ``close``。但依賴這個機制是一個非常不好的習慣,如果你"
"的 socket 在沒有 ``close`` 的情況下消失了,那麼另一端的 socket 可能會認為你只"
"是慢了一步,而無期限的等待。*請務必* \\在使用完畢後使用 ``close`` 關閉你的 "
"sockets。"
#: ../../howto/sockets.rst:302
msgid "When Sockets Die"
msgstr "Sockets 何時銷毀"
#: ../../howto/sockets.rst:304
msgid ""
"Probably the worst thing about using blocking sockets is what happens when "
"the other side comes down hard (without doing a ``close``). Your socket is "
"likely to hang. TCP is a reliable protocol, and it will wait a long, long "
"time before giving up on a connection. If you're using threads, the entire "
"thread is essentially dead. There's not much you can do about it. As long as "
"you aren't doing something dumb, like holding a lock while doing a blocking "
"read, the thread isn't really consuming much in the way of resources. Do "
"*not* try to kill the thread - part of the reason that threads are more "
"efficient than processes is that they avoid the overhead associated with the "
"automatic recycling of resources. In other words, if you do manage to kill "
"the thread, your whole process is likely to be screwed up."
msgstr ""
"使用阻塞式 socket 最糟糕的地方可能是在另一端突然強制關閉(未執行 ``close``)"
"的情況下會發生什麼?你的 socket 很可能會處於阻塞狀態。TCP 是一種可靠的協定,"
"它在放棄連線之前會等待很長很長的時間。如果你正在使用執行緒,整個執行緒基本上"
"已經無法使用。在這方面,你無法做太多事情。只要你不做一些愚蠢的事情,比如在執"
"行阻塞式讀取時持有一個鎖,那麼執行緒並不會消耗太多資源。*不要*\\ 試圖終止執行"
"緒 - 執行緒比行程更有效的部分原因是它們避免了與自動回收資源相關的開銷。換句話"
"說,如果你確實設法終止了執行緒,整個行程可能會出現問題。"
#: ../../howto/sockets.rst:318
msgid "Non-blocking Sockets"
msgstr "非阻塞的 Sockets"
#: ../../howto/sockets.rst:320
msgid ""
"If you've understood the preceding, you already know most of what you need "
"to know about the mechanics of using sockets. You'll still use the same "
"calls, in much the same ways. It's just that, if you do it right, your app "
"will be almost inside-out."
msgstr ""
"如果你已經理解了前面的內容,你已經知道了大部分關於使用 sockets 的機制的所需知"
"識,你仍然會以非常相似的方式使用相同的函式。就這樣而已,如果你做的對,你的程"
"式就會是近乎完美的。"
#: ../../howto/sockets.rst:325
msgid ""
"In Python, you use ``socket.setblocking(False)`` to make it non-blocking. In "
"C, it's more complex, (for one thing, you'll need to choose between the BSD "
"flavor ``O_NONBLOCK`` and the almost indistinguishable POSIX flavor "
"``O_NDELAY``, which is completely different from ``TCP_NODELAY``), but it's "
"the exact same idea. You do this after creating the socket, but before using "
"it. (Actually, if you're nuts, you can switch back and forth.)"
msgstr ""
"在 Python 中可以使用 ``socket.setblocking(False)`` 來設定為非阻塞。在 C 的作"
"法更為複雜(例如,你需要在 BSD 風格的 ``O_NONBLOCK`` 和幾乎沒有區別的 POSIX "
"風格的 ``O_NDELAY`` 之間做出選擇,這與 ``TCP_NODELAY`` 完全不同),但基本思想"
"是一樣的,你要在建立 socket 後但在使用它之前執行此操作。(實際上,如果你願意"
"的話,你甚至可以來回切換。)"
#: ../../howto/sockets.rst:332
msgid ""
"The major mechanical difference is that ``send``, ``recv``, ``connect`` and "
"``accept`` can return without having done anything. You have (of course) a "
"number of choices. You can check return code and error codes and generally "
"drive yourself crazy. If you don't believe me, try it sometime. Your app "
"will grow large, buggy and suck CPU. So let's skip the brain-dead solutions "
"and do it right."
msgstr ""
"主要的機制差異在於 ``send``、``recv``、``connect`` 和 ``accept`` 可能在沒有執"
"行任何操作的情況下就回傳了。你當然有多種選擇。你可以檢查回傳值和錯誤代碼,但"
"這些操作通常會讓自己抓狂。如果你不相信我,不妨試試看。你的應用程式會變得臃"
"腫、錯誤百出,並且占用 CPU。所以,讓我們跳過無腦的解決方案,使用正確的方式。"
#: ../../howto/sockets.rst:339
msgid "Use ``select``."
msgstr "使用 ``select``。"
#: ../../howto/sockets.rst:341
msgid ""
"In C, coding ``select`` is fairly complex. In Python, it's a piece of cake, "
"but it's close enough to the C version that if you understand ``select`` in "
"Python, you'll have little trouble with it in C::"
msgstr ""
"在 C 中,編寫 ``select`` 是非常複雜的,但在 Python 中,這很簡單,並與 C 的版"
"本非常類似,如果你理解了 Python 中的 ``select``,在 C 中處理它時也不會有太大"
"的困難: ::"
#: ../../howto/sockets.rst:345
msgid ""
"ready_to_read, ready_to_write, in_error = \\\n"
" select.select(\n"
" potential_readers,\n"
" potential_writers,\n"
" potential_errs,\n"
" timeout)"
msgstr ""
"ready_to_read, ready_to_write, in_error = \\\n"
" select.select(\n"
" potential_readers,\n"
" potential_writers,\n"
" potential_errs,\n"
" timeout)"
#: ../../howto/sockets.rst:352
msgid ""
"You pass ``select`` three lists: the first contains all sockets that you "
"might want to try reading; the second all the sockets you might want to try "
"writing to, and the last (normally left empty) those that you want to check "
"for errors. You should note that a socket can go into more than one list. "
"The ``select`` call is blocking, but you can give it a timeout. This is "
"generally a sensible thing to do - give it a nice long timeout (say a "
"minute) unless you have good reason to do otherwise."
msgstr ""
"你傳遞給 ``select`` 三個列表:第一個列表包含你可能想要嘗試讀取的所有 "
"sockets;第二個包含所有你可能想要嘗試寫入的 sockets,最後一個(通常為空)包含"
"你想要檢查錯誤的 sockets。你應該注意,一個 socket 可以同時存在於多個列表中。"
"``select`` 呼叫是阻塞的,但你可以設置超時。通常這是一個明智的做法 - 除非有充"
"分的理由,否則給它一個很長的超時(比如一分鐘)。"
#: ../../howto/sockets.rst:360
msgid ""
"In return, you will get three lists. They contain the sockets that are "
"actually readable, writable and in error. Each of these lists is a subset "
"(possibly empty) of the corresponding list you passed in."
msgstr ""
"作為回傳,你將獲得三個列表。它們包含實際上可讀取、可寫入和出錯的 sockets。這"
"些列表中的每一個都是你傳入的相應列表的子集(可能為空)。"
#: ../../howto/sockets.rst:364
msgid ""
"If a socket is in the output readable list, you can be as-close-to-certain-"
"as-we-ever-get-in-this-business that a ``recv`` on that socket will return "
"*something*. Same idea for the writable list. You'll be able to send "
"*something*. Maybe not all you want to, but *something* is better than "
"nothing. (Actually, any reasonably healthy socket will return as writable - "
"it just means outbound network buffer space is available.)"
msgstr ""
"如果一個 socket 在輸出的可讀列表中,你可以幾乎確定,在這個業務中我們能夠得到"
"的最接近確定的事情是,對該 socket 的 ``recv`` 呼叫將會回傳一些\\ *內容*。對於"
"可寫列表,也是同樣的想法。你將能夠發送一些 *內容*。也許不是全部,但\\ *一些內"
"容*\\ 總比什麼都沒有好。(實際上,任何比較正常的 socket 都會以可寫的方式回傳 "
"- 這只是意味者「外送網路 (outbound network)」的緩衝空間是可用的。)"
#: ../../howto/sockets.rst:371
msgid ""
"If you have a \"server\" socket, put it in the potential_readers list. If it "
"comes out in the readable list, your ``accept`` will (almost certainly) "
"work. If you have created a new socket to ``connect`` to someone else, put "
"it in the potential_writers list. If it shows up in the writable list, you "
"have a decent chance that it has connected."
msgstr ""
"如果你有一個「伺服器端」socket,請將其放在 potential_readers 列表中,如果它在"
"可讀列表中出現,你的 ``accept`` 呼叫(幾乎可以確定)會成功。如果你建立了一個"
"新的 socket 去 ``connect`` 到其他地方,請將它放在 potential_writers 列表中,"
"如果它在可寫列表中出現,那麼他有可能已經連接上了。"
#: ../../howto/sockets.rst:377
msgid ""
"Actually, ``select`` can be handy even with blocking sockets. It's one way "
"of determining whether you will block - the socket returns as readable when "
"there's something in the buffers. However, this still doesn't help with the "
"problem of determining whether the other end is done, or just busy with "
"something else."
msgstr ""
"實際上,即使是使用阻塞式 socket 的情況下,``select`` 也很方便。這是一種判斷是"
"否會被阻塞的方法之一 - 當緩衝區中有某些內容時, socket 會回傳為可讀。然而,這"
"仍然無法解決判斷另一端是否完成,或者只是忙於其他事情的問題。"
#: ../../howto/sockets.rst:382
msgid ""
"**Portability alert**: On Unix, ``select`` works both with the sockets and "
"files. Don't try this on Windows. On Windows, ``select`` works with sockets "
"only. Also note that in C, many of the more advanced socket options are done "
"differently on Windows. In fact, on Windows I usually use threads (which "
"work very, very well) with my sockets."
msgstr ""
"**可移植性警告**:在 Unix 上,``select`` 同時適用於 sockets 和文件。但請不要"
"在 Windows 上嘗試這麼做,在 Windows 上,``select`` 只適用於 sockets。同時,請"
"注意,在 C 語言中,許多更進階的 socket 選項在 Windows 上有不同的實現方式。實"
"際上,在 Windows 上,我通常會使用執行緒(這非常,非常有效)與我的 sockets 一"
"起使用。"