import argparse
import random
import socket
MAX_BYTES =65535defserver(interface, port):
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)# 建立socket连接,使用IPv4及UDP协议
sock.bind((interface, port))# 与(IPv4,port)地址对进行绑定print('Listening at', sock.getsockname())# 返回自己绑定的地址对whileTrue:
data, address = sock.recvfrom(MAX_BYTES)# 返回接收到的数据,以及发送端的IPv4地址if random.random()<0.5:# 随机生成0-1的随机数,有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)# 将回复发送给客户端defclient(hostname, port):
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.connect((hostname, port))# 与服务器建立连接,有地一定概率会连接超时从而返回超时错误print('Client socket name is {}'.format(sock.getsockname()))# 打印自己的IPv4地址及端口号
delay =0.1# 延迟0.1s
text ='This is another message'
data = text.encode('ascii')# 将要发送的信息进行编码whileTrue:
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:
delay = delay*2# 再等一段时间发起下一次请求if delay >2.0:raise RuntimeError('I think the server is down')# 如果超过两次依旧没有回复,认为服务器坏掉了else:break# 直接不再循环,停止运行print('The server says {!r}'.format(data.decode('ascii')))
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')# 第二个参数既是服务器的IPv4地址,也是客户端要发送的地址
parser.add_argument('-p', metavar='PORT',type=int, default=1060,help='UDP port(default = 1060)')# 第三个参数1是服务器UDP的端口号
args = parser.parse_args()# 将输入的参数赋给args
function = choices[args.role]
function(args.host, args.p)