使用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,如需转载请自行联系原作者