python--socket/Socketerver並發/udp


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()

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM