一、UCP大文件上传(解决粘包问题)
①客户端
import socket, os, json, struct client = socket.socket() client.connect(('127.0.0.1', 8080)) # 文件大小 file_size = os.path.getsize(r'D:Desktopwendang.txt') # 文件名 file_name = '计算机五大.txt' # 然后定义一个字典 d = { 'file_name': file_name, 'file_size': file_size, 'msg': '成功上传' } # 定义好字典后,先去转一下json,然后encode data_bytes = json.dumps(d).encode('utf-8') # 制作字典的报头 header = struct.pack('i', len(data_bytes)) # 发送报头 client.send(header) # 发送字典 client.send(data_bytes) # 然后发送真实数据:打开文件,一行一行读取出来,一行一行的发送 with open(r'D:Desktopwendang.txt', 'rb') as f: for line in f: client.send(line)
②服务端
import socket, json, struct server = socket.socket() server.bind(('127.0.0.1', 8080)) server.listen(5) while True: conn, addr = server.accept() while True: try: # 先接收报头 header = conn.recv(4) # 解析报头,获取字典长度 header_len = struct.unpack('i', header)[0] # 接收字典 header_bytes = conn.recv(header_len) header_dic = json.loads(header_bytes.decode('utf_8')) print(header_dic) # 打印字典 # 循环接收文件,存储到本地 file_size = header_dic.get('file_size') file_name = header_dic.get('file_name') recv_size = 0 # 文件操作 with open(file_name, 'wb') as f: while recv_size < file_size: # 循环接收 data = conn.recv(1024) f.write(data) recv_size += len(data) print(header_dic.get('msg')) # 文件上传成功后的提示信息 except ConnectionResetError: break conn.close()
二、UDP协议(数据报协议):
没有双向通道,传输数据不可靠,可能出现丢包现象
通信速度比较快,发送的数据不会在内存中保留
1、特性:
①UDP协议不存在粘包问题
②客户端可以发空,自带数据报头
③udp可以实现并发的效果
④服务端不存在,也不影响客户端朝服务端发送数据
2、分析:
①UDP叫数据报协议,意味着发消息都带有数据报头
②UDP的server不需要就行监听也不需要建立连接
③启动服务之后只能被动的等待客户端发消息过来,
客户端发消息的时候,带上服务端的地址 client.sendto(b'hello', server_addr)
服务端发消息的时候,带上客户端的地址 server.sendto(msg.upper(), addr)
3、TCP和UDP
TCP:类似于打电话,要确定服务端收到
UDP:类似于发短信,不考虑服务端是否收到
4、UDP简单使用
①服务端
import socket server = socket.socket(type=socket.SOCK_DGRAM) server.bind(('127.0.0.1', 8080)) msg, addr = server.recvfrom(1024) server.sendto(msg.upper(), addr) print(msg, addr)
②客户端
import socket client = socket.socket(type=socket.SOCK_DGRAM) server_addr = ('127.0.0.1', 8080) # 服务端地址,通常写在配置文件中 client.sendto(b'hello', server_addr) msg, addr = client.recvfrom(1024) print(msg, addr)
5、UDP不存在粘包现象
UDP不存在粘包现象,是由于UDP发送的时候,没有经过Negal算法优化,不会将多个小包合并一次发送出去。另外,在UDP协议的接收端,采用了链式结构来记录每一个到达的UDP包,这样接收端应用程序一次recv只能从socket接收缓冲区中读出一个数据包。也就是说,发送端send了几次,接收端必须recv几次(无论recv时指定了多大的缓冲区)。
①服务端
import socket server = socket.socket(type=socket.SOCK_DGRAM) server.bind(('127.0.0.1', 8080)) # 验证udp是否粘包:不粘包 msg, addr = server.recvfrom(1024) print(msg) # b'baby~' msg1, addr1 = server.recvfrom(1024) print(msg1) # b'baby~' msg2, addr2 = server.recvfrom(1024) print(msg2) # b'baby~'
②客户端
import socket client = socket.socket(type=socket.SOCK_DGRAM) server_addr = ('127.0.0.1', 8080) # 服务端地址,通常写在配置文件中 # 验证udp是否粘包:不粘包 client.sendto(b'baby~', server_addr) client.sendto(b'baby~', server_addr) client.sendto(b'baby~', server_addr)
三、基于UDP实现简易版本的QQ
①服务端
import socket server = socket.socket(type=socket.SOCK_DGRAM) server.bind(('127.0.0.1',8080)) while True: msg,addr = server.recvfrom(1024) print(msg.decode('utf-8')) data = input('>>>:').encode('utf-8') server.sendto(data,addr)
②客户端
import socket client = socket.socket(type=socket.SOCK_DGRAM) server_addr = ('127.0.0.1',8080) while True: msg = input('>>>:') msg = '客户端1的消息:%s'%msg client.sendto(msg.encode('utf-8'),server_addr) data,addr = client.recvfrom(1024) print(data)
四、socketserver模块
1、能够实现并发效果
并发:看起来像同时运行就能称之位并发
2、udp在使用的时候,多个客户端要有一些io操作,不然容易卡死