複習:消息隊列
為了防止消息丢失,或者是調用方,不需一直等待響應方的結果。
# threadtest.py
<code>import</code> <code>codecs</code>
<code>from</code> <code>queue </code><code>import</code> <code>Queue</code>
<code>from</code> <code>threading </code><code>import</code> <code>Thread</code>
<code>import</code> <code>time</code>
<code>class</code> <code>Produce(Thread):</code>
<code> </code><code>def</code> <code>__init__(</code><code>self</code><code>, queue):</code>
<code> </code><code>super</code><code>(Produce, </code><code>self</code><code>).__init__()</code>
<code> </code><code>self</code><code>.fileName </code><code>=</code> <code>"../firstlession/passwd"</code>
<code> </code><code>self</code><code>.fileList </code><code>=</code> <code>list</code><code>()</code>
<code> </code><code>self</code><code>.queue </code><code>=</code> <code>queue</code>
<code> </code><code>def</code> <code>run(</code><code>self</code><code>):</code>
<code> </code><code>with codecs.</code><code>open</code><code>(</code><code>self</code><code>.fileName) as f:</code>
<code> </code><code>self</code><code>.fileList </code><code>+</code><code>=</code> <code>f.readlines()</code>
<code> </code><code>for</code> <code>line </code><code>in</code> <code>self</code><code>.fileList:</code>
<code> </code><code>self</code><code>.queue.put(line)</code>
<code>class</code> <code>Consumer(Thread):</code>
<code> </code><code>super</code><code>(Consumer, </code><code>self</code><code>).__init__()</code>
<code> </code><code>self</code><code>.newPasswd </code><code>=</code> <code>"newpasswd.txt"</code>
<code> </code><code>self</code><code>.stat </code><code>=</code> <code>1</code>
<code> </code><code>while</code> <code>1</code><code>:</code>
<code> </code><code>if</code> <code>self</code><code>.queue.empty():</code>
<code> </code><code>time.sleep(</code><code>2</code><code>)</code>
<code> </code><code>self</code><code>.stat </code><code>+</code><code>=</code> <code>1</code>
<code> </code><code>if</code> <code>self</code><code>.stat </code><code>=</code><code>=</code> <code>5</code><code>:</code>
<code> </code><code>break</code>
<code> </code><code>else</code><code>:</code>
<code> </code><code>self</code><code>.stat </code><code>=</code> <code>1</code>
<code> </code><code>data </code><code>=</code> <code>self</code><code>.queue.get()</code>
<code> </code><code>self</code><code>.fileList.append(data)</code>
<code> </code><code>with codecs.</code><code>open</code><code>(</code><code>self</code><code>.newPasswd, </code><code>'w'</code><code>) as f:</code>
<code> </code><code>f.writelines(</code><code>self</code><code>.fileList)</code>
調用
# thread1.py
<code>from</code> <code>onlive.secondlesson.threadtest </code><code>import</code> <code>Produce, Consumer</code>
<code>def</code> <code>main():</code>
<code> </code><code>q </code><code>=</code> <code>Queue()</code>
<code> </code><code>produce </code><code>=</code> <code>Produce(q)</code>
<code> </code><code>consumer </code><code>=</code> <code>Consumer(q)</code>
<code> </code><code>produce.start()</code>
<code> </code><code>consumer.start()</code>
<code>if</code> <code>__name__ </code><code>=</code><code>=</code> <code>'__main__'</code><code>:</code>
<code> </code><code>main()</code>
socket 簡介
TCP的可靠性實作:
(1)校驗碼
(2)接收方回報
(3)資訊包附帶序号
UDP:
(1)快 不需要花費時間建立和關閉連接配接
(2)快 偶爾丢失一兩個消息包無所謂,但是TCP會嚴格檢查
(3)快 UDP的限制是一個資訊包不超過64KB的資料
TCP和UDP差別:
UDP不建立連接配接,隻保證資料的完整性,資料傳輸快,但是不保證資料是否真的被收到,也不保證資料是否隻接收一次,也不保證次序。
TCP則相反。
服務端是用來給一個或多個用戶端提供服務的,當用戶端發起請求,開始等待服務端的傳回結果,服務端接受完請求以後,根據自己的邏輯處理請求,并傳回給用戶端,用戶端接收到傳回結果以後,關閉和服務端的連接配接。
[備注]:隻要是發送資料的就是"寫",隻要是接收資料的就是"讀"。
最常用的用戶端和服務端有兩種模式:C/S模式(mysql) 和 B/S模式(百度、京東、淘寶網站等)
socket流程:
(1)服務端建立完一個socket以後
(2)需要綁定一個IP:PORT
(3)對其進行監聽(listen)-->【監聽的方法内需要帶一個數字,這個數字表示同時有多少個用戶端可以來通路服務端】
(4)然後接收請求(accept)--> 【用戶端每建立一個連接配接,調用 "connect函數" 後,服務端就需要生成一個新的socket連接配接和用戶端進行傳輸,傳輸完成後關閉用戶端連接配接、關閉服務端;服務端永遠要比用戶端多一個socket連接配接,如果說用戶端是n個socket連接配接,那麼服務端就要建立n+1個socket連接配接,因為剛開始啟動服務端的時候,服務端就要建立一個socket連接配接,每當從用戶端過來一個連接配接,服務端就要建立一個socket連接配接跟用戶端進行互動,是以服務端比用戶端多一個連接配接。】
socket常用函數講解:
建立套接字:
s = socket.socket(address family, socket type)
address family:
socket.AF_INET 預設ipv4
socket.AF_INET6 ipv6
socket.AF_UNIX 隻用于單一unix系統間進行通信
socket type:
socket.SOCK_STREAM 流式socket TCP
socket.SOCK_DGRAM 資料報式socket UDP
TCP 方式 socket:
(1)建立socket:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
(2)綁定位址:
address = ('0.0.0.0', 8009)
s.bind(address) 或者 s.bind((0.0.0.0, 8009)) 兩種方式相同;
【注意:address 必須是一個元組,容易錯誤,address = (host, port)】
【host:服務端ip,字元串類型,如果為0.0.0.0,代表本機的任意一個IP】
【port:服務端提供的端口,整形,0-1024為系統保留(不選這裡面的端口)】
(3)監聽消息:
s.listen(badklog)
backlog 代表可以同時接受多少個socket連接配接
(4)接受連接配接:
conn, addr = s.accept()
接受連接配接并傳回元組(conn,addr),其中conn是新的套接字對象,每個新的連接配接就建立一個新的對象。可以用來接受和發送資料,addr是用戶端的位址:包含host和port。
(5)發送資料:
s.send(string) 發送字元串到連接配接的套接字,可能未将指定内容全部發送;
s.sendall(string) 内部遞歸調用send,将所有内容發送出去,建議使用。
(6)接收資料:
data = s.recv(bufsize)
接收套接字資料,資料以字元串形式傳回,bufsize指定最多接收的資料量,可以使用1024, 2048
如果不知道接收的數量有多少,可以能幾個位元組,可能幾兆,一般通過循環接收。
UDP 方式 socket:
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.sendto(string)
data, address = s.recvfrom(bufsize)
用戶端:
用戶端首先也要建立socket套接字
用戶端連接配接服務端函數:
s.connect(address) #連接配接到address的套接字
result - connect_ex(address) #成功傳回0,失敗傳回錯誤碼
通用:
s.close() #關閉套接字
s.getsocketname() #擷取套接字的名字
s.settimeout(timeout) #設定套接字逾時時間,timeout為float類型,機關秒
s.gettimeout() #獲得套接字逾時時間
s.setblocking(flag) #flage為bool值
setblocking(True) is equivalent to settimeout(None); #不設定逾時時間,一直阻塞在那裡
setblocking(False) is equivalent to settimeout(0.0); #設定逾時時間為0,如果設定False,accept和recv一旦無資料,則報錯。
s.fileno() # 傳回套接字的檔案描述符(一個小整數)。這對于select.select()是有用的。
socket例子:
寫socket工具:
# util.py
<code>import</code> <code>socket</code>
<code>class</code> <code>InitSocketTest(</code><code>object</code><code>):</code>
<code> </code><code>def</code> <code>__init__(</code><code>self</code><code>, host, port, </code><code>type</code><code>):</code>
<code> </code><code>self</code><code>.host </code><code>=</code> <code>host</code>
<code> </code><code>self</code><code>.port </code><code>=</code> <code>port</code>
<code> </code><code>self</code><code>.address </code><code>=</code> <code>(host, port)</code>
<code> </code><code>self</code><code>.</code><code>type</code> <code>=</code> <code>type</code>
<code> </code><code>self</code><code>.s </code><code>=</code> <code>None</code>
<code> </code><code>self</code><code>.creatsocket()</code>
<code> </code><code>def</code> <code>creatsocket(</code><code>self</code><code>):</code>
<code> </code><code>if</code> <code>self</code><code>.</code><code>type</code><code>.upper() </code><code>=</code><code>=</code> <code>"TCP"</code><code>:</code>
<code> </code><code>self</code><code>.s </code><code>=</code> <code>socket.socket(socket.AF_INET, socket.SOCK_STREAM)</code>
<code> </code><code>elif</code> <code>self</code><code>.</code><code>type</code><code>.upper </code><code>=</code><code>=</code> <code>"UDP"</code><code>:</code>
<code> </code><code>self</code><code>.s </code><code>=</code> <code>socket.socket(socket.AF_INET, socket.SOCK_DGRAM)</code>
<code> </code><code>else</code><code>:</code>
<code> </code><code>print</code><code>(</code><code>"you must input the InitSocket(type) is 'UDP|TCP' "</code><code>)</code>
<code>class</code> <code>SocketServerTest(InitSocketTest):</code>
<code> </code><code>def</code> <code>__init__(</code><code>self</code><code>, host, port, </code><code>type</code><code>, backlog):</code>
<code> </code><code>self</code><code>.backlog </code><code>=</code> <code>backlog</code>
<code> </code><code>super</code><code>(SocketServerTest, </code><code>self</code><code>).__init__(host, port, </code><code>type</code><code>)</code>
<code> </code><code>self</code><code>.clientAddress </code><code>=</code> <code>None</code>
<code> </code><code>self</code><code>.s.bind(</code><code>self</code><code>.address)</code>
<code> </code><code>self</code><code>.s.listen(</code><code>self</code><code>.backlog)</code>
<code> </code><code>print</code><code>(</code><code>"server starting…………"</code><code>)</code>
<code> </code><code>conn, </code><code>self</code><code>.clientAddress </code><code>=</code> <code>self</code><code>.s.accept()</code>
<code> </code><code>print</code><code>(</code><code>"accept connect from {0}"</code><code>.</code><code>format</code><code>(</code><code>self</code><code>.clientAddress))</code>
<code> </code><code>for</code> <code>i </code><code>in</code> <code>range</code><code>(</code><code>1</code><code>, </code><code>10</code><code>):</code>
<code> </code><code>conn.sendall(</code><code>"i = {0}"</code><code>.</code><code>format</code><code>(</code><code>str</code><code>(i)).encode(</code><code>"utf-8"</code><code>))</code>
<code> </code><code>self</code><code>.s.close()</code>
<code>class</code> <code>ClientSocketTest(InitSocketTest):</code>
<code> </code><code>self</code><code>.s.connect(</code><code>self</code><code>.address)</code>
<code> </code><code>stat </code><code>=</code> <code>1</code>
<code> </code><code>data </code><code>=</code> <code>self</code><code>.s.recv(</code><code>2048</code><code>)</code>
<code> </code><code>if</code> <code>len</code><code>(data)></code><code>0</code><code>:</code>
<code> </code><code>stat </code><code>=</code> <code>1</code>
<code> </code><code>print</code><code>(data.decode(</code><code>"utf-8"</code><code>))</code>
<code> </code><code>stat </code><code>+</code><code>=</code> <code>1</code>
<code> </code><code>time.sleep(</code><code>1</code><code>)</code>
<code> </code><code>if</code> <code>stat </code><code>=</code><code>=</code> <code>5</code><code>:</code>
# testserver.py
<code>from</code> <code>onlive.sockettest.util </code><code>import</code> <code>SocketServerTest </code>
<code>if</code> <code>__name__ </code><code>=</code><code>=</code> <code>'__main__'</code><code>: </code>
<code> </code><code>socketServer </code><code>=</code> <code>SocketServerTest(host</code><code>=</code><code>"0.0.0.0"</code><code>, port</code><code>=</code><code>9999</code><code>, </code><code>type</code><code>=</code><code>"tcp"</code><code>, backlog</code><code>=</code><code>5</code><code>) </code>
<code> </code><code>socketServer.run()</code>
# testclient.py
<code>from</code> <code>onlive.sockettest.util </code><code>import</code> <code>ClientSocketTest </code>
<code> </code><code>socketClient </code><code>=</code> <code>ClientSocketTest(host</code><code>=</code><code>"127.0.0.1"</code><code>, port</code><code>=</code><code>9999</code><code>, </code><code>type</code><code>=</code><code>"tcp"</code><code>) </code>
<code> </code><code>socketClient.run()</code>
<code></code>
本文轉自 聽丶飛鳥說 51CTO部落格,原文連結:http://blog.51cto.com/286577399/2056083