python開發學習-day08(socket高級、socketserver、進程、線程)

s12-20160305-day08html

pytho自動化開發 day08

Date:2016.03.05

@南非波波

課程大綱:python

day07git

http://www.cnblogs.com/alex3714/articles/5213184.htmlgithub

day08web

http://www.cnblogs.com/alex3714/articles/5227251.html編程

推薦電影

絕美之城  上帝之城 | 千與千尋  龍貓 卡爾的移動城堡

經過實例私有變量,須要將在類中封裝一個方法,該方法返回私有變量的值canvas

1、socket深刻

1.概念api

Unix的進程通訊機制。一個完整的socket有一個本地惟一的socket號,由操做系統分配。socket是面向客戶/服務器模型而設計的,針對客戶和服務器程序提供不一樣的socket系統調用。socket利用客戶/服務器模式巧妙的解決了進程之間創建通訊鏈接的問題。

套接字(socket)是通訊的基石,是支持TCP/IP協議的網絡通訊的基本操做單元。它是網絡通訊過程當中端點的抽象表示,包含進行網絡通訊必須的五種信息:鏈接使用的協議,本地主機的IP地址,本地進程的協議端口,遠地主機的IP地址,遠地進程的協議端口。

2.地址簇ruby

socket.AF_UNIX unix本機進程間通訊 
socket.AF_INET 使用IPV4地址協議進行進程間通訊
socket.AF_INET6  使用IPV6地址協議進行進程間通訊

3.套接字類型服務器

socket.SOCK_STREAM  #使用tcp協議
socket.SOCK_DGRAM   #使用udp協議
socket.SOCK_RAW     #原始套接字,普通的套接字沒法處理ICMP、IFMP等網絡報文,而SOCK_RAM能夠。其次SOCK_RAM也能夠處理特殊的IPV4報文,此外,利用原始套接字能夠經過IP_HDRINCL套接字選項由用戶構造IP頭。
socket.SOCK_RDM    #是一種可靠的UDP形式,即保證交付數據報但不保證順序。SOCK_RAW用來提供對原始協議的低級訪問,在須要執行某些特殊操做時使用,如發送ICMP報文。SOCK_RAW一般僅限於高級用戶或管理員運行的程序使用。

4.socket方法

1. socket.socket(family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None)
2. socket.socketpair([family[, type[, proto]]])
3. socket.create_connection(address[, timeout[, source_address]])
4. socket.getaddrinfo(host, port, family=0, type=0, proto=0, flags=0) 
    獲取要鏈接的對端主機地址
5. sk.bind(address) 
    將套接字綁定到地址,地址的格式取決於地址簇。在AF_INET下,以元組(host.port)的形式表示地址。
6. sk.listen(backlog) 
    開始監聽傳入的鏈接,backlog指定在拒絕鏈接以前,能夠掛起的最大鏈接數量。backlog等於5,表示內核已經鏈接到鏈接請求,但服務器尚未調用accept進行處理的鏈接個數最大爲5.這個值根據內核和服務器物理配置進行設置。
7. sk.setblocking(bool) 
    是否阻塞(默認True),若是設置爲False,那麼accept和recv時一旦無數據則報錯。
8. sk.accept() 
    接受鏈接並返回(conn,address),其中conn是新的套接字對象,能夠用來接收和發送數據,address是鏈接客戶端的地址。接收TCP客戶的鏈接(阻塞式)等待鏈接的到來。
9. sk.connect(address)
    鏈接到address處的套接字。通常,address的格式爲元組(hostname,port),若是鏈接出錯,返回socket.err錯誤。
10. sk.connect_ex(address)
    同上,只是會有返回值,鏈接成功時返回0,鏈接失敗時會返回編碼,例如:10061
11. sk.close()
    關閉套接字
12. sk.recv(bufsize[,flag])
    接收套接字的數據,數據以字符串形式返回。bufsize指定最多能夠接收的數量,建議不要超過1024*8。flag提供有關消息的其餘信息。一般能夠忽略。
13. sk.recvfrom(bufsize[.flag])
    與recv()相似,但返回值是(data,address)。其中data是包含接收數據的字符串,address是發送數據的套接字地址
14. sk.send(string[,flag])
    將string中的數據發送到鏈接的套接字,返回值是要發送的字節數量,該數量可能小於string的字節大小,即:可能未壯指定內容所有發送
