10.python網絡編程(socket server 實現併發 part 2)

1、基於tcp的socket通訊的基本原理分析。
json

基於tcp的socket通訊,主要依靠兩個循環,分別是鏈接循環和通訊循環。
服務器

這個前面的文章有寫過,在這裏就再也不重複了。多線程


2、socketserver實現多併發的原理分析。併發

1.server類:socket

1036857-20170505014200961-1776184607.png

2.reques類。tcp

1036857-20170505014309914-771361140.png

類繼承關係:
ide

1036857-20170505015158101-334152905.png


1036857-20170505015356492-1711228984.png

示例代碼:
this

import socketserver
import struct
import json
import os
class FtpServer(socketserver.BaseRequestHandler):
    coding='utf-8'
    server_dir='file_upload'
    max_packet_size=1024
    BASE_DIR=os.path.dirname(os.path.abspath(__file__))
    def handle(self):
        print(self.request)
        while True:
            data=self.request.recv(4)
            data_len=struct.unpack('i',data)[0]
            head_json=self.request.recv(data_len).decode(self.coding)
            head_dic=json.loads(head_json)
            # print(head_dic)
            cmd=head_dic['cmd']
            if hasattr(self,cmd):
                func=getattr(self,cmd)
                func(head_dic)
    def put(self,args):
        file_path = os.path.normpath(os.path.join(
            self.BASE_DIR,
            self.server_dir,
            args['filename']
        ))
        filesize = args['filesize']
        recv_size = 0
        print('----->', file_path)
        with open(file_path, 'wb') as f:
            while recv_size < filesize:
                recv_data = self.request.recv(self.max_packet_size)
                f.write(recv_data)
                recv_size += len(recv_data)
                print('recvsize:%s filesize:%s' % (recv_size, filesize))
ftpserver=socketserver.ThreadingTCPServer(('127.0.0.1',8080),FtpServer)
ftpserver.serve_forever()

分析開始:spa

結合上面的例子,還有類關係圖一塊看。
線程

ftpserver=socketserver.ThreadingTCPServer(('127.0.0.1',8080),FtpServer)
ftpserver.serve_forever()

查找屬性的順序:ThreadingTCPServer->ThreadingMixIn->TCPServer->BaseServer

  1. 經過ThreadingTCPServer 這個類,實例化出一個ftpserver對象。

    1.2 先從ThreadingTCPServer這個類中找__init__方法,SocketServer的源碼中能夠看到,它自己並無__init__方法,這時候就從ThreadingTCPServer所繼承的兩個父類中去找。從源碼中能夠看到ThreadingTCPServer一共繼承了兩個父類,分別是ThreadingMixIn和TCPServer,其中ThreadingMixIn中也沒有__init__方法,最終在TCPServer下找到了__init__,此時執行TCPServer下的__init__方法。



       1.3 TCPServer下的__init__方法一共作了四件事,分別是執行了BaseServer類下的__init__方法,創                                    建了socket對象,綁定了IP地址和端口(bind),以及開始listen監聽。

        BaseServer類下的__init__方法,作了兩件事,爲建立出來的對象添加了兩個屬性,分別                                            是server_address和RequestHandlerClass,其中server_address是服務端綁定的ip地址和端                        口,RequestHandlerClass是前面咱們本身建立的FtpServer類。

        (完成了bind和listen操做是由於執行了server_bind和server_active)

        

    2.Serve_forever 實現鏈接循環。

        2.1前面說了,ftpserver這個對象是由ThreadingTCPServer這個類建立出來的,因此說,默認狀況下ftpserver這個對象自己,以及ThreadingTCPServer這個類都沒有Serve_forever這個方法,依舊按照上面的套路,閱讀源碼,從ThreadingTCPServer繼承的父類中去找,分別是ThreadingMixIn和TCPServer,在這兩個父類中都沒有找到,接着去看ThreadingMixIn和TCPServer繼承的父類....關於繼承順序的概念在這也再也不贅述.....最終在BaseServer中找到了Serve_forever這個方法。


    2.2serve_forever下主要執行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)。


    2.3上述四部分完成了連接循環,本部分開始進入處理通信部分,在BaseServer中找到finish_request,觸發咱們本身定義的類的實例化,去找__init__方法,而咱們本身定義的類沒有該方法,則去它的父類也就是BaseRequestHandler中找....

 


最後總結下建立socketserver的幾個步驟。

  1. First, you must create a request handler class by subclassing the BaseRequestHandlerclass and overriding its handle() method; this method will process incoming requests.   


首先你必須建立一個類,這個類必須是BaseRequestHandler的子類,而且這個類必需要有一個handle方法,這個方法用來處理鏈接進來的請求。


2.Second, you must instantiate one of the server classes, passing it the server’s address and the request handler class.

其次你必須實例化一個服務器類,在實例化的過程當中,須要傳入服務端地址 以及 那個請求句柄的類。


3.Then call the handle_request() or serve_forever() method of the server object to process one or many requests.

而後,執行服務器對象的handle_request()或 serve_forever()方法 ,來處理一個或多個請求。


4.Finally, call server_close() to close the socket.

最後,執行server_close()這個方法關閉套接字。

相關文章
相關標籤/搜索