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

 

posted @ 2020-03-17 17:16  红叶楠木  阅读(131)  评论(0编辑  收藏  举报