python面试笔试题,python面试题史上最全
在解析实例是如工作之前,我们先看看socektserver类的继承关系图:
请求类继承关系:
计算机网络服务器类继承关系:
有了上面的继承关系图后,我们解析实例就轻松多了,下面,我们从代码开始,慢慢揭开实例面纱:
导入实例
导入结构,json,os
类FtpServer(socketserver .BaseRequestHandler):
编码=utf-8
服务器目录=文件上传
最大数据包大小=1024
BASE _ DIR=OS。路径。dirname(OS。路径。ABS路径(_ _ file _ _))
定义句柄(自身):
打印(自我请求)
虽然正确:
data=self.request.recv(4)
data_len=struct.unpack(i ,data)[0]
head _ JSON=self。请求。recv(数据长度).解码(自编码)
head_dic=json.loads(head_json)
cmd=head_dic[cmd]
如果hasattr(self,cmd):
func=getattr(self,cmd)
func(head_dic)
定义put(自身):
及格
定义获取(自身):
及格
if __name__==__main__ :
主机,端口=本地主机,9999
使用socketserver .ThreadingTCPServer((主机,端口),FtpServer)作为服务器:
server.serve_forever()
我们通过socketserver .ThreadingTCPServer实例化对象服务器,那么此时应用调用类的__init__方法,前往ThreadingTCPServer类看看:
类threading cpserver(threading mixin,UDPServer): pass发现這个类啥都没写,我们知道,如果一个类什么方法都没有定义,那么它的方法肯定都是从其父类继承而来,接着,先到穿线最小值里面看看,
类线程混合:
daemon_threads=False
定义进程请求线程(自身,请求,客户端地址):
passdef进程请求(自身,请求,客户端地址):
及格这个类也没有__init__方法,因此,我们应该去右继承的父类服务模块中找:
服务模块类(基础服务器):
地址_家庭=套接字AF_INET。
socket_type=套接字。袜子_流
请求队列大小=5
允许重用地址=假
def __init__(self,server_address,RequestHandlerClass,bind_and_activate=True):
基础服务器.__init__(self,server_address,RequestHandlerClass)#
自我。插座=插座。插座(自身。address _ family,self.socket_type) #创建套接字对象
如果绑定并激活:
尝试:
self.server_bind() #绑定端口和互联网协议(互联网协议)
self.server_activate() #监听端口
除了:
self.server_close()
上升
看到服务模块的__init__方法,完成了以下几件事:
创建套接字,绑定端口和IP,并监听
将端口、IP和我们创建类传递到基础服务器类中;
此时,对象的初始化工作并没有完成,接着,我们要进入基础服务器类,看看该类下的__init__完成了什么工作:
类库服务器:
超时=无
def __init__(self,server_address,RequestHandlerClass):
self.server_address=服务器_地址#将端口和互联网协议(互联网协议)暂存
自我RequestHandlerClass=RequestHandlerClass #暂存我们创建的类
自我. is_shut_down=线程。事件()#创建事件对象到此,对象的初始化工作完成。然后是调用永远服务()方法,开始不断循环监听。下面,我们来看看,这个服务器_永远实现
注意:我们要清楚一点,我们在找這个方法在哪里的时候,一定要按照顺序去找,也就是说,我们先得从子类开始找,如果子类不存在,就去其父类找。下面我们就遵循這个原则来找找看。
先来看看左继承的父类穿线米辛中有没有永远的服务器:
类线程混合:
daemon_threads=False
定义进程请求线程(自身,请求,客户端地址):
尝试:
self.finish_request请求,客户端地址)
例外情况除外:
self.handle_error(请求,客户端地址)
最后:
self.shutdown _请求(请求)
定义流程请求(自身,请求,客户端地址):
t=螺纹。线程(目标=自己。进程请求线程,
args=(请求,客户端地址))
t.daemon=self.daemon_threads
启动()
再来看看父类三氯苯酚服务器:
class TCP server(BaseServer):def _ _ init _ _(self,server_address,RequestHandlerClass,bind_and_activate=True):
定义服务器_绑定(自身):
定义服务器_激活(自身):
定义服务器_关闭(自身):
定义文件号(自身):
定义get_request(自身):
定义关闭请求(自身,请求):
定义关闭请求(自身,请求):
我们发现,没有服务器_永远方法,好,我去其继承的父类基础服务器类看看:
class base server:def _ _ init _ _(self,server_address,RequestHandlerClass):
定义服务器_激活(自身):
def serve_forever(self,poll_interval=0.5):
定义关机(自我):
定义服务_活动(自身):
定义句柄_请求(自身):
def _ handle _ request _ no block(自身):
定义句柄_超时(自身):
定义验证请求(自身,请求,客户端地址):
定义流程请求(自身,请求,客户端地址):
定义服务器_关闭(自身):
定义完成请求(自身,请求,客户端地址):
定义关闭请求(自身,请求):
定义关闭请求(自身,请求):
定义句柄_错误(自身,请求,客户端_地址):
def __enter__(自身):
def __exit__(self,*args):
我们发现server_forever()果然在這个类中,现在,我们的目标是:找到在什么地方调用我们自己写的处理方法。
在我们找到的server_forever()方法中,
def serve_forever(self,poll_interval=0.5):
自我_ _ is _ shut _ down.clear()
尝试:
使用_ServerSelector()作为选择器:
选择器.寄存器(自身,选择器。事件_读取)#原来底层是用使用来实现不断循环监听
而不是自我。_ _关闭请求:
就绪=选择器。select(poll_interval) #有新的链接进来
如果准备好了:
自我. handle_request_noblock() #这里应该是处理新的链接
self.service_actions()
最后:
自我。_ _关闭请求=假
自我. is_shut_down.set()
好,我大致找到了链接的处理入口,我们跟进去,继续寻找:
def _ handle _ request _ no block(自身):
尝试:
请求,客户端地址=self.get请求()
除了o错误:
返回
if self.verify_request(请求,客户端地址):
尝试:
self.process _请求(请求,客户端地址)#注意这里的流程请求()
例外情况除外:
self.handle_error(请求,客户端地址)
self.shutdown _请求(请求)
除了:
self.shutdown _请求(请求)
上升
否则:
self.shutdown _请求(请求)
到源码中,我们找到该函数,现在,只看我划线的部分。其他部分都是针对异常的处理,如果没有异常,其他都是不会执行的,所以,其他的异常处理,我们先暂时不看。
我们发现,如果有链接,最后会交给进程请求()(我们会发现,在基础服务器类和穿线米辛都有這个方法,这里找类方法,一定要按照类的继承顺序来查找),所以,我们到穿线米辛中去看看processs _ request()做了哪些事情:
定义流程请求(自身,请求,客户端地址):
t=螺纹。线程(目标=自己。process _ request _ thread,args=(请求,客户端地址))#原来开了一个线程,支持并发
t.daemon=self.daemon_threads #开启守护线程
启动()在线程中执行该类下的process_requsest_thread()方法,
定义进程请求线程(自身,请求,客户端地址):
尝试:
self.finish_request请求,客户端地址)
例外情况除外:
self.handle_error(请求,客户端地址)
最后:
self.shutdown _请求(请求)
到此为止,链接建立成功!
下面,我们来看看,当有消息发送,是如何进行处理的。
当有消息发送,选择器监听到了,
def serve_forever(self,poll_interval=0.5):
自我_ _ is _ shut _ down.clear()
尝试:
使用_ServerSelector()作为选择器:
选择器.寄存器(自身,选择器。事件_读取)#监听了活动链接
而不是自我。_ _关闭请求:
就绪=选择器。选择(轮询间隔)
如果准备好了:#准备好了
自我. handle_request_noblock() #进入处理
self.service_actions()
最后:
自我。_ _关闭请求=假
自我. is_shut_down.set()
下面我们跟进_handle_request_noblock(),
def _ handle _ request _ no block(自身):
尝试:
请求,客户端地址=self.get请求()
除了o错误:
返回
if self.verify_request(请求,客户端地址):
尝试:
self.process _请求(请求,客户端地址)
例外情况除外:
self.handle_error(请求,客户端地址)
self.shutdown _请求(请求)
除了:
self.shutdown _请求(请求)
上升
否则:
self.shutdown _请求(请求)
我们到流程请求()看看:
定义流程请求(自身,请求,客户端地址):
启动一个新线程来处理请求。
t=螺纹.线程(目标=自身。进程请求线程,#启动一个线程来处理请求
args=(请求,客户端地址))
t.daemon=self.daemon_threads
启动()
然后开启线程执行,进程请求线程()方法,
定义进程请求线程(自身,请求,客户端地址):
尝试:
self.finish_request(request,client _ address)#-到基础服务器查找
例外情况除外:
self.handle_error(请求,客户端地址)
最后:
self.shutdown _请求(请求)
然后调用完成请求()方法,现在我们跟进看看,
定义完成请求(自身,请求,客户端地址):
自我RequestHandlerClass(请求,客户端地址,自身)执行了请求句柄类(请求,客户端地址,自身),這个是啥?还记得最开始我们传进来的类保存在哪呢?没错,就是RequestHandlerClass里面,现在这里才开始实例化這个类,也就是说,在这里开始调用我们自己的类了。既然是调用我们自己的类,那么必然要实例化,我们先回到自己创建的类,找找__init__方法。
类MyTCPHandler(socketserver .BaseRequestHandler):
定义句柄(自身):
自我。数据=自身。请求。第1024号建议.条状()
打印( {}写道:。格式(self.client_address[0])
打印(自我数据)
自我。请求。sendall(自我。数据。upper())自己类没有写__init__方法,那么我去它继承的BaseRequestHandler()下面找找看:
类BaseRequestHandler:
def __init__(自身,请求,客户端地址,服务器):
自我请求=请求编号接受传进来的请求链接
self.client_address=客户端地址#客户端的ip/端口
self.server=服务器#
self.setup()
尝试:
self.handle()
最后:
self.finish()
定义设置(自身):
及格
定义句柄(自身):
及格
定义完成时间(自身):
及格
我们来看看,它继承类实例化完成了哪些操作:
调用手柄()方法,我们发现,在这个类中也有一个手柄()方法,那么这里调用时调用自己写的还是這个类中的呢?
当然是调用我们自己写!
至此,我们完成了一次通信的完整过程!
总结sockerserver整个流程:
1.开启了线程,支持并发操作
2.输入-输出多路复用,监听多个文件描述符!
参考
在解析实例是如工作之前,我们先看看socektserver类的继承关系图:
请求类继承关系:
计算机网络服务器类继承关系:
有了上面的继承关系图后,我们解析实例就轻松多了,下面,我们从代码开始,慢慢揭开实例面纱:
导入实例
导入结构,json,os
类FtpServer(socketserver .BaseRequestHandler):
编码=utf-8
服务器目录=文件上传
最大数据包大小=1024
BASE _ DIR=OS。路径。dirname(OS。路径。ABS路径(_ _ file _ _))
定义句柄(自身):
打印(自我请求)
虽然正确:
data=self.request.recv(4)
data_len=struct.unpack(i ,data)[0]
head _ JSON=self。请求。recv(数据长度).解码(自编码)
head_dic=json.loads(head_json)
cmd=head_dic[cmd]
如果hasattr(self,cmd):
func=getattr(self,cmd)
func(head_dic)
定义put(自身):
及格
定义获取(自身):
及格
if __name__==__main__ :
主机,端口=本地主机,9999
使用socketserver .ThreadingTCPServer((主机,端口),FtpServer)作为服务器:
server.serve_forever()
我们通过socketserver .ThreadingTCPServer实例化对象服务器,那么此时应用调用类的__init__方法,前往ThreadingTCPServer类看看:
类threading cpserver(threading mixin,UDPServer): pass发现這个类啥都没写,我们知道,如果一个类什么方法都没有定义,那么它的方法肯定都是从其父类继承而来,接着,先到穿线最小值里面看看,
类线程混合:
daemon_threads=False
定义进程请求线程(自身,请求,客户端地址):
passdef进程请求(自身,请求,客户端地址):
及格这个类也没有__init__方法,因此,我们应该去右继承的父类服务模块中找:
服务模块类(基础服务器):
地址_家庭=套接字AF_INET。
socket_type=套接字。袜子_流
请求队列大小=5
允许重用地址=假
def __init__(self,server_address,RequestHandlerClass,bind_and_activate=True):
基础服务器.__init__(self,server_address,RequestHandlerClass)#
自我。插座=插座。插座(自身。address _ family,self.socket_type) #创建套接字对象
如果绑定并激活:
尝试:
self.server_bind() #绑定端口和互联网协议(互联网协议)
self.server_activate() #监听端口
除了:
self.server_close()
上升
看到服务模块的__init__方法,完成了以下几件事:
创建套接字,绑定端口和IP,并监听
将端口、IP和我们创建类传递到基础服务器类中;
此时,对象的初始化工作并没有完成,接着,我们要进入基础服务器类,看看该类下的__init__完成了什么工作:
类库服务器:
超时=无
def __init__(self,server_address,RequestHandlerClass):
self.server_address=服务器_地址#将端口和互联网协议(互联网协议)暂存
自我RequestHandlerClass=RequestHandlerClass #暂存我们创建的类
自我. is_shut_down=线程。事件()#创建事件对象到此,对象的初始化工作完成。然后是调用永远服务()方法,开始不断循环监听。下面,我们来看看,这个服务器_永远实现
注意:我们要清楚一点,我们在找這个方法在哪里的时候,一定要按照顺序去找,也就是说,我们先得从子类开始找,如果子类不存在,就去其父类找。下面我们就遵循這个原则来找找看。
先来看看左继承的父类穿线米辛中有没有永远的服务器:
类线程混合:
daemon_threads=False
定义进程请求线程(自身,请求,客户端地址):
尝试:
self.finish_request请求,客户端地址)
例外情况除外:
self.handle_error(请求,客户端地址)
最后:
self.shutdown _请求(请求)
定义流程请求(自身,请求,客户端地址):
t=螺纹。线程(目标=自己。进程请求线程,
args=(请求,客户端地址))
t.daemon=self.daemon_threads
启动()
再来看看父类三氯苯酚服务器:
class TCP server(BaseServer):def _ _ init _ _(self,server_address,RequestHandlerClass,bind_and_activate=True):
定义服务器_绑定(自身):
定义服务器_激活(自身):
定义服务器_关闭(自身):
定义文件号(自身):
定义get_request(自身):
定义关闭请求(自身,请求):
定义关闭请求(自身,请求):
我们发现,没有服务器_永远方法,好,我去其继承的父类基础服务器类看看:
class base server:def _ _ init _ _(self,server_address,RequestHandlerClass):
定义服务器_激活(自身):
def serve_forever(self,poll_interval=0.5):
定义关机(自我):
定义服务_活动(自身):
定义句柄_请求(自身):
def _ handle _ request _ no block(自身):
定义句柄_超时(自身):
定义验证请求(自身,请求,客户端地址):
定义流程请求(自身,请求,客户端地址):
定义服务器_关闭(自身):
定义完成请求(自身,请求,客户端地址):
定义关闭请求(自身,请求):
定义关闭请求(自身,请求):
定义句柄_错误(自身,请求,客户端_地址):
def __enter__(自身):
def __exit__(self,*args):
我们发现server_forever()果然在這个类中,现在,我们的目标是:找到在什么地方调用我们自己写的处理方法。
在我们找到的server_forever()方法中,
def serve_forever(self,poll_interval=0.5):
自我_ _ is _ shut _ down.clear()
尝试:
使用_ServerSelector()作为选择器:
选择器.寄存器(自身,选择器。事件_读取)#原来底层是用使用来实现不断循环监听
而不是自我。_ _关闭请求:
就绪=选择器。select(poll_interval) #有新的链接进来
如果准备好了:
自我. handle_request_noblock() #这里应该是处理新的链接
self.service_actions()
最后:
自我。_ _关闭请求=假
自我. is_shut_down.set()
好,我大致找到了链接的处理入口,我们跟进去,继续寻找:
def _ handle _ request _ no block(自身):
尝试:
请求,客户端地址=self.get请求()
除了o错误:
返回
if self.verify_request(请求,客户端地址):
尝试:
self.process _请求(请求,客户端地址)#注意这里的流程请求()
例外情况除外:
self.handle_error(请求,客户端地址)
self.shutdown _请求(请求)
除了:
self.shutdown _请求(请求)
上升
否则:
self.shutdown _请求(请求)
到源码中,我们找到该函数,现在,只看我划线的部分。其他部分都是针对异常的处理,如果没有异常,其他都是不会执行的,所以,其他的异常处理,我们先暂时不看。
我们发现,如果有链接,最后会交给进程请求()(我们会发现,在基础服务器类和穿线米辛都有這个方法,这里找类方法,一定要按照类的继承顺序来查找),所以,我们到穿线米辛中去看看processs _ request()做了哪些事情:
定义流程请求(自身,请求,客户端地址):
t=螺纹。线程(目标=自己。process _ request _ thread,args=(请求,客户端地址))#原来开了一个线程,支持并发
t.daemon=self.daemon_threads #开启守护线程
启动()在线程中执行该类下的process_requsest_thread()方法,
定义进程请求线程(自身,请求,客户端地址):
尝试:
self.finish_request请求,客户端地址)
例外情况除外:
self.handle_error(请求,客户端地址)
最后:
self.shutdown _请求(请求)
到此为止,链接建立成功!
下面,我们来看看,当有消息发送,是如何进行处理的。
当有消息发送,选择器监听到了,
def serve_forever(self,poll_interval=0.5):
自我_ _ is _ shut _ down.clear()
尝试:
使用_ServerSelector()作为选择器:
选择器.寄存器(自身,选择器。事件_读取)#监听了活动链接
而不是自我。_ _关闭请求:
就绪=选择器。选择(轮询间隔)
如果准备好了:#准备好了
自我. handle_request_noblock() #进入处理
self.service_actions()
最后:
自我。_ _关闭请求=假
自我. is_shut_down.set()
下面我们跟进_handle_request_noblock(),
def _ handle _ request _ no block(自身):
尝试:
请求,客户端地址=self.get请求()
除了o错误:
返回
if self.verify_request(请求,客户端地址):
尝试:
self.process _请求(请求,客户端地址)
例外情况除外:
self.handle_error(请求,客户端地址)
self.shutdown _请求(请求)
除了:
self.shutdown _请求(请求)
上升
否则:
self.shutdown _请求(请求)
我们到流程请求()看看:
定义流程请求(自身,请求,客户端地址):
启动一个新线程来处理请求。
t=螺纹.线程(目标=自身。进程请求线程,#启动一个线程来处理请求
args=(请求,客户端地址))
t.daemon=self.daemon_threads
启动()
然后开启线程执行,进程请求线程()方法,
定义进程请求线程(自身,请求,客户端地址):
尝试:
self.finish_request(request,client _ address)#-到基础服务器查找
例外情况除外:
self.handle_error(请求,客户端地址)
最后:
self.shutdown _请求(请求)
然后调用完成请求()方法,现在我们跟进看看,
定义完成请求(自身,请求,客户端地址):
自我RequestHandlerClass(请求,客户端地址,自身)执行了请求句柄类(请求,客户端地址,自身),這个是啥?还记得最开始我们传进来的类保存在哪呢?没错,就是RequestHandlerClass里面,现在这里才开始实例化這个类,也就是说,在这里开始调用我们自己的类了。既然是调用我们自己的类,那么必然要实例化,我们先回到自己创建的类,找找__init__方法。
类MyTCPHandler(socketserver .BaseRequestHandler):
定义句柄(自身):
自我。数据=自身。请求。第1024号建议.条状()
print({}写道:。format(self.client_address[0])
打印(自我数据)
自我。request.sendall (self。data.upper())没有在自己的类中编写__init__方法,所以我将在其继承的BaseRequestHandler()下查找它:
类BaseRequestHandler:
def __init__(自身,请求,客户端地址,服务器):
Self.request=request #接受传入请求链接
self . client _ address=client _ address #客户端的ip/端口
self.server=服务器#
self.setup()
尝试:
self.handle()
最后:
self.finish()
定义设置(自身):
及格
定义句柄(自身):
及格
定义完成时间(自身):
及格
让我们看看它通过继承类实例化做了什么:
在调用handle()方法时,我们发现这个类中也有一个handle()方法。那么,在这里调用的时候,是自己写的,还是这个班写的?
当然,叫我们自己写!
至此,我们完成了一个完整的沟通过程!
总结sockerserver的整个流程:
1.启动线程并支持并发操作。
2.I/O多路复用,监听多个文件描述符!
涉及
转载请联系作者取得转载授权,否则将追究法律责任。
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。