代码位置
https://github.com/duganlx/fopnp/tree/m/py3
使用自环接口的UDP服务器和客户端
文件位置:fopnp/py3/chapter02/udp_local.py
import argparse, socket
from datetime import datetime
MAX_BYTES = 65535
def server(port):
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind(('127.0.0.1', port))
print('Listening at {}'.format(sock.getsockname()))
while True:
data, address = sock.recvfrom(MAX_BYTES)
text = data.decode('ascii')
print('The client at {} says {!r}'.format(address, text))
text = 'Your data was {} bytes long'.format(len(data))
data = text.encode('ascii')
sock.sendto(data, address)
def client(port):
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
text = 'The time is {}'.format(datetime.now())
data = text.encode('ascii')
sock.sendto(data, ('127.0.0.1', port))
print('The OS assigned me the address {}'.format(sock.getsockname()))
data, address = sock.recvfrom(MAX_BYTES) # Danger! See Chapter 2
text = data.decode('ascii')
print('The server {} replied {!r}'.format(address, text))
if __name__ == '__main__':
choices = {'client': client, 'server': server}
parser = argparse.ArgumentParser(description='Send and receive UDP locally')
parser.add_argument('role', choices=choices, help='which role to play')
parser.add_argument('-p', metavar='PORT', type=int, default=1060,
help='UDP port (default 1060)')
args = parser.parse_args()
function = choices[args.role]
function(args.p)
运行效果
# 第一个cmd
python udp_local.py server
Listening at ('127.0.0.1', 1060)
The client at ('127.0.0.1', 51680) says 'The time is 2019-12-30 16:42:32.993255'
The client at ('127.0.0.1', 51681) says 'The time is 2019-12-30 16:42:39.982656'
# 第二个cmd
python udp_local.py client
The OS assigned me the address ('0.0.0.0', 51680)
The server ('127.0.0.1', 1060) replied 'Your data was 38 bytes long'
# 第三个cmd
python udp_local.py client
The OS assigned me the address ('0.0.0.0', 51681)
The server ('127.0.0.1', 1060) replied 'Your data was 38 bytes long'
运行在不同机器上的UDP服务器与客户端
文件位置:fopnp/py3/chapter02/udp_remote.py
import argparse, random, socket, sys
MAX_BYTES = 65535
def server(interface, port):
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind((interface, port))
print('Listening at', sock.getsockname())
while True:
data, address = sock.recvfrom(MAX_BYTES)
if random.random() < 0.5:
print('Pretending to drop packet from {}'.format(address))
continue
text = data.decode('ascii')
print('The client at {} says {!r}'.format(address, text))
message = 'Your data was {} bytes long'.format(len(data))
sock.sendto(message.encode('ascii'), address)
def client(hostname, port):
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.connect((hostname, port))
print('Client socket name is {}'.format(sock.getsockname()))
delay = 0.1 # seconds
text = 'This is another message'
data = text.encode('ascii')
while True:
sock.send(data)
print('Waiting up to {} seconds for a reply'.format(delay))
sock.settimeout(delay)
try:
data = sock.recv(MAX_BYTES)
except socket.timeout as exc:
delay *= 2 # wait even longer for the next request
if delay > 2.0:
raise RuntimeError('I think the server is down') from exc
else:
break # we are done, and can stop looping
print('The server says {!r}'.format(data.decode('ascii')))
if __name__ == '__main__':
choices = {'client': client, 'server': server}
parser = argparse.ArgumentParser(description='Send and receive UDP,'
' pretending packets are often dropped')
parser.add_argument('role', choices=choices, help='which role to take')
parser.add_argument('host', help='interface the server listens at;'
' host the client sends to')
parser.add_argument('-p', metavar='PORT', type=int, default=1060,
help='UDP port (default 1060)')
args = parser.parse_args()
function = choices[args.role]
function(args.host, args.p)
运行效果
# cmd1
python udp_remote.py server ""
Listening at ('0.0.0.0', 1060)
Pretending to drop packet from ('127.0.0.1', 53102)
Pretending to drop packet from ('127.0.0.1', 53102)
Pretending to drop packet from ('127.0.0.1', 53102)
The client at ('127.0.0.1', 53102) says 'This is another message'
# cmd2
python udp_remote.py client localhost
Client socket name is ('127.0.0.1', 53102)
Waiting up to 0.1 seconds for a reply
Waiting up to 0.2 seconds for a reply
Waiting up to 0.4 seconds for a reply
Waiting up to 0.8 seconds for a reply
The server says 'Your data was 23 bytes long'
发送大型UDP数据包
文件位置:fopnp/py3/chapter02/big_sender.py
import argparse, socket, sys
# Inlined constants, because Python 3.6 has dropped the IN module.
class IN:
IP_MTU = 14
IP_MTU_DISCOVER = 10
IP_PMTUDISC_DO = 2
if sys.platform != 'linux':
print('Unsupported: Can only perform MTU discovery on Linux',
file=sys.stderr)
sys.exit(1)
def send_big_datagram(host, port):
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.setsockopt(socket.IPPROTO_IP, IN.IP_MTU_DISCOVER, IN.IP_PMTUDISC_DO)
sock.connect((host, port))
try:
sock.send(b'#' * 999999)
except socket.error:
print('Alas, the datagram did not make it')
max_mtu = sock.getsockopt(socket.IPPROTO_IP, IN.IP_MTU)
print('Actual MTU: {}'.format(max_mtu))
else:
print('The big datagram was sent!')
if __name__ == '__main__':
parser = argparse.ArgumentParser(description='Send UDP packet to get MTU')
parser.add_argument('host', help='the host to which to target the packet')
parser.add_argument('-p', metavar='PORT', type=int, default=1060,
help='UDP port (default 1060)')
args = parser.parse_args()
send_big_datagram(args.host, args.p)
运行效果
$ python3 big_sender.py www.example.com
Alas, the datagram did not make it
Actual MTU: 1500
UDP广播
文件位置:fopnp/py3/chapter02/udp_broadcast.py
import argparse, socket
BUFSIZE = 65535
def server(interface, port):
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind((interface, port))
print('Listening for datagrams at {}'.format(sock.getsockname()))
while True:
data, address = sock.recvfrom(BUFSIZE)
text = data.decode('ascii')
print('The client at {} says: {!r}'.format(address, text))
def client(network, port):
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
text = 'Broadcast datagram!'
sock.sendto(text.encode('ascii'), (network, port))
if __name__ == '__main__':
choices = {'client': client, 'server': server}
parser = argparse.ArgumentParser(description='Send, receive UDP broadcast')
parser.add_argument('role', choices=choices, help='which role to take')
parser.add_argument('host', help='interface the server listens at;'
' network the client sends to')
parser.add_argument('-p', metavar='port', type=int, default=1060,
help='UDP port (default 1060)')
args = parser.parse_args()
function = choices[args.role]
function(args.host, args.p)
运行效果
# cmd1
python udp_broadcast.py server ""
Listening for datagrams at ('0.0.0.0', 1060)
The client at ('192.168.19.202', 63753) says: 'Broadcast datagram!'
The client at ('192.168.19.202', 63754) says: 'Broadcast datagram!'
# cmd2
python udp_broadcast.py client 192.168.19.255
# cmd3
python udp_broadcast.py client "<broadcast>"