一、报文
1、我们在网络上传输的所有数据都叫数据包
2、数据包里的数据都叫报文
3、报文里不止有你的数据 还有:ip地址,mac地址,端口号
4、所有的报文都有报头(能告诉你接收多少个字节)
5、自己定制报文:
(1) 在复杂的应用上就会用到
(2)传输文件:文件的名字,文件的大小,文件的类型,储存路径
head = {'filename':'test','filesize':40966,'filetype':'txt','filepath':r'\user\bin'}
6,在网络传输过程中处处有协议;协议就是一堆报文和报头;协议的解析过程我们不需要关心;如果跳出我们所了解的端口ip协议;我们写的程序也需要多次发送数据或者发送多个数据;我们也可以自定义协议-----本质就是一种约定
二、hmac
import hmac
h = hmac.new() #secret_key ,你想进行加密的字节
secert = h.digest()
hmac.compare_digest() #对比密文 另外一个密文
例:检测一下客户端是否合法(不依靠登陆认证)
TCP----->server
import socket,os,hmac
secret_key = b'egg'
sk = socket.socket()
sk.bind(('127.0.0.1',8090))
sk.listen(5)
conn,addr = sk.accept()
def check_conn(conn):
msg = os.urandom(32)
conn.send(msg)
h = hmac.new(secret_key,msg)
digest = h.digest()
client_digest = conn.recv(1024)
return hmac.compare_digest(digest,client_digest)
res = check_conn(conn)
if res:
print('合法的客户端!')
conn.close()
else:
print('合法客户端')
sk.close()
TCP----->client
import socket,hmac
secret = b'egg'
sk = socket.socket()
sk.connect(('127.0.0.1',8090))
msg = sk.recv(1024)
h = hmac.new(secret,msg)
digest = h.digest()
sk.send(digest)
sk.close()
三、socketserver
server:
import socketserver
class MyServer(socketserver.BaseRequestHandler):
def handle(self):#self.request 就相当一个conn
while True:
msg = self.request.recv(1024).decode('utf-8') #self.request 相当于 conn
if msg == 'q':
self.request.close()
break
print(msg)
info = input('>>').encode('utf-8')
self.request.send (info)
if __name__ == '__main__':
server = socketserver.ThreadingTCPServer(('127.0.0.1',8090),MyServer) #线程
server.serve_forever()
client:
import socket
sk = socket.socket()
sk.connect(('127.0.0.1',8090))
while True:
msg = input('>>').encode('utf-8')
if msg == b'q':
sk.send(msg)
break
sk.send(msg)
ret = sk.recv(1024).decode('utf-8')
print(ret)
sk.close()
四、定制报头
server:
import socket
import struct
import json
sk = socket.socket()
sk.bind(('127.0.0.1',8090))
sk.listen(5)
conn,addr = sk.accept()
buffer = 1024
#接收
head_len = conn.recv(4)
head_len = struct.unpack('i',head_len)[0]
json_head = conn.recv(head_len).decode('utf-8')
head = json.loads(json_head)
file_size = head['filesize']
print(file_size)
with open(head['filename'],'wb') as f:
while file_size:
if file_size >= buffer:
content = conn.recv(buffer)
f.write(content)
file_size -= buffer
else:
content = conn.recv(file_size)
f.write(content)
break
conn.close()
sk.close()
client:
import socket
import os
import json
import struct
sk = socket.socket()
sk.connect(('127.0.0.1',8090))
buffer = 1024
head = {'filepath':'D:\Python\全栈\老男孩Python高级全栈开发工程师-1',
'filename':'0011.Pythonfullstacks1day1.mkv',
'filesize':None
}
file_path = os.path.join(head['filepath'],head['filename'])
file_size = os.path.getsize(file_path)
head['filesize'] = file_size
print(file_size)
json_head = json.dumps(head) #字典转字符串
bytes_head = json_head.encode('utf-8')#字符串转bytes
#计算head的长度
head_len = len(bytes_head)
pack_len = struct.pack('i',head_len)
sk.send(pack_len)#先发报头长度
sk.send(bytes_head)#再发送bytes类型报头
with open(file_path,'rb') as f:
while file_size:
if file_size >= buffer:
content = f.read(buffer)#每次读出来的内容
sk.send(content)
file_size -= buffer
else:
content = f.read(file_size)
sk.send(content)
break
sk.close()
五、总复习
1、互联网协议 - 七层:OSI协议
2、应用层:python ; 传输层:tcp/udp ; 网络层:ip(路由器) ;数据链路层:arp(交换机);物理层 网卡
3、arp:通过IP找mac地址
4、交换机:广播,单播,组播
5、ip协议:规定了ip地址的格式,一台机器在一个网络内唯一的标识
6、子网掩码:ip地址与子网掩码按位与运算,得到的是网段
7、网关ip:局域网内的机器访问公网IP,就通过网关访问
8、tcp
:面向流的 可靠 三次握手 四次挥手 –
9、udp
: 面向数据包 不可靠
10、黏包:
(1)在发送信息之前,先告诉对方要发的数据有多大
(2)struct模块将要发送的数据大小固定化。无论如何就发4个字节
(3)自定义协议的概念
11、验证客户合法性:hamc
12、处理并发问题:socketserver