网络编程(三) 文件上传与UDP
一. TCP协议大文件上传
服务端:
import socket import struct import json import os 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()
客户端:
import socket import os import json import struct client = socket.socket() client.connect(('127.0.0.1',8080)) # 文件大小 file_size = os.path.getsize(r'D:\fullstack_s\day32\巴拉巴拉.mp4') # 文件名字 file_name = '性感荷官在线发牌.mp4' # 定义一个字典 d = { "file_name":file_name, "file_size":file_size, 'msg':'注意身体哦!' } 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:\fullstack_s\day32\巴拉巴拉.mp4','rb') as f: for line in f: client.send(line)
二. socketserver模块
1.能够实现并发效果
2.udp在使用的时候,多个客户端要有一些io操作, 不然容易卡死
配合UDP的socketsever模块:
服务端:
import socketserver class MyBaby(socketserver.BaseRequestHandler): def handle(self): # 通信循环 while True: # self.request相当于你的conn通信对象 data,sock = self.request # 收消息 print(data) sock.sendto(data.upper(),self.client_address) # self.client_address客户端地址 if __name__ == '__main__': server = socketserver.ThreadingUDPServer(('127.0.0.1',8080),MyBaby) server.serve_forever()
客户端:
import socket import time client = socket.socket(type=socket.SOCK_DGRAM) server_addr = ('127.0.0.1',8080) while True: client.sendto(b'hello',server_addr) data,addr = client.recvfrom(1024) print(data,addr) time.sleep(1)
配合TCP的socketsever模块:
服务端:
import socketserver class MyBaby(socketserver.BaseRequestHandler): def handle(self): # 通信循环 while True: # self.request相当于你的conn通信对象 data = self.request.recv(1024) # 收消息 print(data) self.request.send(data.upper()) if __name__ == '__main__': server = socketserver.ThreadingTCPServer(('127.0.0.1',8080),MyBaby) server.serve_forever()
客户端:
import socket client = socket.socket() client.connect(('127.0.0.1',8080)) while True: client.send(b'hello') data = client.recv(1024) print(data)
三. UDP协议: 数据报协议,没有双向通道
1.UDP协议不存在黏包问题;
2.客户端可以发空
3.UDP可实现并发效果(不依赖socketserver模块)
4.服务端不存在,客户端也可以朝服务端发送数据
import socket server = socket.socket(type=socket.SOCK_DGRAM) server.bind(('127.0.0.1',8080)) while True: data,addr = server.recvfrom(1024) print(data) server.sendto(data.upper(),addr)
import socket client = socket.socket(type=socket.SOCK_DGRAM) server_addr = ('127.0.0.1',8080) # 服务端地址,通常写在配置文件中 while True: client.sendto(b'hello',server_addr) msg,addr = client.recvfrom(1024) print(msg)
四.简易版QQ(基于UDP协议)
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)
import socket client = socket.socket(type=socket.SOCK_DGRAM) server_addr = ('127.0.0.1',8080) while True: msg = input('>>>:') msg = '客户端2的消息:%s'%msg client.sendto(msg.encode('utf-8'),server_addr) data,addr = client.recvfrom(1024) print(data)