python学习Day31--粘包
【基本知识点】
一、回顾
1、TCP编码、UDP编码、PyCharm带颜色输出
2、三次握手:客服端先发起
客服端先发起连接请求;
服务器回复确认收到,连接客服端的请求;
客服端回复收到请求,可以连接。
3、四次挥手:谁可以先发起请求
客服端发起一个请求,代表我没有数据继续发送了,但是如果你有数据继续发,我可以继续接受;
服务器发送一个确认收到的ACK
服务器再发送一个断开连接的请求,标识可以断开连接了;
客服端回复一个确认能收到。
【三个标识】:
ACK:确认收到; SYN:请求连接的这么一个标识; FIN:请求断开的这么一个标识
4、UDP特点:不面向连接,不可靠,面向数据,速度快。
5、TCP特点:可靠的,基于连接的,面向字节流形式的。
6、OSI五层模型:应用层(http, https, ftp),传输层(tcp, udp),网络层(ip),数据链路层(arp),物理层。
7、socket:是一个模块,是一个套接字,是一个类,是传输层和应用层之间的一个抽象层。
8、子网掩码:子网掩码&IP地址 得到网段
二、执行命令
在py代码中如何去调用操作系统的命令。
1、新模块:subprocess
1 r = subprocess.Popen('dir',shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE) 2 # 各个参数说明subprocess.Popen(cmd,shell=True,subprocess.stdout,subprocess.stderr) 3 # cmd:代表系统命令 4 # shell = True:代表这条命令是 系统命令,告诉操作系统,将cmd当成系统命令去执行 5 # stdout:是执行完系统命令之后,用于保存结果的一个管道 6 # stderr:是执行完系统命令之后,用于保存错误的一个管道
2、一个案例需求:
客服端发送要执行的命令
服务器执行,执行完成将结果返回给客服端
客服端拿到结果呈现到用户眼前
1 # *******************服务端**********************开始 2 import socket 3 import subprocess 4 5 sk = socket.socket() 6 sk.bind(('127.0.0.1',8080)) 7 sk.listen() 8 9 conn,addr = sk.accept() 10 while 1: 11 cmd = conn.recv(1024).decode('utf-8') 12 r = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE) 13 stdout = r.stdout.read() 14 stderr = r.stderr.read() 15 if stderr: 16 conn.send(stderr) 17 else: 18 conn.send(stdout) 19 20 conn.close() 21 sk.close() 22 # *******************服务端**********************结束 23 24 25 # *******************客服端**********************开始 26 import socket 27 28 sk = socket.socket() 29 30 sk.connect_ex(('127.0.0.1',8080)) 31 while 1: 32 cmd = input('请输入一个命令>>>') 33 sk.send(cmd.encode('utf-8')) 34 35 result = sk.recv(102400).decode('gbk') 36 37 print(result) 38 39 40 sk.close() 41 # *******************客服端**********************结束
三、粘包
1、粘包问题:(只有tcp协议才会发生粘包)
① 发送端发送数据,接收端不知道应该如何去接收,造成一种数据混乱的现象。
② udp不会发生粘包,udp协议本层对一次收发数据大小的限制是:
65535 - ip包头(20) - udp包头(8) = 65507
③ 站在数据链路层,因为网卡的MTU一般被限制在了1500,所以对于数据链路层来说,一次收发数据的大小被限制在 1500 - ip包头(20) - udp包头(8) = 1472
【结论】:
如果sendto(num) 的num > 65507 则会报错;
1472 < num < 65507 会在数据链路层拆包,而udp本身就是不可靠协议,所以一旦拆包之后,造成的多个小数据包在网络传输中,如果丢任何一个,那么此次数据传输失败。
2、粘包的缘由:两种
① 合包机制:(Nagle算法)将多次连续发送且时间间隔较小的数据,进行打包成一块数据传送。
② 拆包机制:在发送端因为网卡MTU限制,会将大的超过MTU限制的数据进行拆分,拆分为多个小的数据进行传输;当传输目标主机的操作系统层时,会重新将多个小的数据合并成原本的数据。
3、粘包测试
1 # *******************服务端**********************开始 2 import socket 3 sk = socket.socket() 4 5 sk.bind(('127.0.0.1',8888)) 6 sk.listen() 7 8 conn,addr = sk.accept() 9 10 conn.send(b'hello') 11 conn.send(b'world') 12 13 conn.close() 14 sk.close() 15 16 # *******************服务端**********************结束 17 18 19 # *******************客服端**********************开始 20 import socket 21 sk = socket.socket() 22 23 sk.connect_ex(('127.0.0.1',8888)) 24 25 msg1 = sk.recv(1024) 26 print('msg1:',msg1) # 粘包发生时,打印:msg1: b'helloworld' 27 28 msg2 = sk.recv(1024) 29 30 print('msg2:',msg2) 31 32 sk.close() 33 # *******************客服端**********************结束
结果:
【课后练习】
1、文件的上传下载
1 # *******************服务端**********************开始 2 # 功能不完善,只能实现当前目录。后期可以加上,目录的切换功能 3 import socket 4 import json 5 6 sk = socket.socket() 7 sk.bind(('127.0.0.1',8888)) 8 sk.listen() 9 10 conn,addr = sk.accept() 11 while 1: 12 # 通信 13 str_dic = conn.recv(4800).decode('utf-8') 14 dic = json.loads(str_dic) # 得到字典 15 if dic['opt'] == 'upload': 16 # 上传 17 filename = 'shangchuan_' + dic['filename'] 18 with open(filename, 'w', encoding='utf-8') as f: 19 f.write(dic['content']) 20 break 21 22 elif dic['opt'] == 'download': 23 # 下载 24 filename = dic['filename'] 25 with open(filename,'r',encoding='utf-8') as f: 26 content = f.read() 27 dic['content'] = content 28 str_dic = json.dumps(dic) 29 conn.send(str_dic.encode('utf-8')) 30 break 31 32 conn.close() 33 sk.close() 34 # *******************服务端**********************结束 35 36 37 # *******************客服端**********************开始 38 import os 39 import socket 40 import json 41 42 sk = socket.socket() 43 sk.connect_ex(('127.0.0.1',8888)) # 带返回值,如果出粗,不会报错会返回错误的编码 44 45 menu = {'1':'upload','2':'download'} 46 for k,v in menu.items(): 47 print(k,v) 48 49 num = input("请输入功能选项:") 50 if num == '1': 51 # 上传功能 52 dic = {'opt':menu.get(num),'filename':None,'content':None} 53 file_path = input("请输入一个文件的绝对路径:") 54 # D:/wendang/PyCharmCode/Python学习/day31 粘包/文件上传下载/xxx.py 55 filename = os.path.basename(file_path) 56 with open(file_path,'r',encoding='utf-8') as f: 57 content = f.read() 58 59 dic['filename'] = filename 60 dic['content'] = content 61 62 # 字典序列化 63 str_dic = json.dumps(dic) 64 sk.send(str_dic.encode('utf-8')) 65 66 elif num == '2': 67 # 下载功能 68 filename = input("请输入文件名:") 69 dic = {'opt':menu.get(num),'filename':filename,'content':None} 70 str_dic = json.dumps(dic) 71 sk.send(str_dic.encode('utf-8')) 72 73 str_dic = sk.recv(4800).decode('utf-8') 74 dic = json.loads(str_dic) 75 filename = 'xiazai_' + dic['filename'] 76 with open(filename,'w',encoding='utf-8') as f: 77 f.write(dic['content']) 78 79 else: 80 print("输入错误") 81 82 sk.close() 83 # *******************客服端**********************结束
时间:2020-03-17 17:15:10
作者(QQ):931935931