python学习Day33--SocketServer

我与影子孤独终老i 提交于 2020-03-23 17:22:03

一、回顾(需要记住的)

1、架构:

  C/S架构:充分发挥PC机性能

  B/S架构:统一了应用的接口,隶属于C/S架构

2、物理地址:mac,全球唯一,类似于一个身份证

3、IP地址:四位点分十进制

4、arp协议:通过目标的IP地址,获取目标mac地址

5、OSI五层模型:

  应用层                     http, https, ftp, py文件

  传输层                     tcp/udp协议

  网络层                     ip协议

  数据链路层              arp协议

  物理层                     传输电信号

6、交换机的通信方式:

  单播:点对点

  组播:点对多(一组,不是指所有)

  广播:向多个PC端发送数据包

7、交换机的功能:

  组成局域网,经过内部处理解析数据,将数据以点对点,点对多的方式发送给目标

8、路由器的功能:

  跨网段的数据传输,路由出网络传输的最佳路径。

9、TCP协议:面向连接的,面向字节流传输,可靠

   UDP协议:无连接,面向数据包,不可靠,传输速度快

10、TCP与UDP协议的区别:

  TCP有三次握手,四次挥手

  (1)三次握手:第一次的请求一定是客服端先发起

    客服端向服务器发送一个连接请求;

    客服端回复一个确认接收到请求,并要求连接客服端;

    客服端回复服务器一个确认连接的消息,

  (2)四次挥手:谁先发起都可以

    客服端先发送一个断开连接的请求;

    服务器回复一个确认收到;

    服务器回复一个确认断开连接的请求;

    客服端回复一个确认收到 。

  TCP可能会出现粘包情况

  (1)粘包:在数据传输过程中,接收端接收数据时,不知道应该如何接收数据造成的一个数据混乱的现象。

  (2)粘包的原因:

    一个是拆包机制;

    一个是合包机制(Nagle算法)

    【注意】两个机制都是发生在发送端

  TCP本质上就是只允许一个服务器和一个客服端保持连接

  UDP允许一个服务器和多个客服端同时通信

11、什么是同一时间点,什么叫同一时间间隔?

12、新模块:

  socket模块:套接字,网络传输数据,处于应用层和传输层之间的一个抽象层。

  subprocess模块:Popen方法,执行操作系统命令的。

  struct模块:pack和unpack方法。

二、socket更多方法

1、公共用途法套接字函数

(1)s.recv()                   接收TCP数据

(2)s.send()                  发送TCP数据

(3)s.sendall()              发送TCP数据

(4)s.recvfrom()            接收UDP数据

(5)s.sendto()               发送UDP数据

(6)s.getpeername()     连接当前套接字的远端地址

(7)s.getsockname()    当前套接字的地址

(8)s.getsockopt()        返回指定套接字的参数

(9)s.setsockopt()        设置指定套接字的参数

(10)s.close()               关闭套接字

2、面向锁的套接字方法

(1)s.setblocking()       设置套接字的阻塞与非阻塞模式

(2)s.settimeout()        设置阻塞套接字操作的超时时间

(3)s.gettimeout()        得到阻塞套接字操作的超时时间

3、面向文件的套接字的函数

(1)s.fileno()                 套接字的文件描述符

(2)s.makefile()            创建一个与该套接字相关的文件 

 1 # *******************服务端**********************开始
 2 import socket
 3 import time
 4 # from socket import SOL_SOCKET,SO_REUSEADDR
 5 
 6 sk = socket.socket()
 7 
 8 # 一个服务端口重复使用
 9 # sk.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
10 
11 sk.setblocking(False)# 设置accept和recv两个方法的阻塞与非阻塞状态
12 # 参数为False   代表设置为非阻塞状态
13 # 参数为True 或者不写,默认为阻塞状态
14 
15 sk.bind(('127.0.0.1',8080))
16 
17 # sk.settimeout(4)# 设置等待超时时间
18 # print(sk.gettimeout())# 获取等待超时时间
19 
20 sk.listen()
21 # print(123)
22 
23 time.sleep(1)
24 
25 conn,addr = sk.accept()# 阻塞
26 # print(456)
27 print(conn.recv(1024))# 阻塞
28 # print(789)
29 # print(conn.recv(1024))
30 # print(conn.getpeername()) # 获取连接的远端的地址
31 # print(conn.getsockopt()) # 返回指定套接字的参数
32 
33 conn.close()
34 sk.close()
35 # *******************服务端**********************结束
服务端
 1 # *******************客户端**********************开始
 2 import socket
 3 import time
 4 sk = socket.socket()
 5 while 1:
 6     r = sk.connect_ex(('127.0.0.1',8080))
 7     if r == 0:
 8         break
 9 