15. sk.sendall(string[,flag])
    將string中的數據發送到鏈接的套接字,但在返回以前會嘗試發送全部數據。成功返回None,失敗則跑出異常。內部經過遞歸調用send將全部內容發送出去。
16. sk.sendto(string[,flag],address)
    將數據發送到套接字,address是形式爲(ipaddr,port)的元組,指定遠程地址。返回值是發送的字節數。該函數主要用於UDP協議。
17. sk.settimeout(timeout)
    設置套接字操做的超時期,timeout是一個浮點數,單位是秒。值爲None表示沒有超時期。通常,超時期應該在剛建立套接字時設置,由於它們可能用於鏈接的操做(如 client 鏈接最多等待5s )
18. sk.getpeername()
    返回鏈接套接字的遠程地址。返回值一般是元組(ipaddr,port)
19. sk.getsockname()
    返回套接字本身的地址,一般在是一個元組(ipaddr,port)
20. socket.gethostname()
    獲取程序運行所在計算機的主機名
21. gethostbyname(name) 
    嘗試將給定的主機名解釋爲一個IP地址。首先將檢查當前計算機是否可以解釋。若是不能,一個解釋請求將發送給一個遠程的DNS服務器(遠程的DNS服務器 還可能將解釋請求轉發給另外一個DNS服務器,直到該請求能夠被處理)。gethostbyname函數返回這個IP地址或在查找失敗後引起一個異常。例如: socket.gethostbyname('www.apicloud.com')
    擴展形式:socket.gethostbyname_ex('www.apicloud.com')
    ('98e86f98d416f10c.7cname.com', ['www.apicloud.com'], ['117.25.140.17'])
    它返回一個包含三個元素的元組,分別是給定地址的主要的主機名、同一IP地址的可選的主機名的一個列表、關於同一主機的同一接口的其它IP地址的一個列表(列表可能都是空的)。
22. gethostbyaddr(address)
    函數的做用與gethostbyname_ex相同,只是你提供給它的參數是一個IP地址字符串。
    socket.gethostbyaddr('202.165.102.205')
    ('homepage.vip.cnb.yahoo.com', ['www.yahoo.com.cn'], ['202.165.102.205'])
23. getservbyname(service,protocol)
    函數要求一個服務名(如'telnet'或'ftp')和一個協議(如'tcp'或'udp'),返回服務所使用的端口號:
    >>> socket.getservbyname('http','tcp')
    80
    >>> socket.getservbyname('https','tcp')
    443
    >>> socket.getservbyname('telnet','tcp')
24. sk.fileno()
    套接字的文件描述符
    socket.sendfile(file, offset=0, count=None)
    發送文件 ,但目前多數狀況下並沒有什麼卵用

2、socketserver

參考連接:http://my.oschina.net/u/1433482/blog/190612

SocketServer簡化了網絡服務器的編寫。它有4個類:TCPServer,UDPServer,UnixStreamServer,UnixDatagramServer。這4個類是同步進行處理的,另外經過ForkingMixIn和ThreadingMixIn類來支持異步。

建立服務器的步驟

首先,你必須建立一個請求處理類,它是BaseRequestHandler的子類並重載其handle()方法。其次,你必須實例化一個服務器類,傳入服務器的地址和請求處理程序類。最後,調用handle_request()(通常是調用其餘事件循環或者使用select())或serve_forever()。

服務器類型

5種類型:BaseServer,TCPServer,UnixStreamServer,UDPServer,UnixDatagramServer。 注意:BaseServer不直接對外服務。

服務器對象

class SocketServer.BaseServer:這是模塊中的全部服務器對象的超類。它定義了接口,以下所述,可是大多數的方法不實現,在子類中進行細化。

BaseServer.fileno():返回服務器監聽套接字的整數文件描述符。一般用來傳遞給select.select(), 以容許一個進程監視多個服務器。

BaseServer.handle_request():處理單個請求。處理順序:get_request(), verify_request(), process_request()。若是用戶提供handle()方法拋出異常,將調用服務器的handle_error()方法。若是self.timeout內沒有請求收到, 將調用handle_timeout()並返回handle_request()。

