Socketerve並發
基於tcp套接字,關鍵就是兩個循環,一個鏈接循環,一個通訊循環
Socketserver模塊中分兩個大類:server類(解決鏈接問題)和request類(解決通信問題)
server類:

request類:

繼承關系:



以下述代碼為例,分析socketserver源碼:
ftpserver=socketserver.ThreadingTCPServer(('127.0.0.1',8080),FtpServer)
ftpserver.serve_forever()
查找屬性的順序:
ThreadingTCPServer-->ThreadingMixIn-->TCPServer-->BaseServer
1.實例化得到tfpserver,先找類ThreadingTCPServer的_init_,在TCPServer中找到,進而執行Server_bind,server_active
2.找ftpsever下的server_forever,在BaseServer中找到,進而執行self._handle_request_noblock(),該方法同樣是在BaseServer中
3.執行self._handle_request_noblcok()進而執行request,client_address=self.get_request()(就是TCPServer中的self.socket.accept()),然后執行self.process_request(request,client_address)
4.在ThreadingMiIn中找到process_request,開啟多線程應對並發,進而執行process_request_thread,self.finish_request(request,client_address)
5.上述四部分完成了鏈接循環,本部分開始進入處理通訊部分,在BaseServer中找到finish_request,觸發我們自己定義的類的實例化,去找_init_方法,而我們自己定義的類沒有該方法,則去它的父類也就是BaseRequestHandler中找
源代碼分析總結:
基於tcp的socketserver我們自己定義的類中的
1.self.server即套接字對象
2.self.request即一個鏈接
3.self.client_adderss即客戶端地址
#服務端:
import socketserver
class FTPserver(socketserver.BaseRequestHandler):#定義一個類 繼承BaseRequestHandler #進行通訊
def handle(self):
# print(self)
# print(self.request) #拿到一個conn鏈接循環
while True: #通信循環
data=self.request.recv(1024)
print(data.decode("utf-8"))
self.request.send(data.upper())
if __name__ == '__main__':
obj=socketserver.ThreadingTCPServer(("127.0.0.1",8000),FTPserver) #自己的類名
obj.serve_forever()#鏈接循環
#客戶端1
import socket
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect(("127.0.0.1",8000))
while True:
msg=input(">>").strip()
if not msg:continue
s.send(msg.encode("utf-8"))
data=s.recv(1024)
s.close()
#客戶端2
import socket
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect(("127.0.0.1",8000))
while True:
msg=input(">>").strip()
if not msg:continue
s.send(msg.encode("utf-8"))
data=s.recv(1024)
s.close()
#客戶端3
import socket
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect(("127.0.0.1",8000))
while True:
msg=input(">>").strip()
if not msg:continue
s.send(msg.encode("utf-8"))
data=s.recv(1024)
s.close()
基於UDP的套接字
udp:sendto發消息,recvfrom收消息
udp是基於數據報
sendinto:
sendinto(bytes_data,ip_port):發送數據報,bytes_data為空,還有ip_port,所有即便是發送空的bytes_data,數據報其實也不是空的,自己這端的緩沖區收到內容,操作系統就會控制udp協議發包
recvfrom:
udp協議
(1)如果如果收消息緩沖區里的數據為“空”,recvfrom也會阻塞
(2)只不過udp協議的客戶端sendinto一個空數據並不是真的空數據(包含:空數據+地址信息,得到的報仍然不會為空),所以客戶端只要有一個sendinto(不管是否發送空數據,都不是真的空數據),服務端就可以recvfrom到數據。
(3)udp無鏈接
無鏈接,因而無需listen(backlog),更加沒有什么連接池之說了
無鏈接,udp的sendinto不用管是否有一個正在運行的服務端,可以己端一個勁的發消息,只不過數據丟失
recvfrom收的數據小於sendinto發送的數據時,在mac和linux系統上數據直接丟失,在windows系統上發送的比接收的大直接報錯
只有sendinto發送數據沒有recvfrom收數據,數據丟失
udp套接字簡單示例:
#udp服務端
import socket
ip_port=("127.0.0.1",8000)
buffer_size=1024
udp_server=socket.socket(socket.AF_INET,socket.SOCK_DGRAM) #數據報
udp_server.bind(ip_port)
while True: #通信循環
data,addr=udp_server.recvfrom(buffer_size)
print(data.decode("utf-8"),addr)
msg=input(">>:")
udp_server.sendto(msg.encode("utf-8"),addr)
udp_server.sendto(data.upper(),addr)
udp_serve.close()
#udp客戶端
import socket
ip_port=("127.0.0.1",8000)
buffer_size=1024
udp_client=socket.socket(socket.AF_INET,socket.SOCK_DGRAM) #數據報
while True: #通信循環
msg=input(">>:").strip()
udp_client.sendto(msg.encode("utf-8"),ip_port) #每次發包都要指定端口
data,addr= udp_client.recvfrom(buffer_size)
print(data.decode("utf-8"))
udp_client.close()
#udp客戶端1
import socket
ip_port=("127.0.0.1",8000)
buffer_size=1024
udp_client=socket.socket(socket.AF_INET,socket.SOCK_DGRAM) #數據報
while True: #通信循環
msg=input(">>:").strip()
udp_client.sendto(msg.encode("utf-8"),ip_port) #每次發包都要指定端口
data,addr= udp_client.recvfrom(buffer_size)
print(data.decode("utf-8"))
udp_client.close()
#udp客戶端2
import socket
ip_port=("127.0.0.1",8000)
buffer_size=1024
udp_client=socket.socket(socket.AF_INET,socket.SOCK_DGRAM) #數據報
while True: #通信循環
msg=input(">>:").strip()
udp_client.sendto(msg.encode("utf-8"),ip_port) #每次發包都要指定端口
data,addr= udp_client.recvfrom(buffer_size)
print(data.decode("utf-8"))
udp_client.close()
