1> 基本通信
不需要像TCP一样先建立连接,直接创建socket对象,绑定IP和端口,就能收发数据了,客户端就更简单,
创建对象就行,如下
为什么是recvfrom,sendto?
因为通讯不基于连接,服务端需要知道是谁发来的消息,才能回复,所以recvfrom得到的对象包含 (数据和
客户端IP与端口) ,同理,sendto里面也包含数据和 对端IP和端口,因为没有连接,所以需要指明这个包是发往
哪里 而是之前的TCP协议是建立好了通道再进行数据传送,所以不必IP和端口信息,因为通过通道就是发往对
端的,很明确的知道对端是谁。
2>数据包协议,为何没有粘包现象
可以看到,客户端发了5 个字节的hello,但是服务端收取上限为2,windows下报错了,说缓冲区比数据包小,
linux下直接收取2个字节,其他的丢弃UDP没有通道的概念,自然不有存放残留数据的机制,他每个包都是独立
封装并发送,所以不会有粘包现象,所以它也叫数据报协议。
所以它的收发 也是 一对一的。
3>并且你可以发送空,因为就算你内容为空,UDP自带头部信息(对端IP和端口等),实际上这条消息(这个数据报)并
不为空(因为包含头部大小),所以操作系统是会帮你发送的。
4>应用场景
绝大多数的应用都是基于TCP的,但也有些UDP通信的场景或应用,如QQ,DNS域名解析(输入网址,DNS服务器
会转换成IP+端口再访问,这个时候对数据的安全性啥的要求并不太高, 请求断就断了,我再发一次就是,但是
追求速度,速度正是UDP的长处)等类似一些这样的场景。
二>基于TCP实现文件上传和下载(面向对象版)
服务端
class Ftp_server(): ''' 服务端的文件操作类,包含上传,下载,运行服务等功能 ''' def __init__(self, addr, port): self.addr = addr self.port = port self.socket_obj = socket.socket() self.serfile_dir = conf['server']['file_dir'] self.socket_obj.bind((self.addr, self.port)) self.socket_obj.listen(5) def wait_client_conn(self): ''' 服务端启动函数,这里建立连接,并且等待客户端的指令,反射至对应的函数 ''' while True: print('文件服务器已经启动,等待客户端接入...') conn, data = self.socket_obj.accept() while True: try: cmd = conn.recv(1024) if not cmd:continue operation = cmd.decode().split()[0] file_name = cmd.decode().split()[1] if hasattr(self, operation): func = getattr(self, operation) func(conn, file_name) except ConnectionResetError: print('客户端已关闭连接!') break