BaseServer.serve_forever(poll_interval=0.5): 處理請求,直到一個明確的shutdown()請求。每poll_interval秒輪詢一次shutdown。忽略self.timeout。若是你須要作週期性的任務,建議放置在其餘線程。

BaseServer.shutdown():告訴serve_forever()循環中止並等待其中止。python2.6版本。

BaseServer.address_family: 地址家族,好比socket.AF_INET和socket.AF_UNIX。

BaseServer.RequestHandlerClass:用戶提供的請求處理類,這個類爲每一個請求建立實例。

BaseServer.server_address:服務器偵聽的地址。格式根據協議家族地址的各不相同,請參閱socket模塊的文檔。

BaseServer.socketSocket:服務器上偵聽傳入的請求socket對象的服務器。

服務器類支持下面的類變量:

BaseServer.allow_reuse_address:服務器是否容許地址的重用。默認爲false ,而且可在子類中更改。

BaseServer.request_queue_size

請求隊列的大小。若是單個請求須要很長的時間來處理,服務器忙時請求被放置到隊列中,最多能夠放request_queue_size個。一旦隊列已滿,來自客戶端的請求將獲得 「Connection denied」錯誤。默認值一般爲5 ,但能夠被子類覆蓋。

BaseServer.socket_type:服務器使用的套接字類型; socket.SOCK_STREAM和socket.SOCK_DGRAM等。

BaseServer.timeout:超時時間,以秒爲單位,或 None表示沒有超時。若是handle_request()在timeout內沒有收到請求,將調用handle_timeout()。

下面方法能夠被子類重載,它們對服務器對象的外部用戶沒有影響。

BaseServer.finish_request():實際處理RequestHandlerClass發起的請求並調用其handle()方法。 經常使用。

BaseServer.get_request():接受socket請求,並返回二元組包含要用於與客戶端通訊的新socket對象,以及客戶端的地址。

BaseServer.handle_error(request, client_address):若是RequestHandlerClass的handle()方法拋出異常時調用。默認操做是打印traceback到標準輸出,並繼續處理其餘請求。

BaseServer.handle_timeout():超時處理。默認對於forking服務器是收集退出的子進程狀態,threading服務器則什麼都不作。

BaseServer.process_request(request, client_address) :調用finish_request()建立RequestHandlerClass的實例。若是須要,此功能能夠建立新的進程或線程來處理請求,ForkingMixIn和ThreadingMixIn類作到這點。經常使用。

BaseServer.server_activate():經過服務器的構造函數來激活服務器。默認的行爲只是監聽服務器套接字。可重載。

BaseServer.server_bind():經過服務器的構造函數中調用綁定socket到所需的地址。可重載。

BaseServer.verify_request(request, client_address):返回一個布爾值,若是該值爲True ,則該請求將被處理,反之請求將被拒絕。此功能能夠重寫來實現對服務器的訪問控制。默認的實現始終返回True。client_address能夠限定客戶端,好比只處理指定ip區間的請求。 經常使用。

請求處理器

處理器接收數據並決定如何操做。它負責在socket層之上實現協議(i.e., HTTP, XML-RPC, or AMQP),讀取數據,處理並寫反應。能夠重載的方法以下:

setup(): 準備請求處理. 默認什麼都不作,StreamRequestHandler中會建立文件相似的對象以讀寫socket.

handle(): 處理請求。解析傳入的請求,處理數據,併發送響應。默認什麼都不作。經常使用變量:self.request,self.client_address,self.server。

finish(): 環境清理。默認什麼都不作,若是setup產生異常,不會執行finish。

一般只須要重載handle。self.request的類型和數據報或流的服務不一樣。對於流服務,self.request是socket 對象;對於數據報服務,self.request是字符串和socket 。能夠在子類StreamRequestHandler或DatagramRequestHandler中重載,重寫setup()和finish() ,並提供self.rfile和self.wfile屬性。 self.rfile和self.wfile能夠讀取或寫入,以得到請求數據或將數據返回到客戶端。

