简单好玩易懂 !Python 之UDP网络编程

一、什么是UDP?

UDP全称User Datagram Protocol,中文是用户数据报协议。是Internet协议集中的一种无连接传输层协议,提供面向事务简单不可靠传送服务。简单来说,UDP就是传输层的一种传输协议,传输时不需要与目标主机建立连接,只要知道对方的ip和端口号便可直接传输。我们可以将UDP比作写信:每次寄信都需要写入邮寄地址和邮寄编号,寄信之前你不必打电话通知对方便可直接邮寄。
我们大体的了解了一下UDP的定义,那么接下来我们来看一下“写信模式”有哪些特点吧。

二、UDP的特点

1.不可靠性:

UDP尽最大努力交付,但不保证一定交付成功。也就是说,通过UDP协议传输的数据不能保证其完整性可到达性。不管到达还是不到达不会通知主机。因此不需要维护主机和目标主机之间复杂的连接关系。通俗点来讲,就好比古代,你要和在异地的女朋友飞鸽传书(额……古代的异地恋……),你只管将信封寄出去,而你不能知道鸽子是否在路途中遭遇了什么,信封是否可以传达到(万一遇到贝爷,那就蛋糕了……)

既然UDP 具有不可靠性,那么UDP是否就没有存在的必要性了呢?答案是否定的。UDP不像tcp那样在其中捆绑了大量了安全保障功能,因此UDP在传输过程中就不会有很大的系统开销,极大的降低了执行时间,从而提高了传输效率,这种效率是tcp难以望其项背的。由于UDP的传输速度的优势,使得UDP对于一些实时应用很重要。

 2.无连接性:

UDP是无连接的,即通信前是不需要创建连接的,目标主机的运输层收到之后不给出确认。接着上一个比喻,你放飞鸽子时是不需要通知你女朋友的(好像也没办法通知……);鸽子即便将信封传达到了,她也无法立即通知你“我已经收到了”。

3.面向报文:

对应用层传下来的报文和对ip网络层交上来的报文都不进行改动,直接添加/去除首部后进行下一步操作。报文过长则在ip层会被分片;报文过短则在ip层的数据报的首部会很长。在这里就不再使用飞鸽传书了,使用飞鸽传书的升级版--写信(emmm……穿越了):当你写信的时候将信(数据字段)放在信封(首部)里即可,当写的内容太多时,会使用好几张信纸;当内容太少时,字数可能还不如信封上的字多。而当你女盆友收到信后,直接将信封拆开就可以看你们的“小情书”了。

4.没有拥塞机制:

网络出现拥塞不会降低源主机的发送速率,对某些实时性应用很重要。如IP电话、实时视频等。同时允许在网络拥塞时丢失一些数据,但不允许数据有太大的时延

因为UDP没有拥塞机制,因此当过多的源主机同时向网络发送高速率的实时数据时,很有可能造成拥塞,从而导致数据丢失。对于一些实时应用,可以对这种不可靠传输进行适当改进,增加一些保护、修复措施,如前向纠错重传丢失的报文

5.没有明确意义上的客户端与服务器端

你既可以写信也可以收信,两者没有太大区别(爱情本就是相互的嘛……)。

6.支持一对一,一对多,多对一、多对多的交互通信

  • 单播:单播就是一对一的通讯模式。发送方需要指定对方的ip和端口,只有对应的机器才能接收发送的数据,不会对子网内其它机器产生任何影响。
  • 多播:多播就是一对多的通讯模式。一台机器对子网内所有机器中的部分机器进行通讯。这些机器都可以接收到由主机发送的数据,而子网中未指定的机器不受影响。
  • 广播:当多播中的机器数量为子网中所有机器数时,此时的“多播”不再称为多播,而是广播。ip协议中规定,广播只能在一个子网中进行,而不能在广域网中进行广播。
  • 组播:同样,组播也是一对多的通讯模式。一台机器加入一个组播ip后,之后向组播ip发送的数据,在组播中的机器都能收到该数据。

7.首部开销小,只有8个字节

UDP由两部分组成,一部分是首部字段,另一部分是数据字段
首部字段仅有8字节,分为4个字段

  • 源端口:  源端口号。在需要对方回信时选用,不需要时可用全0。
  • 目的端口: 目的端口号。在终点交付时使用。
  • 长度:   udp用户数据报的长度,其最小值为8(仅首部)。
  • 检验和:   检测udp用户数据报在传输中是否有错,若有错就丢弃。

三、socket通信

其实,创建socket的方式和读写文件的方式类似,还记如何得读写文件吗?我们来一起回忆一下:

f  = open()   # 打开文件
f.read()/f.write()    #  对文件进行操作
f.close()   # 关闭文件   

下面我们再看一下创建socket的方式:

1.导入socket模块

import socket

2.创建套接字对象(socket)

t = socket.socket(socket.AF_INET,sockeet.SOCK_DGRAM)

其中创创建套接字时socket需要两个参数socket(AddressFamily,Type)

AdressFamily:  可以选择AF_INET(用于Internet进程间的通信)或者AF_UNIX(同一台机器进程间通信),实际中常用AF_INET.
Type:   可以是SOCK_STREAM(流式套接字,主要用于TCP协议)或者SOCK_DGRAM(数据报套接字,主要用UDP协议).

3.绑定本地信息(bind)

t.bind(("",5678))   #参数为一个含有两位元素的元组,第一个元素为本机ip,默认自动分配;第二个元素为端口号。

4.使用套接字接收/发送数据(recvfrom/sendto)

# 1.发送数据
data = ""   # 需要发送的数据
t.sendto(data.encode("转码"),("ip",port))   # 两个参数:参数1为传输数据,参数2为元组("目标ip",目标端口)

# 2.接收数据
recv _data, dest_ip_and_port = t.recvfrom(1024)   # 返回数据:数据内容,对方的(ip和端口号)

关闭套接字(close)

t.close()  

关注我,玩转python!

猜你喜欢

转载自blog.csdn.net/qq_45807032/article/details/105139292