先看一个例子IO-multiplexing+阻塞IO
首先需要明确的是IO复用是同步的,并不是异步的
IO-multiplexing+阻塞IO
程序实现了Netcat的简单功能
#!/usr/bin/python
import os
import select
import socket
import sys
def relay(sock):
poll = select.poll()
poll.register(sock, select.POLLIN)
poll.register(sys.stdin, select.POLLIN)
done = False
while not done:
events = poll.poll(10000) # 10 seconds
for fileno, event in events:
if event & select.POLLIN:
if fileno == sock.fileno():
data = sock.recv(8192)
if data:
sys.stdout.write(data)
else:
done = True
else:
assert fileno == sys.stdin.fileno()
data = os.read(fileno, 8192)
if data:
sock.sendall(data)
else:
sock.shutdown(socket.SHUT_WR)
poll.unregister(sys.stdin)
def main(argv):
if len(argv) < 3:
binary = argv[0]
print "Usage:\n %s -l port\n %s host port" % (argv[0], argv[0])
return
port = int(argv[2])
if argv[1] == "-l":
# server
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_socket.bind(('', port))
server_socket.listen(5)
(client_socket, client_address) = server_socket.accept()
server_socket.close()
relay(client_socket)
else:
# client
sock = socket.create_connection((argv[1], port))
relay(sock)
if __name__ == "__main__":
main(sys.argv)
试验1
[root@localhost python]# python netcat.py localhost 1234 > /dev/null
//chargen会打印吞吐量,write hole,只输出数据,不接受数据
[root@localhost tpc]# ./chargen -l 1234
Accepting... Ctrl-C to exit
accepted no. 1 client
171.688 MiB/s
166.395 MiB/s
186.773 MiB/s
240.171 MiB/s
235.967 MiB/s
130.270 MiB/s
18.044 MiB/s
client端
python netcat.py localhost 1234 > /dev/null
试验2
先在./chargen -l 1234命令行下敲几个输入,如下
[root@localhost tpc]# ./chargen -l 1234
Accepting... Ctrl-C to exit
accepted no. 1 client
171.688 MiB/s
166.395 MiB/s
186.773 MiB/s
240.171 MiB/s
235.967 MiB/s
130.270 MiB/s
18.044 MiB/s
accepted no. 2 client
11.838 MiB/s
。。
//这里chargen不打印了,阻塞了
client端
python netcat.py localhost 1234 < /dev/zero > /dev/null
这里用strace看一下netcat.py阻塞在了sendto()上。
用netstat查看下
[root@localhost david]# netstat -tnp | grep 1234
tcp 5966266 4188544 127.0.0.1:50776 127.0.0.1:1234 ESTABLISHED 5620/python
tcp 975372 4169984 127.0.0.1:1234 127.0.0.1:50776 ESTABLISHED 5612/./chargen
netcat.py阻塞在了write上,其发送缓冲区满了;因此chargen也会阻塞在write上。
再看一个thread-per-connection的netcat,并没有影响,chargen任然在打印
[root@localhost david]# netstat -tnp | grep 1234
tcp 0 4188544 127.0.0.1:50778 127.0.0.1:1234 ESTABLISHED 5802/./netcat
tcp 975372 0 127.0.0.1:1234 127.0.0.1:50778 ESTABLISHED 5612/./chargen
netcat继续再收,虽然阻塞在发送上(可从上面看出netcat的发送缓冲区满了),但是任然在接受。
注意IO复用如果和阻塞IO一起使用了,一旦真的阻塞,就会把此事件循环中管的别的事件挡住了