示例代碼

  1. server

    #!/usr/local/env python3
    '''
    Author:@南非波波
    Blog:http://www.cnblogs.com/songqingbo/
    E-mail:qingbo.song@gmail.com
    '''
    import socketserver
    
    class MyHandleServer(socketserver.BaseRequestHandler):
        '''
        定義一個測試socketserver類
        '''
        def handle(self):
            '''
            定義一個函數,用來處理每一個客戶端發來的請求
            :return:
            '''
            print("新創建一個鏈接:",self.client_address)
            while True:
                try:
                    client_data = self.request.recv(1024)
                    if not client_data:
                        print("客戶端發送的數據爲空,主動斷開!",self.client_address)
                        break
                    print("客戶端發來的請求:",client_data.decode())
                    self.request.send(client_data)
                except ConnectionResetError:
                    print("客戶端主動斷開!",self.client_address)
                    break
    
    if __name__ == "__main__":
        HOST,PORT = "127.0.0.1",5000
        server = socketserver.ThreadingTCPServer((HOST,PORT),MyHandleServer)
        server.serve_forever()
  2. client

    #!/usr/local/env python3
    '''
    Author:@南非波波
    Blog:http://www.cnblogs.com/songqingbo/
    E-mail:qingbo.song@gmail.com
    '''
    import socket
    
    ip_port = ("127.0.0.1",5000)
    
    sk = socket.socket()
    sk.connect(ip_port)
    while True:
        msg = input(">>:").strip()
        if not msg:
            break
        sk.sendall(bytes(msg,"utf8"))
        server_reply = sk.recv(1024)
        print("服務端返回:",str(server_reply,"utf8"))
    sk.close()

3、異常處理

http://www.cnblogs.com/wupeiqi/articles/5017742.html

  1. 異常基礎(python3的寫法)

    在編程過程當中爲了增長友好性,在程序出現bug時通常不會將錯誤信息顯示給用戶,而是顯示一個提示的頁面,通俗來講就是不讓用戶看見代碼出錯的頁面

    try:
        pass
    except Exception as ex:
        pass
  2. 異常種類

    經常使用異常:

    AttributeError 試圖訪問一個對象沒有的樹形,好比foo.x,可是foo沒有屬性x
    IOError 輸入/輸出異常;基本上是沒法打開文件
    ImportError 沒法引入模塊或包;基本上是路徑問題或名稱錯誤
    IndentationError 語法錯誤(的子類) ;代碼沒有正確對齊
    IndexError 下標索引超出序列邊界,好比當x只有三個元素,卻試圖訪問x[5]
    KeyError 試圖訪問字典裏不存在的鍵
    KeyboardInterrupt Ctrl+C被按下
    NameError 使用一個還未被賦予對象的變量
    SyntaxError Python代碼非法,代碼不能編譯(我的認爲這是語法錯誤,寫錯了)
    TypeError 傳入對象類型與要求的不符合
    UnboundLocalError 試圖訪問一個還未被設置的局部變量,基本上是因爲另有一個同名的全局變量,
    致使你覺得正在訪問它
    ValueError 傳入一個調用者不指望的值,即便值的類型是正確的

    更多種類:

    ArithmeticError
    AssertionError
    AttributeError
    BaseException
    BufferError
    BytesWarning
    DeprecationWarning
    EnvironmentError
    EOFError
    Exception  #捕獲通常的全部異常
    FloatingPointError
    FutureWarning
    GeneratorExit
    ImportError  #捕獲導入模塊異常
    ImportWarning
    IndentationError
    IndexError  #捕獲索引異常
    IOError  #捕獲IO異常
    KeyboardInterrupt  #捕獲鍵盤組合鍵異常
    KeyError
    LookupError
    MemoryError
    NameError
    NotImplementedError
    OSError
    OverflowError
    PendingDeprecationWarning
    ReferenceError
    RuntimeError
    RuntimeWarning
    StandardError
    StopIteration
    SyntaxError
    SyntaxWarning
    SystemError
    SystemExit
    TabError
    TypeError
    UnboundLocalError
    UnicodeDecodeError
    UnicodeEncodeError
    UnicodeError
    UnicodeTranslateError
    UnicodeWarning
    UserWarning
    ValueError
    Warning
    ZeroDivisionError
  3. 自定義異常類

    #!/usr/local/env python3
    '''
    Author:@南非波波
    Blog:http://www.cnblogs.com/songqingbo/
    E-mail:qingbo.song@gmail.com
    '''
    class SwhtError(Exception):
        '''
        自定義異常
        '''
        def __init__(self,msg):
            '''
            初始化函數
            :param msg:用戶輸入message
            :return:
            '''
            self.message = msg
    
        def __str__(self): #名稱能夠自行定義,只是經過該方法返回message的值
            '''
            返回用戶輸入的信息
            :return:
            '''
            return self.message
    
    try:
        raise SwhtError("這是一個致命的錯誤!")
    except Exception as e:
        print("dsdsd",e)
  4. 示例代碼:

    dic = ["swht", 'shen']
    try:
        dic[10]
    except IndexError as e:
        print("IndexError:",e)
    
    dic = {'k1':'v1'}
    try:
        dic['k20']
    except KeyError as e:
        print("keyError:",e)
    
    s1 = 'hello'
    try:
        int(s1)
    except ValueError as e:
        print("ValueError:",e)
  5. 特殊異常

    雖然python自帶的一個處理萬能異常類Exception,可是並非有一些異常都能被捕獲的。若是要想捕獲這些特殊的異常,就須要進行自定義異常類

  6. 異常其餘架構

    try:
        # 主代碼塊
        pass
    except KeyError as e:
        # 異常時,執行該塊
        pass
    else:
        # 主代碼塊執行完,執行該塊
        pass
    finally:
        # 不管異常與否,最終執行該塊
        pass
  7. 主動觸發異常

    try:
        raise Exception('錯誤了。。。')
    except Exception as e:
        print("Error",e)
  8. Asser斷言:

    相當重要的判斷,強制判斷前面的業務結果是否符合要求,不然就拋出異常

    a = 1
    try:
        assert a == 2
        print("True")
    except Exception as e:
        print("False",e)

