天天看點

Python實作web聊天室

使用Python子產品中的select子產品實作web聊天室功能

select子產品

Python中的select子產品專注于I/O多路複用,提供了select  poll  epoll三個方法(其中後兩個在Linux中可用,windows僅支援select),另外也提供了kqueue方法(freeBSD系統)

參數: 可接受四個參數(前三個必須)

    rlist: wait until ready for reading

    wlist: wait until ready for writing

    xlist: wait for an “exceptional condition”

    timeout: 逾時時間

select方法:

    每次調用slect都要将所有的fd拷貝到核心空間(每次都要拷貝),導緻效率下降

    監聽的的實作是通過周遊所有的fd,(周遊消耗的時間消耗多)判斷是否有資料通路

    最大連接配接數(input中放的檔案描述符數量1024)

pull方法:

    最大連接配接數沒有限制了,除此之外和select一樣。使用較少

epull方法:

    内部通過3個函數實作(select是其中一個)

    第一個函數:

      建立epoll句柄,把所有的fd拷貝到核心空間,隻需要拷貝一次

    第二個函數: 回調函數

    某一個函數或者動作成功完成後,會自動觸發一個函數為所有的fd綁定一個回調函數,一旦有資料通路,觸發改回調函數,回調函數把fd放到連結清單中。(隻要有活動,把fd放到連結清單中,動态監聽)這樣就提高了效率。例子:交試卷

    第三個函數,判斷連結清單是否為空

server端代碼

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

<code>#/usr/bin/env python</code>

<code>#-*- coding:utf-8 -*-</code>

<code>import</code> <code>socket</code>

<code>import</code> <code>select</code>

<code># 封裝</code>

<code>class</code> <code>SelectServer(</code><code>object</code><code>):</code>

<code>    </code><code># 定義主函數</code>

<code>    </code><code>def</code> <code>__init__(</code><code>self</code><code>, host, port, backlog):</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>.backlog </code><code>=</code> <code>backlog</code>

<code>        </code><code>self</code><code>.server </code><code>=</code> <code>None</code>

<code>        </code><code>self</code><code>.socketList </code><code>=</code> <code>list</code><code>()</code>

<code>    </code><code>def</code> <code>_initSocket(</code><code>self</code><code>):</code>

<code>        </code><code>self</code><code>.server </code><code>=</code> <code>socket.socket(socket.AF_INET, socket.SOCK_STREAM)</code>

<code>        </code><code>self</code><code>.server.bind(</code><code>self</code><code>.address)</code>

<code>        </code><code>self</code><code>.server.listen(</code><code>self</code><code>.backlog)</code>

<code>        </code><code>self</code><code>.socketList.append(</code><code>self</code><code>.server)</code>

<code>        </code><code>print</code><code>(</code><code>"chat room has start!"</code><code>)</code>

<code>        </code><code>while</code> <code>1</code><code>:</code>

<code>            </code><code>rlist, wlist, elist </code><code>=</code> <code>select.select(</code><code>self</code><code>.socketList, [], [])</code>

<code>            </code><code>for</code> <code>r </code><code>in</code> <code>rlist:</code>

<code>                </code><code>if</code> <code>r </code><code>=</code><code>=</code> <code>self</code><code>.server:</code>

<code>                    </code><code>serverConn, clienAddr </code><code>=</code> <code>self</code><code>.server.accept()</code>

<code>                    </code><code>self</code><code>.socketList.append(serverConn)</code>

<code>                    </code><code>print</code><code>(</code><code>"{0}進入了房間"</code><code>.</code><code>format</code><code>(clienAddr))</code>

<code>                    </code><code>self</code><code>.broadcast(r, </code><code>"{0}進入了房間"</code><code>.</code><code>format</code><code>(clienAddr))</code>

<code>                </code><code>else</code><code>:</code>

<code>                    </code><code>try</code><code>:</code>

<code>                        </code><code>data </code><code>=</code> <code>r.recv(</code><code>2048</code><code>)</code>

<code>                        </code><code>if</code> <code>data:</code>

<code>                            </code><code>print</code><code>(</code><code>"{0}: {1}"</code><code>.</code><code>format</code><code>(clienAddr, data))</code>

