天天看點

46. Python Socket程式設計

複習:消息隊列

為了防止消息丢失,或者是調用方,不需一直等待響應方的結果。

# 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)--&gt;【監聽的方法内需要帶一個數字,這個數字表示同時有多少個用戶端可以來通路服務端】

(4)然後接收請求(accept)--&gt; 【用戶端每建立一個連接配接,調用 "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)&gt;</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