4、進程與線程

  1. 概念

    1. 進程

      一個具備必定獨立功能的程序關於某個數據集合的一次運行活動,是系統進行資源分配和調度運行的基本單位
    2. 線程

      線程是操做系統可以進行運算調度的最小單位。它被包含在進程之中,是進程中的實際運做單位。一條線程指的是進程中一個單一順序的控制流,一個進程中能夠併發多個線程,每條線程並行執行不一樣的任務
    3. 進程與線程的區別

      1. 進程是一個動態的概念
      
      進程是程序的一次執行過程,是動態概念
      
      程序是一組有序的指令集和,是靜態概念
      
      2. 不一樣的進程能夠執行同一個程序
      
      區分進程的條件:所執行的程序和數據集合。
      
      兩個進程即便執行在相同的程序上,只要他們運行在不一樣的數據集合上,他們也是兩個進程。例如:多個用戶同時調用同一個編譯程序編譯他們編寫的C語言源程序,因爲編譯程序運行在不一樣的數據集合(不一樣的C語言源程序)上,因而產生了一個個不一樣的進程
      
      3. 每一個進程都有本身的生命週期
      
      當操做系統要完成某個任務時,它會建立一個進程。當進程完成任務以後,系統就會撤銷這個進程,收回它所佔用的資源。從建立到撤銷的時間段就是進程的生命期
      
      4. 進程之間存在併發性
      
      在一個系統中,同時會存在多個進程。他們輪流佔用CPU和各類資源
      
      5. 進程間會相互制約
      
      進程是系統中資源分配和運行調度的單位,在對資源的共享和競爭中,必然相互制約,影響各自向前推動的速度
      
      6. 進程能夠建立子進程,程序不能建立子程序
      
      7. 從結構上講,每一個進程都由程序、數據和一個進程控制塊(Process Control Block, PCB)組成
  2. 進程鎖

Python threading模塊

1.  線程的兩種調用方式
    1.  直接調用
    2.  繼承式調用
2.  join&&Demo
3.  線程鎖
    1.  互斥鎖
    2.  遞歸鎖
    3.  Semaphore(信號量)
4.

示例代碼:

#!/usr/local/env python3

import threading,time

def addNum():
    global num #聲明修改全局變量
    print("--get num:",num)
    time.sleep(1)
    lock.acquire()
    num -=1
    lock.release()

lock = threading.Lock()
num = 100
threading_list = []
for i in range(2040):
    t = threading.Thread(target=addNum)
    t.start()
    threading_list.append(t)
for t in threading_list: #等待全部線程執行完畢
    t.join()

print("num:",num)

event

多進程

進程間通信

隊列
管道
manager

進程同步

進程池

相關文章
相關標籤/搜索