10 time.sleep(5)
11 
12 sk.send(b'hello')
13 # print(sk.getsockname())# 获取当前套接字的地址
14 
15 # sendall 一次性把数据全部发出去
16 # sk.sendall(b'world')
17 
18 sk.close()
19 # *******************客户端**********************结束
客户端

三、客服端合法性检验

1、验证身份

 1 # *******************服务端**********************开始
 2 import socket
 3 import hashlib
 4 
 5 sk = socket.socket()
 6 sk.bind(('127.0.0.1',8060))
 7 sk.listen()
 8 
 9 conn,addr = sk.accept()
10 sor = b'alex'
11 r_str = '这是一个随机的字符串'
12 conn.send(r_str.encode('utf-8'))
13 
14 # 加密算法
15 md5_obj = hashlib.md5(sor) # 加盐
16 md5_obj.update(r_str.encode('utf-8'))
17 result = md5_obj.hexdigest() # 结果是字符串
18 
19 # 服务器接收客服端发来的秘文,并返回结果
20 msg = conn.recv(1024).decode('utf-8')
21 if msg == result:
22     conn.send(b'sucess')
23 else:
24     conn.send(b'failed')
25 
26 conn.close()
27 sk.close()
28 # *******************服务端**********************结束
服务端
 1 # *******************客户端**********************开始
 2 import socket
 3 import hashlib
 4 
 5 sk = socket.socket()
 6 sk.connect_ex(('127.0.0.1',8060))
 7 sor = b'alex'
 8 r_str = sk.recv(1024) # 接收服务器发来的随机字符串
 9 
10 # 加密算法
11 md5_obj = hashlib.md5(sor) # 加盐
12 md5_obj.update(r_str)
13 result = md5_obj.hexdigest() # 结果是字符串
14 sk.send(result.encode('utf-8'))
15 
16 # 接收秘文验证结果
17 msg = sk.recv(1024)
18 print(msg)
19 
20 # while 1:
21 #     name = input("请输入用户名>>>")
22 #     pawd = input("请输入密码>>>")
23 
24 
25 sk.close()
26 # *******************客户端**********************结束
客户端

2、随机字符串获取和hmac模块的md5加盐算法

 1 import hmac
 2 import os
 3 
 4 # print(os.urandom(16),len(os.urandom(16)))
 5 
 6 sor = b'wusir'
 7 
 8 r_str = os.urandom(16) # 真正随机字符串
 9 
10 # MD5加盐新方法  与hashlib一样
11 md5_obj = hmac.new(sor,r_str)
12 r = md5_obj.digest()
13 print(r)

3、针对上述--优化版本

 1 # *******************服务端(优化版)**********************开始
 2 # 优化地方:
 3 # 随机字符串   加密算法hmac
 4 import socket
 5 import hmac
 6 import os
 7 
 8 sk = socket.socket()
 9 sk.bind(('127.0.0.1',8060))
10 sk.listen()
11 
12 conn,addr = sk.accept()
13 sor = b'alex'
14 r_str = os.urandom(16)  # r_str是byte类型
15 conn.send(r_str)
16 
17 # 加密算法
18 md5_obj = hmac.new(sor,r_str)
19 result = md5_obj.digest() # 结果是byte类型
20 
21 # 服务器接收客服端发来的秘文,并返回结果
22 msg = conn.recv(1024)
23 if msg == result:
24     conn.send(b'sucess')
25 else:
26     conn.send(b'failed')
27 
28 conn.close()
29 sk.close()
30 # *******************服务端(优化版)**********************结束
服务端
 1 # *******************客户端(优化版)**********************开始
 2 import socket
 3 import hmac
 4 
 5 sk = socket.socket()
 6 sk.connect_ex(('127.0.0.1',8060))
 7 sor = b'alex'
 8 r_str = sk.recv(1024) # 接收服务器发来的随机字符串
 9 
10 # 加密算法
11 md5_obj = hmac.new(sor,r_str) # 加盐
12 result = md5_obj.digest() # 结果是byte类型
13 sk.send(result)
14 
15 # 接收秘文验证结果
16 msg = sk.recv(1024)
17 print(msg)
18 
19 # while 1:
20 #     name = input("请输入用户名>>>")
21 #     pawd = input("请输入密码>>>")
22 
23 
24 sk.close()
25 # *******************客户端(优化版)**********************结束
客户端

四、socketserver介绍及用户三次登陆

