验证客户端的合法性

作业讲解

一对多聊天,不用ip,port来判断和谁聊天

server端

 1  import socket
 2  friend_lst = {'alex':'32','太白':'33'}
 3  sk =socket.socket(type=socket.SOCK_DGRAM)
 4  sk.bind(('127.0.0.1',9001))
 5  while True:
 6      msg,addr = sk.recvfrom(1500)
 7      msg = msg.decode('utf-8')
 8      name,message  = msg.split('|',1)  # 只切一次
 9      print('\033[1;%sm %s:%s\033[0m'%(friend_lst.get(name,'30'),name,message))
10      content = input('>>>')
11      sk.sendto(content.encode('utf-8'),addr)

 

client端
 1  import socket
 2  name = '大壮'
 3  sk = socket.socket(type=socket.SOCK_DGRAM)
 4  5  while True:
 6      content = input('>>>')
 7      if content.upper() == 'Q': break
 8      content = '%s|%s'%(name,content)
 9      sk.sendto(content.encode('utf-8'),('127.0.0.1',9001))
10      msg = sk.recv(1024).decode('utf-8')
11      if msg.upper() == 'Q': break
12      print(msg)

 

传送小文件

server端

 1  import json
 2  import socket
 3  # 接收
 4  sk = socket.socket()
 5  sk.bind(('127.0.0.1',9001))
 6  sk.listen()
 7  8  conn,_ = sk.accept()
 9  msg = conn.recv(1024).decode('utf-8')
10  msg = json.loads(msg)
11 12  with open(msg['filename'],'wb') as f:
13      content = conn.recv(msg['filesize'])
14      print('-->',len(content))
15      f.write(content)
16  conn.close()
17  sk.close()

 

client端

 1  import os
 2  import json
 3  import socket
 4  # 发送
 5  sk = socket.socket()
 6  sk.connect(('127.0.0.1',9001))
 7  8  # 文件名\文件大小
 9  abs_path = r'D:\python_22\day30\tmp'
10  filename = os.path.basename(abs_path)
11  filesize = os.path.getsize(abs_path)
12  dic = {'filename':filename,'filesize':filesize}
13  str_dic = json.dumps(dic)
14  sk.send(str_dic.encode('utf-8'))
15 16  with open(abs_path,mode = 'rb') as f:
17      content = f.read()
18      sk.send(content)
19 20  sk.close()

 

总结:把文件名和文件大小先做一个字典用json传过去,打开一个同名文件,只接受文件大小的数据

传送大文件

server端

 1  import json
 2  import struct
 3  import socket
 4  # 接收
 5  sk = socket.socket()
 6  sk.bind(('127.0.0.1',9001))
 7  sk.listen()
 8  9  conn,_ =sk.accept()
10  msg_len = conn.recv(4)
11  dic_len = struct.unpack('i',msg_len)[0]
12  msg = conn.recv(dic_len).decode('utf-8')
13  msg = json.loads(msg)
14 15  with open(msg['filename'],'wb') as f:
16      while msg['filesize'] > 0:
17          content = conn.recv(1024)
18          msg['filesize'] -= len(content)
19          f.write(content)
20  conn.close()
21  sk.close()

 

client端

 1  import os
 2  import json
 3  import struct
 4  import socket
 5  # 发送
 6  sk = socket.socket()
 7  sk.connect(('127.0.0.1',9001))
 8  9  # 文件名\文件大小
10  abs_path = r'D:\python22期\day28 课上视频\3.网络基础概念.mp4'
11  filename = os.path.basename(abs_path)
12  filesize = os.path.getsize(abs_path)
13  dic = {'filename':filename,'filesize':filesize}
14  str_dic = json.dumps(dic)
15  b_dic = str_dic.encode('utf-8')
16  mlen = struct.pack('i',len(b_dic))
17  sk.send(mlen)   # 4个字节 表示字典转成字节之后的长度
18  sk.send(b_dic)  # 具体的字典数据
19 20  with open(abs_path,mode = 'rb') as f:
21      while filesize>0:
22          content = f.read(1024)
23          filesize -= len(content)
24          sk.send(content)
25  sk.close()

 

