概述
之前版本的服务端,在while true的大循环中,只要来一个连接直接就进入小循环当中了。
在小链接中,只要不跳出来,服务端将一直处于这个小的通信循环当中。不能并发。
soketserver版本:
1、类Mysever就是用来实例化函数handle方法的。
2、handle方法就是收发消息的过程(通信循环)。添加异常处理
3、连接循环在if __name__ == '__main__'当中写入,只有右键运行整个程序的时候才能执行
4、类TreadingTCPServer利用类MySever实例化得到一个对象s:将通信循环Mysever嵌套在 TreadingTCPServer 当中。
实现多线程的服务端:实现并发,每来一个链接就可以通过mysever实例化建立一个收发消息handle函数来执行。
soketserver模块介绍:
虽说用Python编写简单的网络程序很方便,但复杂一点的网络程序还是用现成的框架比较好。这样就可以专心事务逻辑,而不是套接字的各种细节。SocketServer模块简化了编写网络服务程序的任务。同时SocketServer模块也是Python标准库中很多服务器框架的基础。
socketserver模块可以简化网络服务器的编写,Python把网络服务抽象成两个主要的类,一个是Server类,用于处理连接相关的网络操作,另外一个则是RequestHandler类,用于处理数据相关的操作。并且提供两个MixIn 类,用于扩展 Server,实现多进程或多线程。
socketsever中分为两大类:
第一类:sever类:专门处理链接。最基本的有五个:
它包含了种五种server类,BaseServer(不直接对外服务)。TCPServer使用TCP协议,UDPServer使用UDP协议,还有两个不常使用的,即UnixStreamServer和UnixDatagramServer,这两个类仅仅在unix环境下有用(AF_unix)。
BaseSever ------> TCPServer(UnixStreamServer)-------> UDPServer(UnixDatagramServer),
其中,TCPServer继承BaseSever,UDPServer继承TCPServer。
UnixStreamServer(只能处理Unix平台上的TCP)继承TCPServer,UnixDatagramServer继承UDPServer。这俩一般也不会用到。
#利用反射hasattr判断对象socket中是否含有AF_UNIX属性的地址家族 if hasattr(socket,"AF_UNIX")
__all__.extend(["UnixSteamServer","UnixDatagramServer","ThreadingUnixStreamServer","ThreadingUnixDatagramServer"]) #若有,则在原来的基础上添加有关unix的一系列类。 #AF_Inet基于网络的地址家族
跟并发有关的:
进程:ForkingTCPServer继承ForkingMixIn和TCPServer,ForkingUDPServer继承ForkingMixIn和UDPServer
线程:ThreadingTCPServer继承ThreadingMixIn和TCPServer,ThreadingUDPServer继承ThreadingMixIn和UDPServer
第二类:request类:处理通信
BaseRequestHandler()
StreamRequestHandler()
DatagramRequestHandler()
#服务端socketserver的TCP版本 import socketserver ''' def __init__(self, request, client_address, server): self.request = request self.client_address = client_address self.server = server self.setup() try: self.handle() finally: self.finish() ''' class MyServer(socketserver.BaseRequestHandler): def handle(self): #必须写,因为一定会需要调用。handle用于控制通讯循环 print('conn is: ',self.request) #conn print('addr is: ',self.client_address) #addr while True: try: #收消息 data=self.request.recv(1024) if not data:break print('收到客户端的消息是',data,self.client_address) #发消息 self.request.sendall(data.upper()) except Exception as e: print(e) break if __name__ == '__main__': s=socketserver.ThreadingTCPServer(('127.0.0.1',8080),MyServer) #多线程 # ThreadingTCPServer中没有init,只能找他父类中的,他继承了ThreadingMixIn和TCPServer #在ThreadingMixIn中没有,找TCPServer中也没有,继续在TCPServer的父类BaseSever中找到__init__ ''' address_family = socket.AF_INET socket_type = socket.SOCK_STREAM request_queue_size = 5 allow_reuse_address = False #不允许重新使用地址 def __init__(self,server_address,RequestHandlerClass,bind_and_activate=True): BaseServer.__init__(self,server_address,RequestHandlerClass) self.socket = socket.socket(self.address_family,self.socket_type) #就是上几行中init定义之前写好的 if bind_and_activate: #绑定IP并激活 try: self.server_bind() self.server_active() #active中self.socket.listen(self.request_queue_size) except: self.server_close() raise ''' # s=socketserver.ForkingTCPServer(('127.0.0.1',8080),MyServer) #多进程 #以下两行是init中写好的,init产生一个套接字对象,经历一个实例化过程 # self.server_address = server_address # self.RequestHandlerClass = RequestHandlerClass print(s.server_address) #('127.0.0.1',8080) print(s.RequestHandlerClass) #<class '__main__.MyServer'> print(MyServer) #<class '__main__.MyServer'> print(s.socket) #<socket.socket fd=236, family=AddressFamily.AF_INET,type=SocketKind.SOCK_STREAM,proto=0> print(s.server_address) s.serve_forever() #最终在TCPServer的父类BaseServer中找到, # forever中会while死循环一直执行来接收链接,一个request就一个链接conn,client_address接收的就是客户端地址 #当中会执行self.process_request(request,client_address) #在ThreadingMixIn中找到 #完成链接循环,MyServer(request,client_address,self) 这才是最终得到的 #同样Mysever中没有init,去找父类中的
##服务端socketserver的UDP版本,UDP当中用的不多 import socketserver class MyServer(socketserver.BaseRequestHandler): def handle(self): print(self.request) print('收到客户端的消息是',self.request[0]) self.request[1].sendto(self.request[0].upper(),self.client_address) if __name__ == '__main__': s=socketserver.ThreadingUDPServer(('127.0.0.1',8080),MyServer) #多线程 #在父类中UDPServer的父类TCPServer中的init,此时会先经历UDPServer中的一系列参数赋值 ''' class UDPServer(TCPServer): allow_reuse_address = False socket_type = socket.SOKET_DGRAM max_packet_size = 8192 def __init__() #产生UDP套接字,并进行绑定和激活 # UDPServer自己定义的激活函数server_activate什么都不用做 ''' s.serve_forever()
认证客户端的链接合法性
如果你想在分布式系统中实现一个简单的客户端链接认证功能,又不像SSL那么复杂,那么利用hmac+加盐的方式来实现
#服务端 #_*_coding:utf-8_*_ __author__ = 'Linhaifeng' from socket import * import hmac,os secret_key=b'linhaifeng bang bang bang' #用于’加盐‘ def conn_auth(conn): ''' 认证客户端链接 :param conn: :return: ''' print('开始验证新链接的合法性') msg=os.urandom(32) #产生32个字节的随机数 conn.sendall(msg) #发送给客户端 h=hmac.new(secret_key,msg) #hash验证的模块,对产生的msg数据加盐 digest=h.digest() #得到数值 respone=conn.recv(len(digest)) #接收客户端返回的hash值 return hmac.compare_digest(respone,digest) #判断服务端和客户端的hash是否相同 def data_handler(conn,bufsize=1024): #专门处理通信 if not conn_auth(conn): print('该链接不合法,关闭') conn.close() return print('链接合法,开始通信') while True: data=conn.recv(bufsize) if not data:break conn.sendall(data.upper()) def server_handler(ip_port,bufsize,backlog=5): ''' 只处理链接 :param ip_port: :return: ''' tcp_socket_server=socket(AF_INET,SOCK_STREAM) tcp_socket_server.bind(ip_port) tcp_socket_server.listen(backlog) while True: conn,addr=tcp_socket_server.accept() print('新连接[%s:%s]' %(addr[0],addr[1])) data_handler(conn,bufsize) if __name__ == '__main__': ip_port=('127.0.0.1',9999) bufsize=1024 server_handler(ip_port,bufsize)
#客户端(合法) #_*_coding:utf-8_*_ __author__ = 'Linhaifeng' from socket import * import hmac,os secret_key=b'linhaifeng bang bang bang' def conn_auth(conn): ''' 验证客户端到服务器的链接 :param conn: :return: ''' msg=conn.recv(32) h=hmac.new(secret_key,msg) digest=h.digest() conn.sendall(digest) def client_handler(ip_port,bufsize=1024): tcp_socket_client=socket(AF_INET,SOCK_STREAM) tcp_socket_client.connect(ip_port) conn_auth(tcp_socket_client) while True: data=input('>>: ').strip() if not data:continue if data == 'quit':break tcp_socket_client.sendall(data.encode('utf-8')) respone=tcp_socket_client.recv(bufsize) print(respone.decode('utf-8')) tcp_socket_client.close() if __name__ == '__main__': ip_port=('127.0.0.1',9999) bufsize=1024 client_handler(ip_port,bufsize)
#不知道加密方式 #_*_coding:utf-8_*_ __author__ = 'Linhaifeng' from socket import * def client_handler(ip_port,bufsize=1024): tcp_socket_client=socket(AF_INET,SOCK_STREAM) tcp_socket_client.connect(ip_port) while True: data=input('>>: ').strip() if not data:continue if data == 'quit':break tcp_socket_client.sendall(data.encode('utf-8')) respone=tcp_socket_client.recv(bufsize) print(respone.decode('utf-8')) tcp_socket_client.close() if __name__ == '__main__': ip_port=('127.0.0.1',9999) bufsize=1024 client_handler(ip_port,bufsize)
#知道认证方式,不知道加的什么盐 #_*_coding:utf-8_*_ __author__ = 'Linhaifeng' from socket import * import hmac,os secret_key=b'linhaifeng bang bang bang' def conn_auth(conn): ''' 验证客户端到服务器的链接 :param conn: :return: ''' msg=conn.recv(32) h=hmac.new(secret_key,msg) digest=h.digest() conn.sendall(digest) def client_handler(ip_port,bufsize=1024): tcp_socket_client=socket(AF_INET,SOCK_STREAM) tcp_socket_client.connect(ip_port) conn_auth(tcp_socket_client) while True: data=input('>>: ').strip() if not data:continue if data == 'quit':break tcp_socket_client.sendall(data.encode('utf-8')) respone=tcp_socket_client.recv(bufsize) print(respone.decode('utf-8')) tcp_socket_client.close() if __name__ == '__main__': ip_port=('127.0.0.1',9999) bufsize=1024 client_handler(ip_port,bufsize)
转载于:https://www.cnblogs.com/Josie-chen/p/9001582.html
最后
以上就是殷勤大米为你收集整理的socket实现并发soketserver版本:soketserver模块介绍: 认证客户端的链接合法性的全部内容,希望文章能够帮你解决socket实现并发soketserver版本:soketserver模块介绍: 认证客户端的链接合法性所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复