iocp的python封裝(續)

來源:互聯網
上載者:User

原文地址:http://darkbull.net/python/bca/pyiocp/

題記

        以前用C++封裝過iocp的python模組,寫過兩篇文章。儘管當前公司的項目最終將部署在linux上,但現在的開發是在window上。用select模型寫了個簡單的net io wrapper,但好像很不穩定,老是出現一些莫名其妙的問題。這兩天,決定把這以前寫的pyiocp代碼翻出來,整整再用。但當我開啟項目的時候,我暈了(大腦缺氧,極需美女給我做人工呼吸!)好久沒用C++了,本來我的C++基礎就不咋的,再加上用了這麼長時間的python,看以前的C++代碼盡然會頭暈,雖然有詳細的注釋,但似乎還是回憶不起來。!@#$$#!@ 以前封裝的pyiocp,只在公司項目的測試中使用過一段時間,問題也比較多,沒用多久就廢了。這兩天時間,我用C語言又重新寫了一個封裝。使用的是gcc。本來想讓代碼在vs下也能編譯通過,但後來發現vc2008對c99的支援極差,所有的變數都必須放在塊語句開始處、執行代碼的前面。我無語,不想對代碼做大調整,一來怕麻煩,二來我覺得把變數放在塊語句的開始處會降低代碼的可讀性。於是不再提供在vc的支援。

實現模式

        關於IOCP的資料在網上有一卡車一卡車的,這裡我不再做重複的勞動,只分享一下pyiocp的實現原理。第一次封裝的時候,有一張圖來描述使用pyiocp收發資料的過程:

        由可以看出,伺服器接收、發送的資料都通過pyiocp。在實際使用過程中,我發現這種實現模式有一個問題:遊戲伺服器發送的資料包,一般都比較小(最大的也不過幾K),而每個socket的低層協議棧緩衝區大小預設是32K,除非出現下面兩種情況會使緩衝區填滿而收到相應的socket錯誤,一是在極短的時間內發送的資料量超過32K,二是用戶端的網路極差,放在緩衝區裡的資料半天也沒發出去。第一種情況在我們的遊戲伺服器中是不會出現的,而對於第二種情況,如果不及時的關閉這種串連,那麼發送給這個串連的資料將不斷的堆積在記憶體裡,使記憶體佔用越來越大。所以,我覺得沒有必要通過pyiocp發送資料,這樣增加了程式的複雜性的同時,也沒帶來多少好處。索性直接通過socket發送,如果發送的時候收到socket錯誤(在send時很少會發生錯誤,即使出錯,緩衝區滿是主要原因),就把該串連斷掉。我曾經讀我領導寫的代碼時,他就是這麼乾的。所以,新設計之後的pyiocp內部工作模式是這樣的:

        除了上面講的實現模式不一樣之後,新封裝的pyiocp使用了記憶體池。記憶體池是一年前寫的,實現參考了python源碼的記憶體池實現。

pyiocp模組的使用

        下面是pyiocp模組提供的方法:

  • init(): 初始化內部使用的資源。在調用其他函數之前,必須先調用該方法。如果調用成功,返回0,否則,返回一個錯誤碼,可以通過errinfo(errno)來查看錯誤碼的描述。一般在程式啟動的時候調用該方法。
  • cleanup(): 釋放內部使用的資源。
  • run(ip, port): 啟動pyiocp監聽。參數ip為字串,表示綁定的本地ip地址,參數port是一個整數,表示監聽的連接埠。函數調用成功,返回0,否則返回一個錯誤碼。
  • stop(): 停止監聽。調用該方法後,原先在事件隊列中未處理的事件將被清空。
  • send(fileno, data): 發送資料。參數fileno表示socket控制代碼,data為發送的資料。上面講到資料是直接發送給用戶端的,那麼與這裡講的豈不矛盾。其實,send內部實現只是簡單地調用winsocket的send()方法,而沒用使用WSASend投遞。所以並不矛盾。函數返回0表示資料發送成功,否則應該通過errinfo(errno)來查看錯誤資訊。
  • close(fileno):關閉串連。參數fileno表示將要關閉的socket控制代碼。函數返回0表示操作成功,否則應該通過errinfo(errno)來查看錯誤資訊。
  • event():擷取一個事件。如果隊列中沒有事件,返回None。事件是一個包含三個元素的元組,[0]表示事件的類型,0: NET_NEW,1: NET_LEAVE,2: DATA_NEW。[1]表示對應的socket控制代碼。[2]表示相應的資料,NET_NEW事件的資料是ip,port,NET_LEAVE事件的資料為None,DATA_NEW事件的資料為二進位字串。
  • count(): 返回當前串連的數量
  • errinfo(errno): 查看錯誤碼對應的資訊。
樣本
#!/usr/bin/env python# -*- coding: utf-8 -*-import pyiocpimport timeNET_NEW = 0NET_LEAVE = 1DATA_NEW = 2pyiocp.init()pyiocp.run('127.0.0.1', 1234)while True:    event = pyiocp.event()    if event is None:        time.sleep(0.1)        continue        type, fileno, data = event    if type == NET_NEW:        ip = data        print '---->', ip    elif type == NET_LEAVE:        print '<----'    else:        print 'recv data:', data        pyiocp.stop()pyiocp.cleanup()

源碼下載與編譯

       pyiocp_new:使用gcc編譯,在編譯的時候,修改makefile中的python版本

       pyiocp_old:使用c++編寫,裡面有vs與CodeBlocks的專案檔

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.