pythonsocket非阻塞
⑴ mac os x 下的python 為什麼沒有epoll
介紹
從2.6版本開始, python 提供了使用linux epoll 的功能. 這篇文章通過3個例子來大致介紹如何使用它. 歡迎提問和反饋.
阻塞式socket通訊
第一個例子是一個簡單的python3.0版本的伺服器代碼, 監聽8080埠的http請求, 列印結果到命令行, 回應http response給客戶端.
行 9: 建立伺服器的socket
行 10: 允許11行的bind()操作, 即使其他程序也在監聽同樣的埠. 不然的話, 這個程序只能在其他程序停止使用這個埠之後的1到2分鍾後才能執行.
行 11: 綁定socket到這台機器上所有IPv4地址上的8080埠.
行 12: 告訴伺服器開始響應從客戶端過來的連接請求.
行 14: 程序會一直停在這里, 直到建立了一個連接. 這個時候, 伺服器socket會建立一個新的socket, 用來和客戶端通訊. 這個新的socket是accept()的返回值, address對象標示了客戶端的IP地址和埠.
行 15-17: 接收數據, 直到一個完整的http請求被接收完畢. 這是一個簡單的http伺服器實現.
行 18: 為了方便驗證, 列印客戶端過來的請求到命令行.
行 19: 發送回應.
行 20-22: 關閉連接, 以及伺服器的監聽socket.
python官方 HOWTO 裡面有具體如何使用socket編程的描述.
1 import socket
2
3 EOL1 = b'\n\n'
4 EOL2 = b'\n\r\n'
5 response = b'HTTP/1.0 200 OK\r\nDate: Mon, 1 Jan 1996 01:01:01 GMT\r\n'
6 response += b'Content-Type: text/plain\r\nContent-Length: 13\r\n\r\n'
7 response += b'Hello, world!'
8
9 serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
10 serversocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
11 serversocket.bind(('0.0.0.0', 8080))
12 serversocket.listen(1)
13
14 connectiontoclient, address = serversocket.accept()
15 request = b''
16 while EOL1 not in request and EOL2 not in request:
17 request += connectiontoclient.recv(1024)
18 print(request.decode())
19 connectiontoclient.send(response)
20 connectiontoclient.close()
21
22 serversocket.close()
第2個例子, 我們在15行加上了一個循環, 用來循環處理客戶端請求, 直到我們中斷這個過程(在命令行下面輸入鍵盤中斷, 比如Ctrl-C). 這個例子更明顯地表示出來了, 伺服器socket並沒有用來做數據處理, 而是接受伺服器過來的連接, 然後建立一個新的socket, 用來和客戶端通訊.
最後的23-24行確保伺服器的監聽socket最後總是close掉, 即使出現了異常.
1 import socket
2
3 EOL1 = b'\n\n'
4 EOL2 = b'\n\r\n'
5 response = b'HTTP/1.0 200 OK\r\nDate: Mon, 1 Jan 1996 01:01:01 GMT\r\n'
6 response += b'Content-Type: text/plain\r\nContent-Length: 13\r\n\r\n'
7 response += b'Hello, world!'
8
9 serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
10 serversocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
11 serversocket.bind(('0.0.0.0', 8080))
12 serversocket.listen(1)
13
14 try:
15 while True:
16 connectiontoclient, address = serversocket.accept()
17 request = b''
18 while EOL1 not in request and EOL2 not in request:
19 request += connectiontoclient.recv(1024)
20 print('-'*40 + '\n' + request.decode()[:-2])
21 connectiontoclient.send(response)
22 connectiontoclient.close()
23 finally:
24 serversocket.close()
非同步socket和linux epoll的優勢
第2個例子裡面的socket採用的是阻塞方式, 因為python解釋器在出現事件之前都處在停止狀態. 16行的accept()一直阻塞, 直到新的連接進來. 19行的recv()也是一直阻塞, 直到從客戶端收到數據(或者直到沒有數據可以接收). 21行的send()也一直阻塞, 直到所有需要發送給客戶端的數據都交給了linux內核的發送隊列.
當一個程序採用阻塞socket的時候, 它經常採用一個線程(甚至一個進程)一個socket通訊的模式. 主線程保留伺服器監聽socket, 接受進來的連接, 一次接受一個連接, 然後把生成的socket交給一個分離的線程去做交互. 因為一個線程只和一個客戶端通訊, 在任何位置的阻塞都不會造成問題. 阻塞本身不會影響其他線程的工作.
多線程阻塞socket模式代碼清晰, 但是有幾個缺陷, 可能很難確保線程間資源共享工作正常, 可能在只有一個CPU的機器上效率低下.
C10K(單機1萬連接問題!) 探討了其他處理並行socket通訊的模式. 一種是採用非同步socket. socket不會阻塞, 直到特定事件發生. 程序在非同步socket上面進行一個特定操作, 並且立即得到一個結果, 不管執行成功或者失敗. 然後讓程序決定下一步怎麼做. 因為非同步socket是非阻塞的, 我們可以不採用多線程. 所有的事情都可以在一個線程裡面完成. 雖然這種模式有它需要面對的問題, 它對於特定程序來說還是不錯的選擇. 也可以和多線程合起來使用: 單線程的非同步socket可以當作伺服器上面處理網路的一個模塊, 而線程可以用來訪問阻塞式的資源, 比如資料庫.
Linux 2.6有一些方式來管理非同步socket, python API能夠用的有3種: select, poll和epoll. epoll和poll比select性能更好, 因為python程序不需要為了特定的事件去查詢單獨的socket, 而是依賴操作系統來告訴你什麼socket產生了什麼事件. epoll比poll性能更好, 因為它不需要每次python程序查詢的時候, 操作系統都去檢查所有的socket, 在事件產生的時候, linux跟蹤他們, 然後在python程序調用的時候, 返回具體的列表. 所以epoll在大量(上千)並行連接下, 是一種更有效率, 伸縮性更強的機制. 圖示.
採用epoll的非同步socket編程示例
採用epoll的程序一般這樣操作:
建立一個epoll對象
告訴epoll對象, 對於一些socket監控一些事件.
問epoll, 從上次查詢以來什麼socket產生了什麼事件.
針對這些socket做特定操作.
告訴epoll, 修改監控socket和/或監控事件.
重復第3步到第5步, 直到結束.
銷毀epoll對象.
採用非同步socket的時候第3步重復了第2步的事情. 這里的程序更復雜, 因為一個線程需要和多個客戶端交互.
行 1: select模塊帶有epoll功能
行 13: 因為socket默認是阻塞的, 我們需要設置成非阻塞(非同步)模式.
行 15: 建立一個epoll對象.
行 16: 注冊伺服器socket, 監聽讀取事件. 伺服器socket接收一個連接的時候, 產生一個讀取事件.
行 19: connections表映射文件描述符(file descriptors, 整型)到對應的網路連接對象上面.
行 21: epoll對象查詢一下是否有感興趣的事件發生, 參數1說明我們最多等待1秒的時間. 如果有對應事件發生, 立刻會返回一個事件列表.
行 22: 返回的events是一個(fileno, event code)tuple列表. fileno是文件描述符, 是一個整型數.
行 23: 如果是伺服器socket的事件, 那麼需要針對新的連接建立一個socket.
行 25: 設置socket為非阻塞模式.
行 26: 注冊socket的read(EPOLLIN)事件.
行 31: 如果讀取事件發生, 從客戶端讀取新數據.
行 33: 一旦完整的http請求接收到, 取消注冊讀取事件, 注冊寫入事件(EPOLLOUT), 寫入事件在能夠發送數據回客戶端的時候產生.
行 34: 列印完整的http請求, 展示即使通訊是交錯的, 數據本身是作為一個完整的信息組合和處理的.
行 35: 如果寫入事件發生在一個客戶端socket上面, 我們就可以發送新數據到客戶端了.
行s 36-38: 一次發送一部分返回數據, 直到所有數據都交給操作系統的發送隊列.
行 39: 一旦所有的返回數據都發送完, 取消監聽讀取和寫入事件.
行 40: 如果連接被明確關閉掉, 這一步是可選的. 這個例子採用這個方法是為了讓客戶端首先斷開, 告訴客戶端沒有數據需要發送和接收了, 然後讓客戶端斷開連接.
行 41: HUP(hang-up)事件表示客戶端斷開了連接(比如 closed), 所以伺服器這端也會斷開. 不需要注冊HUP事件, 因為它們都會標示到注冊在epoll的socket.
行 42: 取消注冊.
行 43: 斷開連接.
行s 18-45: 在這里的異常捕捉的作用是, 我們的例子總是採用鍵盤中斷來停止程序執行.
行s 46-48: 雖然開啟的socket不需要手動關閉, 程序退出的時候會自動關閉, 明確寫出來這樣的代碼, 是更好的編碼風格.
⑵ 初學者怎麼學習Python
初學者、零基礎學Python的話,建議參加培訓班,入門快、效率高、周期短、實戰項目豐富,還可以提升就業競爭力。
以下是老男孩教育Python全棧課程內容:階段一:Python開發基礎
Python開發基礎課程內容包括:計算機硬體、操作系統原理、安裝linux操作系統、linux操作系統維護常用命令、Python語言介紹、環境安裝、基本語法、基本數據類型、二進制運算、流程式控制制、字元編碼、文件處理、數據類型、用戶認證、三級菜單程序、購物車程序開發、函數、內置方法、遞歸、迭代器、裝飾器、內置方法、員工信息表開發、模塊的跨目錄導入、常用標准庫學習,b加密\re正則\logging日誌模塊等,軟體開發規范學習,計算器程序、ATM程序開發等。
階段二:Python高級級編編程&資料庫開發
Python高級級編編程&資料庫開發課程內容包括:面向對象介紹、特性、成員變數、方法、封裝、繼承、多態、類的生成原理、MetaClass、__new__的作用、抽象類、靜態方法、類方法、屬性方法、如何在程序中使用面向對象思想寫程序、選課程序開發、TCP/IP協議介紹、Socket網路套接字模塊學習、簡單遠程命令執行客戶端開發、C\S架構FTP伺服器開發、線程、進程、隊列、IO多路模型、資料庫類型、特性介紹,表欄位類型、表結構構建語句、常用增刪改查語句、索引、存儲過程、視圖、觸發器、事務、分組、聚合、分頁、連接池、基於資料庫的學員管理系統開發等。
階段三:前端開發
前端開發課程內容包括:HTML\CSS\JS學習、DOM操作、JSONP、原生Ajax非同步載入、購物商城開發、Jquery、動畫效果、事件、定時期、輪播圖、跑馬燈、HTML5\CSS3語法學習、bootstrap、抽屜新熱榜開發、流行前端框架介紹、Vue架構剖析、mvvm開發思想、Vue數據綁定與計算屬性、條件渲染類與樣式綁定、表單控制項綁定、事件綁定webpack使用、vue-router使用、vuex單向數據流與應用結構、vuex actions與mutations熱重載、vue單頁面項目實戰開發等。
階段四:WEB框架開發
WEB框架開發課程內容包括:Web框架原理剖析、Web請求生命周期、自行開發簡單的Web框架、MTV\MVC框架介紹、Django框架使用、路由系統、模板引擎、FBV\CBV視圖、Models ORM、FORM、表單驗證、Django session & cookie、CSRF驗證、XSS、中間件、分頁、自定義tags、Django Admin、cache系統、信號、message、自定義用戶認證、Memcached、redis緩存學習、RabbitMQ隊列學習、Celery分布式任務隊列學習、Flask框架、Tornado框架、Restful API、BBS+Blog實戰項目開發等。
階段五:爬蟲開發
爬蟲開發課程內容包括:Requests模塊、BeautifulSoup,Selenium模塊、PhantomJS模塊學習、基於requests實現登陸:抽屜、github、知乎、博客園、爬取拉鉤職位信息、開發Web版微信、高性能IO性能相關模塊:asyncio、aiohttp、grequests、Twisted、自定義開發一個非同步非阻塞模塊、驗證碼圖像識別、Scrapy框架以及源碼剖析、框架組件介紹(engine、spider、downloader、scheler、pipeline)、分布式爬蟲實戰等。
階段六:全棧項目實戰
全棧項目實戰課程內容包括:互聯網企業專業開發流程講解、git、github協作開發工具講解、任務管理系統講解、介面單元測試、敏捷開發與持續集成介紹、django + uwsgi + nginx生產環境部署學習、介面文檔編寫示例、互聯網企業大型項目架構圖深度講解、CRM客戶關系管理系統開發等。
階段七:數據分析
數據分析課程內容包括:金融、股票知識入門股票基本概念、常見投資工具介紹、市基本交易規則、A股構成等,K線、平均線、KDJ、MACD等各項技術指標分析,股市操作模擬盤演示量化策略的開發流程,金融量化與Python,numpy、pandas、matplotlib模塊常用功能學習在線量化投資平台:優礦、聚寬、米筐等介紹和使用、常見量化策略學習,如雙均線策略、因子選股策略、因子選股策略、小市值策略、海龜交易法則、均值回歸、策略、動量策略、反轉策略、羊駝交易法則、PEG策略等、開發一個簡單的量化策略平台,實現選股、擇時、倉位管理、止盈止損、回測結果展示等功能。
階段八:人工智慧
人工智慧課程內容包括:機器學習要素、常見流派、自然語言識別、分析原理詞向量模型word2vec、剖析分類、聚類、決策樹、隨機森林、回歸以及神經網路、測試集以及評價標准Python機器學習常用庫scikit-learn、數據預處理、Tensorflow學習、基於Tensorflow的CNN與RNN模型、Caffe兩種常用數據源製作、OpenCV庫詳解、人臉識別技術、車牌自動提取和遮蔽、無人機開發、Keras深度學習、貝葉斯模型、無人駕駛模擬器使用和開發、特斯拉遠程式控制制API和自動化駕駛開發等。
階段九:自動化運維&開發
自動化運維&開發課程內容包括:設計符合企業實際需求的CMDB資產管理系統,如安全API介面開發與使用,開發支持windows和linux平台的客戶端,對其它系統開放靈活的api設計與開發IT資產的上線、下線、變更流程等業務流程。IT審計+主機管理系統開發,真實企業系統的用戶行為、管理許可權、批量文件操作、用戶登錄報表等。分布式主機監控系統開發,監控多個服務,多種設備,報警機制,基於http+restful架構開發,實現水平擴展,可輕松實現分布式監控等功能。
階段十:高並發語言GO開發高並發語言GO開發課程內容包括:Golang的發展介紹、開發環境搭建、golang和其他語言對比、字元串詳解、條件判斷、循環、使用數組和map數據類型、go程序編譯和Makefile、gofmt工具、godoc文檔生成工具詳解、斐波那契數列、數據和切片、make&new、字元串、go程序調試、slice&map、map排序、常用標准庫使用、文件增刪改查操作、函數和面向對象詳解、並發、並行與goroute、channel詳解goroute同步、channel、超時與定時器reover捕獲異常、Go高並發模型、Lazy生成器、並發數控制、高並發web伺服器的開發等。
⑶ python socket 阻塞模式怎麼確保數據recv
可以通過setsockopt,或者更簡單的setblocking, settimeout設置。阻塞式的socket的recv服從這樣的規則:
當緩沖區內有數據時,立即返回所有的數據;當緩沖區內無數據時,阻塞直到緩沖區中有數據。非阻塞式的socket的recv服從的規則則是:
當緩沖區內有數據時,立即返回所有的數據;當緩沖區內無數據時,產生EAGAIN的錯誤並返回(在Python中會拋出一個異常)。兩種情況都不會返回空字元串,返回空數據的結果是對方關閉了連接之後才會出現的。
⑷ python:如何以非阻塞的方式讀
代碼是這樣的:
subp = subprocess.Popen(["d:/T1.exe"], shell=True, stdout=subprocess.PIPE, bufsize=0)
subp.stdout.read()
但是發現read和readline函數是阻塞方式調用的,一定要subprocess運行結束才能返回數據。
⑸ 怎樣判斷websocket是否斷開 有沒有對應的api (我用的是Django 和Python語言)
# coding:utf-8
import os
import struct
import base64
import hashlib
import socket
import threading
import paramiko
def get_ssh(ip, user, pwd):
try:
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(ip, 22, user, pwd, timeout=15)
return ssh
except Exception, e:
print e
return "False"
def recv_data(conn): # 伺服器解析瀏覽器發送的信息
try:
all_data = conn.recv(1024)
if not len(all_data):
return False
except:
pass
else:
code_len = ord(all_data[1]) & 127
if code_len == 126:
masks = all_data[4:8]
data = all_data[8:]
elif code_len == 127:
masks = all_data[10:14]
data = all_data[14:]
else:
masks = all_data[2:6]
data = all_data[6:]
raw_str = ""
i = 0
for d in data:
raw_str += chr(ord(d) ^ ord(masks[i % 4]))
i += 1
return raw_str
def send_data(conn, data): # 伺服器處理發送給瀏覽器的信息
if data:
data = str(data)
else:
return False
token = "\x81"
length = len(data)
if length < 126:
token += struct.pack("B", length) # struct為Python中處理二進制數的模塊,二進制流為C,或網路流的形式。
elif length <= 0xFFFF:
token += struct.pack("!BH", 126, length)
else:
token += struct.pack("!BQ", 127, length)
data = '%s%s' % (token, data)
conn.send(data)
return True
def handshake(conn, address, thread_name):
headers = {}
shake = conn.recv(1024)
if not len(shake):
return False
print ('%s : Socket start handshaken with %s:%s' % (thread_name, address[0], address[1]))
header, data = shake.split('\r\n\r\n', 1)
for line in header.split('\r\n')[1:]:
key, value = line.split(': ', 1)
headers[key] = value
if 'Sec-WebSocket-Key' not in headers:
print ('%s : This socket is not websocket, client close.' % thread_name)
conn.close()
return False
MAGIC_STRING = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'
HANDSHAKE_STRING = "HTTP/1.1 101 Switching Protocols\r\n" \
"Upgrade:websocket\r\n" \
"Connection: Upgrade\r\n" \
"Sec-WebSocket-Accept: {1}\r\n" \
"WebSocket-Origin: {2}\r\n" \
"WebSocket-Location: ws://{3}/\r\n\r\n"
sec_key = headers['Sec-WebSocket-Key']
res_key = base64.b64encode(hashlib.sha1(sec_key + MAGIC_STRING).digest())
str_handshake = HANDSHAKE_STRING.replace('{1}', res_key).replace('{2}', headers['Origin']).replace('{3}', headers['Host'])
conn.send(str_handshake)
print ('%s : Socket handshaken with %s:%s success' % (thread_name, address[0], address[1]))
print 'Start transmitting data...'
print '- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -'
return True
def dojob(conn, address, thread_name):
handshake(conn, address, thread_name) # 握手
conn.setblocking(0) # 設置socket為非阻塞
ssh = get_ssh('192.168.1.1', 'root', '123456') # 連接遠程伺服器
ssh_t = ssh.get_transport()
chan = ssh_t.open_session()
chan.setblocking(0) # 設置非阻塞
chan.exec_command('tail -f /var/log/messages')
while True:
clientdata = recv_data(conn)
if clientdata is not None and 'quit' in clientdata: # 但瀏覽器點擊stop按鈕或close按鈕時,斷開連接
print ('%s : Socket close with %s:%s' % (thread_name, address[0], address[1]))
send_data(conn, 'close connect')
conn.close()
break
while True:
while chan.recv_ready():
clientdata1 = recv_data(conn)
if clientdata1 is not None and 'quit' in clientdata1:
print ('%s : Socket close with %s:%s' % (thread_name, address[0], address[1]))
send_data(conn, 'close connect')
conn.close()
break
log_msg = chan.recv(10000).strip() # 接收日誌信息
print log_msg
send_data(conn, log_msg)
if chan.exit_status_ready():
break
clientdata2 = recv_data(conn)
if clientdata2 is not None and 'quit' in clientdata2:
print ('%s : Socket close with %s:%s' % (thread_name, address[0], address[1]))
send_data(conn, 'close connect')
conn.close()
break
break
def ws_service():
index = 1
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(("127.0.0.1", 12345))
sock.listen(100)
print ('\r\n\r\nWebsocket server start, wait for connect!')
print '- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -'
while True:
connection, address = sock.accept()
thread_name = 'thread_%s' % index
print ('%s : Connection from %s:%s' % (thread_name, address[0], address[1]))
t = threading.Thread(target=dojob, args=(connection, address, thread_name))
t.start()
index += 1
ws_service()
⑹ python 的tornado主要用來做什麼
一個用Python寫的相對簡單的、可擴展、非阻塞的Web伺服器架構,以處理上萬的同時的連介面,讓實時的Web服務通暢起來。跟現在一些用Python寫的Web架構相似,比如Django,但更注重速度,能夠處理海量的同時發生的流量
⑺ python無法立即完成一個非阻止性套接字操作
你使用了非阻塞模式,而10035表示數據還沒有返回給你。
你可以在接收前先select一下,如果有數據就接受,沒有就跳過。
你可參考python官方文檔
http://docs.python.org/howto/sockets.html
裡面有Non-blocking Sockets的一章可以看看。
import select
...
while 1:
infds,outfds,errfds = select.select([s,],[],[],5)
if len(infds) >0:
....
else:
print "no data coming"
⑻ Python三大web框架分別是什麼 哪個更好
【導讀】目前,Python比較火的三大web框架有Django、Flask和Tornado,要論這三個Web框架哪個更好的話,建議一點,Django幫我們事先搭建了好多,上手會快一些,學習的話可以先從Django學起,然後再學習Flask和Tornado,下面我們就來具體了解一下Python三大web框架的詳情。
1、Django
Django是一個開放源代碼的Web應用框架,由Python寫成。採用了MTV的框架模式,即模型M,模板T和視圖V。它最初是被開發來用於管理勞倫斯出版集團旗下的一些以新聞內容為主的網站的,即是CMS(內容管理系統)軟體。
2、Flask
Flask是一個使用Python編寫的輕量級Web應用框架。其 WSGI工具箱採用Werkzeug ,模板引擎則使用 Jinja2
。Flask使用BSD授權。
Flask也被稱為 「microframework」 ,因為它使用簡單的核心,用 extension
增加其他功能。Flask沒有默認使用的資料庫、窗體驗證工具。
Flask 很輕,花很少的成本就能夠開發一個簡單的網站。非常適合初學者學習。Flask 框架學會以後,可以考慮學習插件的使用。例如使用 WTForm +
Flask-WTForm 來驗證表單數據,用 SQLAlchemy + Flask-SQLAlchemy 來對你的資料庫進行控制。
3、Tornado
Tornado是一種 Web 伺服器軟體的開源版本。Tornado 和現在的主流 Web 伺服器框架(包括大多數 Python
的框架)有著明顯的區別:它是非阻塞式伺服器,而且速度相當快。
得利於其 非阻塞的方式和對epoll的運用,Tornado 每秒可以處理數以千計的連接,因此 Tornado 是實時 Web 服務的一個
理想框架。
關於Python三大web框架的簡單介紹,就給大家分享到這里了,當然學習是永無止境的,學習一項技能更是受益終身,所以,只要肯努力學,什麼時候開始都不晚,希望大家抓緊時間進行學習吧。
⑼ python grpc起的服務怎麼測試
1、首先是Keepalived機制。
1)客戶端的Keepalives設置可以work了。
2)設置Keepalives後,在整個網路連接建立完成之後,會不斷的發送ping消息給服務端。
3)服務端根據Keppavlied的ping消息來自動識別哪些連接是斷了的。
2、服務端可以設置連接的時效了,當設置連接的最大時間到了,該連接將會中斷掉。
3、增加了trace的一些傳遞。
4、對LoadBalancers進行了一些變化。
⑽ python的socket的非阻塞實現
setblocking(0)之後就是非阻塞的。
select模塊只是說能夠同時處理多個socket,至於這些socket是阻塞還是非阻塞,都沒有關系。當然從性能上考慮,現在的趨勢是select+非阻塞。