python SELECT疑问

nadia_forever 2014-06-11 11:19:59
在下想用非阻塞IO加python IO多路复用机制 发送大量HTTP请求(参考Apache AB代码)。这个方法如果用epoll是工作正常的,但是如果换成select就出现奇怪问题。

先上代码:

#!/usr/bin/python2.7                                                                                                                            

import select
import socket

class Client:
REQUEST_FMT = "HEAD %s HTTP/1.1\r\nHost: localhost\r\nAccept: *\r\n\r\n"
def __init__(self, uri):
self._sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self._sock.setblocking(False)
self._uri = uri
try:
self._sock.connect(("127.0.0.1", 801))
except socket.error, e:
if e.errno != 115:
raise e

def fileno(self):
return self._sock.fileno()

def test(self):
data = Client.REQUEST_FMT % self._uri
self._sock.send(data)

def judge(self):
print "HEHE %s" % self._sock.recv(1024)


if __name__ == "__main__":
dispatcher = select.select
a = Client("/test.flv")
b = Client("/50x.html")

data = {}
data[a.fileno()] = a
data[b.fileno()] = b

read_set = set((a, b))
write_set = set()

while len(data) != 0:

r_list, w_list, e_list = dispatcher(read_set, write_set, (), 30)

print "len(r_list)=%d" % len(r_list)

for i in r_list:
read_set.remove(i)
try:
i.test()
except socket.error, e:
print "HOLE SHIT!! %s" % e

else:
write_set.add(i)

for i in w_list:

write_set.remove(i)

i.judge()

if len(read_set) == 0 and len(write_set) == 0:
break


127.0.0.1:801起着我本机的NGINX。执行脚本后,执行netstat -ntp 可以看到脚本与 NGINX建立了TCP链接。但是SELECT必须在超时几次后,才会向NGINX发送HTTP请求,这让我很搞不懂。而且虽然脚本发送请求成功,但是NGINX访问日志并没有任何访问记录,而且i.judge()输出 HEHE 并没有返回页面内容这也让我很搞不懂。

执行 strace 查看 系统调用输出
9653 select(5, [3 4], [], [], {30, 0}) = 1 (in [4], left {29, 851925})
9653 write(1, "len(r_list)=1\n", 14) = 14
9653 sendto(4, "HEAD /50x.html HTTP/1.1\r\nHost: l"..., 55, 0, NULL, 0) = 55
9653 select(5, [3], [4], [], {30, 0}) = 1 (out [4], left {29, 999996})
9653 write(1, "len(r_list)=0\n", 14) = 14
9653 recvfrom(4, "", 1024, 0, NULL, NULL) = 0
9653 write(1, "HEHE \n", 6) = 6
9653 select(4, [3], [], [], {30, 0}) = 1 (in [3], left {29, 999998})
9653 write(1, "len(r_list)=1\n", 14) = 14
9653 sendto(3, "HEAD /test.flv HTTP/1.1\r\nHost: l"..., 55, 0, NULL, 0) = 55
9653 select(4, [], [3], [], {30, 0}) = 1 (out [3], left {29, 999998})
9653 write(1, "len(r_list)=0\n", 14) = 14
9653 recvfrom(3, "", 1024, 0, NULL, NULL) = 0
9653 write(1, "HEHE \n", 6) = 6

求各位分享一下自己看法。
...全文
118 4 打赏 收藏 转发到动态 举报
写回复
用AI写文章
4 条回复
切换为时间正序
请发表友善的回复…
发表回复
nadia_forever 2014-06-11
  • 打赏
  • 举报
回复
自己顶一下。
nadia_forever 2014-06-11
  • 打赏
  • 举报
回复
3楼所言极是。谢了~
panghuhu250 2014-06-11
  • 打赏
  • 举报
回复
r_list和w_list搞反了吧?r_list是可以读的,你用send,w_list是可以写的,你用recv. 还有,write_set开始为空,所以总不会有可以写的socket,而不发送请求,也不会有数据返回,select只有等到timeout.

#!/usr/bin/python2.7                                                                                                                            

import select
import socket

class Client:
    REQUEST_FMT = "HEAD %s HTTP/1.1\r\nHost: localhost\r\nAccept: *\r\n\r\n"
    def __init__(self, uri):
        self._sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self._sock.setblocking(False)
        self._uri = uri
        try:
            self._sock.connect(("127.0.0.1", 801))
        except socket.error, e:
            if e.errno != 115:
                raise e
        
    def fileno(self):
        return self._sock.fileno()

    def test(self):
        data = Client.REQUEST_FMT % self._uri
        self._sock.send(data)

    def judge(self):
        print "HEHE %s" % self._sock.recv(1024)

if __name__ == "__main__":
    dispatcher = select.select
    a = Client("/test.flv")
    b = Client("/50x.html")

    data = {}
    data[a.fileno()] = a
    data[b.fileno()] = b
    read_set = set((a, b))
    write_set = set((a,b))

    while len(data) != 0:
        r_list, w_list, e_list = dispatcher(read_set, write_set, (), 30)

        print "len(r_list)=%d" % len(r_list)
        print "len(w_list)=%d" % len(w_list)

        for i in r_list:
            read_set.remove(i)
            try:
                i.judge()
            except socket.error, e:
                print "HOLE SHIT!! %s" % e
            else:
                write_set.add(i)
        for i in w_list:
            write_set.remove(i)
            i.test()
        if len(read_set) == 0 and len(write_set) == 0:
            break
运行结果(马上出结果,没有timeout):

len(r_list)=0
len(w_list)=2
len(r_list)=1
len(w_list)=0
HEHE HTTP/1.1 404 Not Found
server: ecstatic-0.4.5
Content-Type: text/plain
Date: Wed, 11 Jun 2014 12:49:22 GMT
Connection: keep-alive


len(r_list)=0
len(w_list)=1
len(r_list)=1
len(w_list)=0
HEHE HTTP/1.1 404 Not Found
server: ecstatic-0.4.5
Content-Type: text/plain
Date: Wed, 11 Jun 2014 12:49:22 GMT
Connection: keep-alive


len(r_list)=0
len(w_list)=1

nadia_forever 2014-06-11
  • 打赏
  • 举报
回复
自己在顶一下

37,719

社区成员

发帖
与我相关
我的任务
社区描述
JavaScript,VBScript,AngleScript,ActionScript,Shell,Perl,Ruby,Lua,Tcl,Scala,MaxScript 等脚本语言交流。
社区管理员
  • 脚本语言(Perl/Python)社区
  • IT.BOB
加入社区
  • 近7日
  • 近30日
  • 至今

试试用AI创作助手写篇文章吧