使用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拷贝到内核空间(每次都要拷贝),导致效率下降
每次调用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
|
#/usr/bin/env python
#-*- coding:utf-8 -*-
import
socket
import
select
# 封装
class
SelectServer(
object
):
# 定义主函数
def
__init__(
self
, host, port, backlog):
self
.host
=
host
self
.port
=
port
self
.address
=
(host, port)
self
.backlog
=
backlog
self
.server
=
None
self
.socketList
=
list
()
def
_initSocket(
self
):
self
.server
=
socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self
.server.bind(
self
.address)
self
.server.listen(
self
.backlog)
self
.socketList.append(
self
.server)
print
(
"chat room has start!"
)
while
1
:
rlist, wlist, elist
=
select.select(
self
.socketList, [], [])
for
r
in
rlist:
if
r
=
=
self
.server:
serverConn, clienAddr
=
self
.server.accept()
self
.socketList.append(serverConn)
print
(
"{0}进入了房间"
.
format
(clienAddr))
self
.broadcast(r,
"{0}进入了房间"
.
format
(clienAddr))
else
:
try
:
data
=
r.recv(
2048
)
if
data:
print
(
"{0}: {1}"
.
format
(clienAddr, data))
self
.broadcast(r,
"{0}: {1}"
.
format
(clienAddr, data))
except
Exception as e:
self
.broadcast(r,
"{0}下线"
.
format
(clienAddr))
print
(
"{0}下线"
.
format
(clienAddr))
r.close()
self
.socketList.remove(r)
self
.server.close()
# 定义广播函数
def
broadcast(
self
, r, data):
for
i
in
self
.socketList:
if
i !
=
r
and
i !
=
self
.server:
try
:
i.sendall(data)
except
:
i.close()
self
.socketList.remove(i)
# 定义main函数
def
main():
selectServer
=
SelectServer(host
=
"192.168.154.131"
, port
=
9999
, backlog
=
5
)
selectServer._initSocket()
if
__name__
=
=
'__main__'
:
main()
|
client端代码
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
|
#/usr/bin/env python
#-*- coding:utf-8 -*-
import
socket, select, string, sys
import
time
# main function
if
__name__
=
=
"__main__"
:
host
=
"192.168.154.131"
port
=
9999
s
=
socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(
2
)
try
:
s.connect((host, port))
except
:
print
(
'Unable to connect'
)
sys.exit()
print
(
'Connected to remote host. Start sending messages'
)
while
1
:
rlist
=
[sys.stdin, s]
read_list, write_list, error_list
=
select.select(rlist, [], [])
for
sock
in
read_list:
if
sock
=
=
s:
data
=
sock.recv(
2048
)
if
not
data:
continue
else
:
sys.stdout.write(data)
else
:
msg
=
raw_input
(
"我说: "
)
s.sendall(msg)
|