1、sockserver模块:主要是解决TCP协议中,服务器不能同时连接多个客服端的问题

  处于socket抽象层和应用层之间的一层,比socket更贴近用户

 1 # *******************服务端**********************开始
 2 import socketserver
 3 
 4 class MySocket(socketserver.BaseRequestHandler):
 5     def handle(self):# 这个方法的名字是固定的,必须是这个名字
 6         # 收发的逻辑代码
 7         # self.request == conn
 8         msg = self.request.recv(1024).decode('utf-8')
 9         print(msg)
10         self.request.send(msg.upper().encode('utf-8'))
11 
12 server = socketserver.TCPServer(('127.0.0.1',8080),MySocket)# 固定的
13 server.serve_forever()# 开启一个永久性的服务
14 # *******************服务端**********************结束
 1 # *******************客户端**********************开始
 2 import socket
 3 sk = socket.socket()
 4 sk.connect(('127.0.0.1',8080))
 5 
 6 msg_s = input('>>>')
 7 sk.send(msg_s.encode('utf-8'))
 8 
 9 print(sk.recv(1024).decode('utf-8'))
10 
11 sk.close()
12 # *******************客户端**********************结束

2、用户三次登陆验证

 1 # *******************服务端**********************开始
 2 import socketserver
 3 import json
 4 import hashlib
 5 
 6 def zhuce():
 7     pass
 8 
 9 class MySocket(socketserver.BaseRequestHandler):
10     def handle(self):
11         sor = b'wusir'#
12         while 1:
13             str_dic = self.request.recv(1024).decode('utf-8')
14             # 接收到 一个字典,类似于{'status':False,'username':None,'password':None}
15             if not str_dic:break # 当客户端登录失败退出程序的情况下,这里会接收到一个空消息。
16             dic = json.loads(str_dic)
17             if not dic['status']:
18                 '''没有登录成功的情况下'''
19                 with open('info','r',encoding='utf-8') as f:
20                     # 文件内容的存储方式  用户名|密码
21                     for info in f:
22                         username,pawd_txt = info.strip().split('|')
23                         if username == dic['username']:
24                             '''用户存在,就对客户端发来的用户的密码再次加密,与文件中对比'''
25                             md5_obj = hashlib.md5(sor)
26                             md5_obj.update(dic['password'].encode('utf-8'))
27                             pawd = md5_obj.hexdigest()
28                             if pawd_txt == pawd:
29                                 '''密码正确的情况下'''
30                                 dic['status'] = True
31                             else:
32                                 dic['reason'] = '密码错误'
33                             break
34                     else:
35                         '''用户不存在'''
36                         dic['reason'] = '用户不存在'
37                         zhuce()
38                 #  dic = {status:False ,  username ,   password,   reason}
39                 #  dic = {status:True ,  username ,   password}
40                 str_dic = json.dumps(dic)
41                 self.request.send(str_dic.encode('utf-8'))
42             else:
43                 '''已经是登录成功了'''
44 
45 server = socketserver.TCPServer(('127.0.0.1',8080),MySocket)
46 server.serve_forever()
47 # *******************服务端**********************结束
服务端
 1 # *******************客户端**********************开始
 2 import socket
 3 import hashlib
 4 import json
 5 
 6 sk = socket.socket()
 7 sk.connect(('127.0.0.1',8080))
 8 
 9 dic = {'status':False,'username':None,'password':None}
10 c = 3
11 while c:
12     username = input('请输入用户名')
13     password = input('请输入密码')
14 
15     md5_obj = hashlib.md5(password.encode('utf-8'))
16     md5_obj.update(username.encode('utf-8'))
17     pawd_m = md5_obj.hexdigest()
18 
19     dic['username'] = username
20     dic['password'] = pawd_m
21     str_dic = json.dumps(dic)
22     sk.send(str_dic.encode('utf-8'))
23 
24     # 服务器应该回复我一个这样的字典:
25     # 是否登录成功,如果没有登录成功是因为什么原因?
26     res_dic = sk.recv(1024).decode('utf-8')# str_dic
27     result = json.loads(res_dic)# dic = {status:False/True ,  username ,   password,   reason}
28     if result['status']:
29         print('登录成功')
30         break
31     else:
32         print('失败,%s'%result['reason'])
33         c -= 1
34 
35 sk.close()
36 # *******************客户端**********************结束
客户端
 1 import hashlib
 2 
 3 sor = b'wusir'
 4 u = 'xiaoxue'
 5 p = 'pangpangde'
 6 
 7 md5_obj = hashlib.md5(p.encode('utf-8'))
 8 md5_obj.update(u.encode('utf-8'))
 9 r = md5_obj.hexdigest()
10 
11 md5_obj = hashlib.md5(sor)
12 md5_obj.update(r.encode('utf-8'))
13 res = md5_obj.hexdigest()
14 print(res)
手动加入用户密码

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!