socketserver模块解析
socketserver模块是基于socket而来的模块,它是在socket的基础上进行了一层封装,并且实现并发等功能。
看看具体用法:
import socketserver #1、引入模块
class MyServer(socketserver.BaseRequestHandler): #2、自己写一个类,类名自己随便定义,然后继承socketserver这个模块里面的BaseRequestHandler这个类
def handle(self): #3、写一个handle方法,必须叫这个名字
#self.request #6、self.request 相当于一个conn
self.request.recv(1024) #7、收消息
msg = '亲,学会了吗'
self.request.send(bytes(msg,encoding='utf-8')) #8、发消息
self.request.close() #9、关闭连接
# 拿到了我们对每个客户端的管道,那么我们自己在这个方法里面的就写我们接收消息发送消息的逻辑就可以了
pass
if __name__ == '__mian__':
#thread 线程,现在只需要简单理解线程,别着急,后面很快就会讲到啦,看下面的图
server = socketserver.ThreadingTCPServer(('127.0.0.1',8090),MyServer)#4、使用socketserver的ThreadingTCPServer这个类,将IP和端口的元祖传进去,还需要将上面咱们自己定义的类传进去,得到一个对象,相当于我们通过它进行了bind、listen
server.serve_forever() #5、使用我们上面这个类的对象来执行serve_forever()方法,他的作用就是说,我的服务一直开启着,就像京东一样,不能关闭网站,对吧,并且serve_forever()帮我们进行了accept
#注意:
#有socketserver 那么有socketclient的吗?
#当然不会有,我要作为客户去访问京东的时候,京东帮我也客户端了吗,客户端是不是在我们自己的电脑啊,并且socketserver对客户端没有太高的要求,只需要自己写一些socket就行了。
截图
通过上面的代码,我们来分析socket的源码:
在整个socketserver这个模块中,其实就干了两件事情:
1、一个是循环建立链接的部分,每个客户链接都可以连接成功
2、一个通讯循环的部分,就是每个客户端链接成功之后,要循环的和客户端进行通信。
看代码中的:server=socketserver.ThreadingTCPServer(('127.0.0.1',8090),MyServer)
还记得面向对象的继承吗?来,大家自己尝试着看看源码:
查找属性的顺序:ThreadingTCPServer->ThreadingMixIn->TCPServer->BaseServer
实例化得到server
,先找ThreadMinxIn
中的__init__
方法,发现没有init
方法,然后找类ThreadingTCPServer
的__init_
_,在TCPServer
中找到,在里面创建了socket
对象,进而执行server_bind
(相当于bind
),server_active
(点进去看执行了listen
)
找server
下的serve_forever
,在BaseServer
中找到,进而执行self._handle_request_noblock()
,该方法同样是在BaseServer
中
执行self._handle_request_noblock()
进而执行request
, client_address = self.get_request()
(就是TCPServer中的self.socket.accept()
),然后执行self.process_request(request, client_address)
在ThreadingMixIn
中找到process_request
,开启多线程应对并发,进而执行process_request_thread
,执行self.finish_request(request, client_address)
上述四部分完成了链接循环,本部分开始进入处理通讯部分,在BaseServer中找到finish_request
,触发我们自己定义的类的实例化,去找__init__
方法,而我们自己定义的类没有该方法,则去它的父类也就是BaseRequestHandler
中找....
源码分析总结:
基于tcp的socketserver我们自己定义的类中的
-
self.server
即套接字对象 -
self.request
即一个链接 -
self.client_address
即客户端地址
基于udp的socketserver我们自己定义的类中的
-
self.request
是一个元组(第一个元素是客户端发来的数据,第二部分是服务端的udp套接字对象),如(b'adsf', <socket.socket fd=200, family=AddressFamily.AF_INET, type=SocketKind.SOCK_DGRAM, proto=0, laddr=('127.0.0.1', 8080)>)
-
self.client_address
即客户端地址
一个完整的sockeserver代码示例:
服务端代码示例:
import socketserver
class MysocketServer(socketserver.BaseRequestHandler):
def handle(self):
# self.request 相当于conn链接通道
while 1:
from_client_msg = self.request.recv(1024)
print(from_client_msg.decode("utf-8"))
server_msg = input("服务器>>>")
self.request.send(server_msg.encode("utf-8"))
if __name__ == '__main__':
ip_port = ('127.0.0.1', 8001)
server = socketserver.ThreadingTCPServer(ip_port, MysocketServer)
server.serve_forever()
client.py
import socket
client=socket.socket()
client.connect(('127.0.0.1',8001))
while 1:
msg=input('别开车>>>').encode("utf-8")
client.send(msg)
from_server_msg=client.recv(1024)
print(from_server_msg.decode("utf-8"))
client.close()