总结:传送大文件时,不能保证每次接收的都是限定的字节,因为tcp优化会把大文件拆成小文件传送,所以实际接收的文件会比上限要小,应该总文件大小 -= 传过来的内容大小。粘包发生在传送字典时,为了防止粘包所以先传字典长度,因为是一个大文件所以粘包无所谓。

今日内容

验证客户端的合法性

用处

当需要考虑是否有恶意客户端访问会影响服务器正常运行时。比如恶意客户端会通过扫端口等方法盗取信息或传送非法文件。

认证机制

服务端获取一个随机字符串,发送给客户端,之后服务端会把秘钥与发送的内容经过算法得出一个结果,此时客户端也会把秘钥与接收的内容经过同样的算法,将得出的结果发送给服务端,服务端通过比较两者结果是否相同判定客户端是否合法。

秘钥:用于验证身份的一段约定好的数据

随机字符串:发送的内容可能会被截获,为了安全一次认证后需换一个随机内容

算法:hashlib模块

1  # import os
2  # ret = os.urandom(16)
3  # print(ret)
4 5  # import hashlib
6  # sha = hashlib.sha1(密钥)
7  # sha.update(随机字符串)
8  # 结果 = sha.hexdigest()

 

hmac模块

1  # h = hmac.new(b'alex_sb',os.urandom(32))
2  # ret = h.digest()
3  # print(ret)

 

实现代码

server端

 1 import os
 2 import socket
 3 import hashlib
 4 
 5 secret_key = b'alex_sb'
 6 sk = socket.socket()
 7 sk.bind(('127.0.0.1',9001))
 8 sk.listen()
 9 
10 conn,addr = sk.accept()
11 # 创建一个随机的字符串
12 rand = os.urandom(32)
13 # 发送随机字符串
14 conn.send(rand)
15 
16 # 根据发送的字符串 + secrete key 进行摘要
17 sha = hashlib.sha1(secret_key)
18 sha.update(rand)
19 res = sha.hexdigest()
20 
21 # 等待接收客户端的摘要结果
22 res_client = conn.recv(1024).decode('utf-8')
23 # 做比对
24 if res_client == res:
25     print('是合法的客户端')
26     # 如果一致,就显示是合法的客户端
27     # 并可以继续操作
28     conn.send(b'hello')
29 else:
30     conn.close()
31     # 如果不一致,应立即关闭连接

 

client端

 1 import socket
 2 import hashlib
 3 
 4 secret_key = b'alex_sb979'
 5 sk = socket.socket()
 6 sk.connect(('127.0.0.1',9001))
 7 
 8 # 接收客户端发送的随机字符串
 9 rand = sk.recv(32)
10 # 根据发送的字符串 + secret key 进行摘要
11 sha = hashlib.sha1(secret_key)
12 sha.update(rand)
13 res = sha.hexdigest()
14 # 摘要结果发送回server端
15 sk.send(res.encode('utf-8'))
16 # 继续和server端进行通信
17 msg = sk.recv(1024)
18 print(msg)

 

并发的tcp协议server端 — socketserver

socketserver是socket的底层模块

底层模块

 

底层模块的效率全看使用者的使用方法

实现代码

server端(背)

 1 import time
 2 import socketserver
 3 
 4 class Myserver(socketserver.BaseRequestHandler):
 5     def handle(self):
 6         conn = self.request
 7         while True:
 8             try:
 9                 content = conn.recv(1024).decode('utf-8')
10                 conn.send(content.upper().encode('utf-8'))
11                 time.sleep(0.5)
12             except ConnectionResetError:
13                 break
14 server = socketserver.ThreadingTCPServer(('127.0.0.1',9001),Myserver)
15 server.serve_forever()

 

client端(没改动)

1 import socket
2 
3 sk = socket.socket()
4 sk.connect(('127.0.0.1',9001))
5 
6 while True:
7     sk.send(b'hello')
8     content = sk.recv(1024).decode('utf-8')
9     print(content)

 

posted @ 2019-01-28 17:37  .如影随行  阅读(539)  评论(0编辑  收藏  举报