Skip to content

Commit 585e80d

Browse files
committed
11.03 小节完成~
1 parent 03987ad commit 585e80d

File tree

1 file changed

+78
-78
lines changed

1 file changed

+78
-78
lines changed

source/c11/p03_creating_udp_server.rst

Lines changed: 78 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -5,94 +5,94 @@
55
----------
66
问题
77
----------
8-
You want to implement a server that communicates with clients using the UDP Internet
9-
protocol.
8+
你想实现一个基于UDP协议的服务器来与客户端通信。
109

1110
|
1211
1312
----------
1413
解决方案
1514
----------
16-
As with TCP, UDP servers are also easy to create using the socketserver library. For
17-
example, here is a simple time server:
18-
19-
from socketserver import BaseRequestHandler, UDPServer
20-
import time
21-
22-
class TimeHandler(BaseRequestHandler):
23-
def handle(self):
24-
print('Got connection from', self.client_address)
25-
# Get message and client socket
26-
msg, sock = self.request
27-
resp = time.ctime()
28-
sock.sendto(resp.encode('ascii'), self.client_address)
29-
30-
if __name__ == '__main__':
31-
serv = UDPServer(('', 20000), TimeHandler)
32-
serv.serve_forever()
33-
34-
As before, you define a special handler class that implements a handle() method for
35-
servicing client connections. The request attribute is a tuple that contains the incoming
36-
datagram and underlying socket object for the server. The client_address contains
37-
the client address.
38-
To test the server, run it and then open a separate Python process that sends messages
39-
to it:
40-
41-
>>> from socket import socket, AF_INET, SOCK_DGRAM
42-
>>> s = socket(AF_INET, SOCK_DGRAM)
43-
>>> s.sendto(b'', ('localhost', 20000))
44-
0
45-
>>> s.recvfrom(8192)
46-
(b'Wed Aug 15 20:35:08 2012', ('127.0.0.1', 20000))
47-
>>>
15+
跟TCP一样,UDP服务器也可以通过使用 ``socketserver`` 库很容易的被创建。
16+
例如,下面是一个简单的时间服务器:
17+
18+
.. code-block:: python
19+
20+
from socketserver import BaseRequestHandler, UDPServer
21+
import time
22+
23+
class TimeHandler(BaseRequestHandler):
24+
def handle(self):
25+
print('Got connection from', self.client_address)
26+
# Get message and client socket
27+
msg, sock = self.request
28+
resp = time.ctime()
29+
sock.sendto(resp.encode('ascii'), self.client_address)
30+
31+
if __name__ == '__main__':
32+
serv = UDPServer(('', 20000), TimeHandler)
33+
serv.serve_forever()
34+
35+
跟之前一样,你先定义一个实现 ``handle()`` 特殊方法的类,为客户端连接服务。
36+
这个类的 ``request`` 属性是一个包含了数据报和底层socket对象的元组。``client_address`` 包含了客户端地址。
37+
38+
我们来测试下这个服务器,首先运行它,然后打开另外一个Python进程向服务器发送消息:
39+
40+
.. code-block:: python
41+
42+
>>> from socket import socket, AF_INET, SOCK_DGRAM
43+
>>> s = socket(AF_INET, SOCK_DGRAM)
44+
>>> s.sendto(b'', ('localhost', 20000))
45+
0
46+
>>> s.recvfrom(8192)
47+
(b'Wed Aug 15 20:35:08 2012', ('127.0.0.1', 20000))
48+
>>>
4849
4950
|
5051
5152
----------
5253
讨论
5354
----------
54-
A typical UDP server receives an incoming datagram (message) along with a client
55-
address. If the server is to respond, it sends a datagram back to the client. For trans‐
56-
mission of datagrams, you should use the sendto() and recvfrom() methods of a
57-
58-
socket. Although the traditional send() and recv() methods also might work, the for‐
59-
mer two methods are more commonly used with UDP communication.
60-
Given that there is no underlying connection, UDP servers are often much easier to
61-
write than a TCP server. However, UDP is also inherently unreliable (e.g., no “connec‐
62-
tion” is established and messages might be lost). Thus, it would be up to you to figure
63-
out how to deal with lost messages. That’s a topic beyond the scope of this book, but
64-
typically you might need to introduce sequence numbers, retries, timeouts, and other
65-
mechanisms to ensure reliability if it matters for your application. UDP is often used in
66-
cases where the requirement of reliable delivery can be relaxed. For instance, in real-
67-
time applications such as multimedia streaming and games where there is simply no
68-
option to go back in time and recover a lost packet (the program simply skips it and
69-
keeps moving forward).
70-
The UDPServer class is single threaded, which means that only one request can be serv‐
71-
iced at a time. In practice, this is less of an issue with UDP than with TCP connections.
72-
However, should you want concurrent operation, instantiate a ForkingUDPServer or
73-
ThreadingUDPServer object instead:
74-
75-
from socketserver import ThreadingUDPServer
76-
...
77-
if __name__ == '__main__':
78-
serv = ThreadingUDPServer(('',20000), TimeHandler)
79-
serv.serve_forever()
80-
81-
Implementing a UDP server directly using sockets is also not difficult. Here is an
82-
example:
83-
84-
from socket import socket, AF_INET, SOCK_DGRAM
85-
import time
86-
87-
def time_server(address):
88-
sock = socket(AF_INET, SOCK_DGRAM)
89-
sock.bind(address)
90-
while True:
91-
msg, addr = sock.recvfrom(8192)
92-
print('Got message from', addr)
93-
resp = time.ctime()
94-
sock.sendto(resp.encode('ascii'), addr)
95-
96-
if __name__ == '__main__':
97-
time_server(('', 20000))
55+
一个典型的UPD服务器接收到达的数据报(消息)和客户端地址。如果服务器需要做应答,
56+
它要给客户端回发一个数据报。对于数据报的传送,
57+
你应该使用socket的 ``sendto()`` 和 ``recvfrom()`` 方法。
58+
尽管传统的 ``send()`` 和 ``recv()`` 也可以达到同样的效果,
59+
但是前面的两个方法对于UDP连接而言更普遍。
60+
61+
由于没有底层的连接,UPD服务器相对于TCP服务器来讲实现起来更加简单。
62+
不过,UDP天生是不可靠的(因为通信没有建立连接,消息可能丢失)。
63+
因此需要由你自己来决定该怎样处理丢失消息的情况。这个已经不在本书讨论范围内了,
64+
不过通常来说,如果可靠性对于你程序很重要,你需要借助于序列号、重试、超时以及一些其他方法来保证。
65+
UDP通常被用在那些对于可靠传输要求不是很高的场合。例如,在实时应用如多媒体流以及游戏领域,
66+
无需返回恢复丢失的数据包(程序只需简单的忽略它并继续向前运行)。
67+
68+
``UDPServer`` 类是单线程的,也就是说一次只能为一个客户端连接服务。
69+
实际使用中,这个无论是对于UDP还是TCP都不是什么大问题。
70+
如果你想要并发操作,可以实例化一个 ``ForkingUDPServer`` 或 ``ThreadingUDPServer`` 对象:
71+
72+
.. code-block:: python
73+
74+
from socketserver import ThreadingUDPServer
75+
76+
if __name__ == '__main__':
77+
serv = ThreadingUDPServer(('',20000), TimeHandler)
78+
serv.serve_forever()
79+
80+
直接使用 ``socket`` 来是想一个UDP服务器也不难,下面是一个例子:
81+
82+
.. code-block:: python
83+
84+
from socket import socket, AF_INET, SOCK_DGRAM
85+
import time
86+
87+
def time_server(address):
88+
sock = socket(AF_INET, SOCK_DGRAM)
89+
sock.bind(address)
90+
while True:
91+
msg, addr = sock.recvfrom(8192)
92+
print('Got message from', addr)
93+
resp = time.ctime()
94+
sock.sendto(resp.encode('ascii'), addr)
95+
96+
if __name__ == '__main__':
97+
time_server(('', 20000))
9898

0 commit comments

Comments
 (0)