python udp_Python网络编程学习笔记(一)——UDP

代码清单2-1 使用自环接口的UDP服务器和客户端

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)

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)

服务器首先创建了一个空套接字,这个套接字没有与任何IP地址或端口号绑定,也没有进行任何连接。但该套接字还是标记了所属的特定类别:协议族AF_INET以及数据报类型SOCK_DGRAM。AF_INET为Ipv4协议的套接字类型,SOCK_DGRAM为UDP协议。

sock.bind()命令请求绑定一个UDP网络地址,绑定失败(如端口号被占用)则会抛出异常

format为字符串格式化命令。{!r}对应repr()(这里不懂)。sock.getsockname()获取该套接字的二元组。

while True:进入循环,不断运行recvfrom()接受消息。MAX_BYTES为可接受消息的最大值。decode解码,encode编码,sendto发送消息。其中address对应一个二元组,记录发送该消息的主机的ip地址和端口号,如(127.0.0.1, 1060)

客户端创建套接字后,并没有与ip地址和端口号绑定,操作系统会随机分配一个端口号。

代码清单2-2 运行在不同机器上的UDP服务器与客户端

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)

hostname = sys.argv[2]

sock.connect((hostname, port))

print('Client socket name is {}'.format(sock.getsockname()))

delay = 0.1

text = 'This is anthor message'

data = text.encode('ascii')

while True:

sock.send(data)

print('Wating up to {} seconds for a delay'.format(delay))

sock.settimeout(delay)

try:

data = sock.recv(MAX_BYTES)

except socket.timeout:

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')))

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 listen 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)

server服务器端,sock.bind((interface, port))绑定本地接口,interface为本地IP地址,设成空字符串表示任何本地接口。

while True:循环,随机丢弃连接请求,只处理一半消息。

sys.argv[2],获取命令行参数中的第三项(命令行 python udp_2_2.py client 127.0.0.1,第三项为127.0.0.1)。

sock.connect((hostname, port))连接服务器端口。当客户端尝试使用套接字时,操作系统会为其随机分配一个临时端口(隐式绑定)。此外,运行connect(),如果操作系统发现传入的数据包返回地址与已连接的地址不同,则会将该数据包丢弃,解决了客户端混杂性的问题。

指数退避技术:尝试重发数据包的频率越来越低。

代码清单2-3 发送大型UDP数据包

import IN, argparse, socket

if not hasattr(IN, 'IP_MTU'):

raise RuntimeError('cannot perform MTU discovery on this combination''of operating system and Python distribution')

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'#' * 65000)

except socket.error:

print('The datagam 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)

本程序没有顺利执行,显示没有import IN 失败

代码清单2-4,使用UDP广播

import socket, argparse

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 listen at;''network the cllient 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)

客户端和服务器端设置并不复杂。服务器端只负责接收数据,客户端只负责发送数据。

客户端setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1),setsockopt为设置套接字选项,SO_BROADCAST该选项允许发送并接收UDP数据包

服务器端运行代码后开始监听:

python udp_2_4.py server ""

客户端运行代码

python udp_2_4.py client 192.168.1.129

向本地192.168.1.129地址发送数据包

运行代码

python udp_2_4.py client 192.168.1.255

或者

python udp_2_4.py client ""

发送广播。

其中''为Python特殊主机名,表示广播地址。

你可能感兴趣的:(python,udp)