Python 网络编程之 UDP 协议

UDP 和 TCP 的区别

  TCP UDP
链接性 面向链接 面向无链接
传输可靠性 可靠 不可靠
传输模式 数据报
应用场景 传输大量的数据 少许数据
速度

TCP:python

TCP 的可靠体如今传输数据以前,会有三次握手来创建链接。在数据传完后,还会断开链接用来节约系统资源。在数据传递时,有确认机制、重传机制、拥塞控制机制以保证传输的可靠性,但这些机制都会消耗大量的时间和系统资源,每一个链接都会占用系统的 CPU、内存等硬件资源,因此也致使 TCP 容易被人利用,好比 DDOS、CC 等攻击。编程

通常用于文件传输、收发邮件或远程登陆等对数据准确性要求高的场景。segmentfault

UDP:服务器

UDP 没有 TCP 那些可靠的机制,因此在数据传递时,若是网络质量很差,就会很容易丢包。但 UDP 也是没法避免攻击的,好比:UDP Flood 攻击。网络

通常用于即时通信、在线视频、网络电话等对传输效率要求高,但对准确性要求相对低的场景。socket

  • 面向有链接型

面向有链接型

发送数据以前,须要在收发主机之间创建一条通讯线路,在通讯传输先后,专门进行创建和断开链接的处理,若是与对端之间没法通讯,可避免发送无谓的数据。函数

  • 面向无链接型

面向无链接型

这种类型不要求创建和断开链接,发送端可任什么时候候发送数据,接收端也不知道本身什么时候从哪里接受数据,这种状况下,接收端须要时常确认是否收到数据,彼此也不须要确认对方是否存在。编码

关于 TCP 网络编程的实现请参考个人另外一篇博文 Socket 通讯原理spa

UDP 网络编程实现

面向无链接的 UDP 时序图code

UDP 通讯过程

建立 Socket

sock = socket.socket(family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None)
  1. family -> 地址族

    • socket.AF_UNIX: 用于同一台机器上的进程通讯(既本机通讯)
    • socket.AF_INET: 用于服务器与服务器之间的网络通讯
    • socket.AF_INET6: 基于 IPV6 方式的服务器与服务器之间的网络通讯
  2. type -> Socket 对象的类型

    • socket.SOCK_STREAM: 基于 TCP 的流式 Socket 通讯
    • socket.SOCK_DGRAM: 基于 UDP 的数据报式 Socket 通讯
    • socket.SOCK_RAW: 原始套接字,普通的套接字没法处理 ICMP、IGMP 等网络报文,而 SOCK_RAW 能够;其次 SOCK_RAW 也能够处理特殊的 IPV4 报文;此外,利用原始套接字,能够经过 IP_HDRINCL 套接字选项由用户构造 IP 头
    • socket.SOCK_SEQPACKET: 可靠的连续数据包服务
  3. proto -> 协议编号,默认是 0,通常能够忽略该参数
  4. fileno -> Socket 的文件描述符,若是指定了 fileno,则其余参数将被忽略,返回指定文件描述符的 Socket。
建立 TCP Socket:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

建立 UDP Socket:
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

UDP 通讯

sock.recvfrom(bufsize[, flags])

接受 UDP 套接字的数据,与 recv() 相似,但返回值是 tuple(data, address)。其中 data 是包含接受数据的字符串,address 是发送数据的 Socket 地址

注意协议接收到的数据可能大于 buf 的长度,因此在这种状况下要调用几回 recv 函数才能把 Socket 接收缓冲区中的数据 copy 完。recv 函数仅仅是 copy 数据,真正接收数据是由协议来完成的。
sock.sendto(bytes, address)

发送 UDP 数据,将数据发送到 Socket,address 形式为 tuple(ipaddr, port),指定远程地址发送,返回值是发送的字节数

Python 2.x 发送的报文是 str 类型,Python 3.x 发送的报文是 bytes 类型,在发送前要记得编码。

客户端代码

import socket

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
address = ('127.0.0.1', 8020)

while True:
    msg = input('Wanna send: ')
    if not msg:
        break
    sock.sendto(bytes(msg, 'utf-8'), address)  # Return the number of bytes sent
    data, addr = sock.recvfrom(1024)
    data = data.decode('utf-8')
    print('Response:', data)

sock.close()

服务端代码

import socket
import time

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind(('127.0.0.1', 8020))

print('waiting for message...')
while True:
    data, addr = sock.recvfrom(1024)
    data = data.decode('utf-8')
    print('Got message from', addr)
    print('Received message:', data)
    sock.sendto(bytes('[%s] %s' % (time.ctime(), data), 'utf-8'), addr)

sock.close()
相关文章
相关标签/搜索