[Python网络编程]使用select,poll

平时我们看到的非阻塞socket(select,poll,epoll)多用在服务器端,相比于客户端,我们很容易淹没在细节之中。下面是客户端使用select,poll的代码事例。

我们使用简单的同步socket获取http://192.168.9.178/cs.php?a=php的内容,

# -*- coding: utf-8 -*-

import socket
import select
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
host = '192.168.9.178'
s.connect((host,80))
packet = """\
GET /cs.php?a=php HTTP/1.0
Host: %s

""" % host
contentLength=len(packet)

#sync
s.send(packet)
print packet
d=[]
while 1:
    b=s.recv(100)
    if not b:
        break
    d.append(b)

print ''.join(d)
print 'done'

下面使用非阻塞socket发送同样请求,首先使用select,代码有意并没有一次发送或读取很多字节,这样通过打印我们就可以看到异步请求的过程。

# -*- coding: utf-8 -*-

import socket
import select
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
host = '192.168.9.178'
s.connect((host,80))
packet = """\
GET /cs.php?a=php HTTP/1.0
Host: %s

""" % host
contentLength=len(packet)

#async
s.setblocking(0)
start=0
d=[]
while 1:
    r,w,e=select.select([s],[s],[s],10)
    if e:
        print 'errr'
        break
    if s in w:
        if start < contentLength:
            start += s.send(packet[start:start+20])
    if s in r:
        b=s.recv(20)
        if not b:
            break
        d.append(b)

print ''.join(d)
print 'done'

select可直接处理类socket对象,只要具有fileno方法即可。

下面是用poll实现相同的功能,不管是select还是poll都要关注结束条件。由于poll比select多了for循环,所以通过标志位判断是否结束。


# -*- coding: utf-8 -*-

import socket
import select
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
host = '192.168.9.178'
s.connect((host,80))
packet = """\
GET /cs.php?a=php HTTP/1.0
Host: %s

""" % host
contentLength=len(packet)

#sync
s.send(packet)
print packet
d=[]
while 1:
    b=s.recv(100)
    if not b:
        break
    d.append(b)

print ''.join(d)
print 'done'

#async poll
s.setblocking(0)
READ_ONLY = select.POLLIN | select.POLLPRI | select.POLLHUP | select.POLLERR
READ_WRITE = READ_ONLY | select.POLLOUT

poller=select.poll()
poller.register(s,READ_WRITE)
start=0
d=[]
sfd = s.fileno()
fail=full=0
while 1:
    events = poller.poll(1000) #单位毫秒
    for fd,flag in events: #返回的是(fileno,falg)的列表
        if fd is sfd:
            if flag & select.POLLOUT:
                if start < contentLength: #这边最好判断一下内容是否已发送完,因为发送完了fd还是可写的
                    start += s.send(packet[start:start+20])
            if flag & (select.POLLIN | select.POLLPRI): #注意这边不要elif,因为fd经常是可读可写
                b=s.recv(10)
                if not b: #有读事件,但为EOF,说明内容已结束
                    full=1
                    break
                d.append(b)
            if flag & select.POLLHUP:
                print 'POLLHUP'
                fail = 1
           
    if full or fail:
        break

print ''.join(d)
print 'done'


你可能感兴趣的:([Python网络编程]使用select,poll)