Python——网络编程(二)socket进阶2

#socketserver模块实现并发

socketserver就是一个py文件,可以ctrl进去看看都是如何实现的

socketserver的两个最基本的类:

 (以下箭头代表继承关系)

  • server类:用于处理链接

分为以下五种:

右边两个代表专用于Unix的TCP和UDPservice,一般不用

 

 

 

  • request类: 用于处理通信

 

 

  • 其余类都是继承以上两大类(注意继承的优先级是由左到右递减)

“ThreadingUDPServer", "ThreadingTCPServer", "ThreadingMixIn"

"ForkingUDPServer","ForkingTCPServer", "ForkingMixIn"

 

 

 

 1 import socketserver
 2 
 3 buffer_size = 1024
 4 ip_port = ('222.195.137.208', 8000)
 5 
 6 #需要继承socketserver.BaseRequestHandler类
 7 class MyServer(socketserver.BaseRequestHandler):
 8 
 9     #一定需要自己重新定义handle
10     def handle(self):
11         print(self.request)         #相当于原来的conn
12         print(self.client_address)  #相当于原来的addr
13 
14         #通讯循环
15         while True:
16             try:
17                 # 接收客户端消息
18                 data = self.request.recv(buffer_size)
19 
20                 if not data:break
21                 print('客户端发来的消息: ', data.decode('utf8'))
22 
23                 #发送消息
24                 self.request.sendall(data.upper())
25             except Exception as e:
26                 print(e)
27                 break
28 
29 
30 if __name__ == '__main__':
31     #链接循环
32 
33     # 创建多线程服务端实例(来一个链接创建一个实例,进行通信),其中MyServer代表的就是通信循环
34     s = socketserver.ThreadingTCPServer(ip_port, MyServer)
35     #这代表'永远服务',也就是链接循环
36     s.serve_forever()
socketserver服务端-TCP
 1 from socket import *
 2 
 3 ip_port = ('222.195.137.208', 8000)
 4 buffer_size = 1024
 5 
 6 client = socket(AF_INET, SOCK_STREAM)
 7 print('连接中...')
 8 client.connect(ip_port)
 9 print('连接成功: %s!' %ip_port[0])
10 
11 while True:
12     msg = input('>>')
13 
14     if not msg: continue
15     if msg == 'exit': break
16     client.send(msg.encode('utf8'))
17 
18     data = client.recv(buffer_size)
19 
20     print('收到消息:\n%s' %data.decode('utf8'))
21 
22 client.close()
客户端-TCP
  
 1 import socketserver
 2 
 3 buffer_size = 1024
 4 ip_port = ('222.195.137.208', 8000)
 5 
 6 class MyServer(socketserver.BaseRequestHandler):
 7 
 8     def handle(self):
 9         print(self.request)         #相当于原来的(接收的数据data, udp的套接字对象) --》 元组形式
10         print(self.client_address)  #相当于原来的addr
11         #和tcp不同的是,这里不需要再通讯循环了,udp的serverforever帮你做了
12         try:
13              #由于消息已经被接收到了self.request里,这里无需再接收
14             data = self.request[0]
15 
16             print('客户端发来的消息: ', data.decode('utf8'))
17 
18             #发送消息
19             self.request[1].sendto(data.upper(), self.client_address)
20         except Exception as e:
21             print(e)
22 
23 if __name__ == '__main__':
24 
25     s = socketserver.ThreadingUDPServer(ip_port, MyServer)
26     s.serve_forever()
socketserver服务端-UDP
 1 from socket import *
 2 
 3 ip_port = ('222.195.137.208', 8000)
 4 buffer_size = 1024
 5 
 6 client = socket(AF_INET, SOCK_DGRAM)
 7 
 8 while True:
 9     msg = input('>>')
10 
11     if not msg: continue
12     if msg == 'exit': break
13     client.sendto(msg.encode('utf8'), ip_port)
14 
15     data, addr = client.recvfrom(buffer_size)
16 
17     print('收到消息:\n%s' %data.decode('utf8'))
18 
19 client.close()
客户端-UDP

 如果需要使地址重用的话,加上这句

#验证客户端链接合法性

先介绍两个模块:

os.urandom():

函数定位: Return a string of n random bytes suitable for cryptographic use. 
意思就是,返回一个有n个byte那么长的一个string,然后很适合用于加密

hmac

和hashlib模块类似,主要介绍以下几个方法

 1 import hmac, os
 2 #产生32位的随机bytes
 3 msg = os.urandom(32)
 4 #设置密匙
 5 secret_key = b'wwj'
 6 #产生加密信息
 7 h1 = hmac.new(secret_key, msg)
 8 m1 = h1.digest()
 9 
10 h2 = hmac.new(msg)
11 m2 = h2.digest()
12 
13 #比较两个加密信息是否一致
14 print(hmac.compare_digest(m1, m2))

#验证客户端链接合法性思路

1.服务端给客户端发送指定位数的随机信息

1.客户端收到此随机信息

 

2.服务端对此信息进行添加密匙的加密

2.客户端对此信息进行添加密匙的加密

 

3.客户端发送加密信息给服务端

3.服务度收到客户端的加密信息,与自己的加密信息进行比对,相同则认证通过

 1 import hmac, os
 2 
 3 msg = os.urandom(32)
 4 secret_key = b'wwj'
 5 
 6 conn.sendall(msg)
 7 h = hmac.new(secret_key, msg)
 8 digest = h.digest()
 9 respone = conn.recv(len(digest))
10 
11 print(hmac.compare_digest(digest, respone))
服务端
1 import hmac, os
2 
3 secret_key = b'wwj'
4 msg = conn.recv(32)
5 h = hmac.new(secret_key, msg)
6 digest = h.digest()
7 conn.sendall(digest)
客户端

 这样想要合法连接,需要:

1. 知道服务端的认证机制

2. 知道客户端的secret_key

 

 

posted @ 2019-12-19 17:27  Matrixssy  阅读(245)  评论(0编辑  收藏  举报