<code>                            </code><code>self</code><code>.broadcast(r, </code><code>"{0}: {1}"</code><code>.</code><code>format</code><code>(clienAddr, data))</code>

<code>                    </code><code>except</code> <code>Exception as e:</code>

<code>                        </code><code>self</code><code>.broadcast(r, </code><code>"{0}下線"</code><code>.</code><code>format</code><code>(clienAddr))</code>

<code>                        </code><code>print</code><code>(</code><code>"{0}下線"</code><code>.</code><code>format</code><code>(clienAddr))</code>

<code>                        </code><code>r.close()</code>

<code>                        </code><code>self</code><code>.socketList.remove(r)</code>

<code>        </code><code>self</code><code>.server.close()</code>

<code>    </code><code># 定義廣播函數</code>

<code>    </code><code>def</code> <code>broadcast(</code><code>self</code><code>, r, data):</code>

<code>        </code><code>for</code> <code>i </code><code>in</code> <code>self</code><code>.socketList:</code>

<code>            </code><code>if</code> <code>i !</code><code>=</code> <code>r </code><code>and</code> <code>i !</code><code>=</code> <code>self</code><code>.server:</code>

<code>                </code><code>try</code><code>:</code>

<code>                    </code><code>i.sendall(data)</code>

<code>                </code><code>except</code><code>:</code>

<code>                    </code><code>i.close()</code>

<code>                    </code><code>self</code><code>.socketList.remove(i)</code>

<code># 定義main函數</code>

<code>def</code> <code>main():</code>

<code>    </code><code>selectServer </code><code>=</code> <code>SelectServer(host</code><code>=</code><code>"192.168.154.131"</code><code>, port</code><code>=</code><code>9999</code><code>, backlog</code><code>=</code><code>5</code><code>)</code>

<code>    </code><code>selectServer._initSocket()</code>

<code>if</code> <code>__name__ </code><code>=</code><code>=</code> <code>'__main__'</code><code>:</code>

<code>    </code><code>main()</code>

client端代碼

<code>import</code> <code>socket, select, string, sys</code>

<code>import</code> <code>time</code>

<code># main function</code>

<code>if</code> <code>__name__ </code><code>=</code><code>=</code> <code>"__main__"</code><code>:</code>

<code>    </code><code>host </code><code>=</code> <code>"192.168.154.131"</code>

<code>    </code><code>port </code><code>=</code> <code>9999</code>

<code>    </code><code>s </code><code>=</code> <code>socket.socket(socket.AF_INET, socket.SOCK_STREAM)</code>

<code>    </code><code>s.settimeout(</code><code>2</code><code>)</code>

<code>    </code><code>try</code><code>:</code>

<code>        </code><code>s.connect((host, port))</code>

<code>    </code><code>except</code><code>:</code>

<code>        </code><code>print</code><code>(</code><code>'Unable to connect'</code><code>)</code>

<code>        </code><code>sys.exit()</code>

<code>    </code><code>print</code><code>(</code><code>'Connected to remote host. Start sending messages'</code><code>)</code>

<code>    </code><code>while</code> <code>1</code><code>:</code>

<code>        </code><code>rlist </code><code>=</code> <code>[sys.stdin, s]</code>

<code>        </code><code>read_list, write_list, error_list </code><code>=</code> <code>select.select(rlist, [], [])</code>

<code>        </code><code>for</code> <code>sock </code><code>in</code> <code>read_list:</code>

<code>            </code><code>if</code> <code>sock </code><code>=</code><code>=</code> <code>s:</code>

<code>                </code><code>data </code><code>=</code> <code>sock.recv(</code><code>2048</code><code>)</code>

<code>                </code><code>if</code> <code>not</code> <code>data:</code>

<code>                    </code><code>continue</code>

<code>                    </code><code>sys.stdout.write(data)</code>

<code>            </code><code>else</code><code>:</code>

<code>                </code><code>msg </code><code>=</code> <code>raw_input</code><code>(</code><code>"我說: "</code><code>)</code>

<code>                </code><code>s.sendall(msg)</code>

<code></code>

本文轉自 粗糧面包 51CTO部落格,原文連結:http://blog.51cto.com/culiangmianbao/2058054,如需轉載請自行聯系原作者