# Written by Bram Cohen
# see LICENSE.txt for license information
#文件名称:RewServer.py
#读码日记:2004-9-7
#笔 者:zfive5(醉马不肖 之 [孤舟蓑笠翁, 独钓寒江雪])
#
# 分析RawServer类 主要负责socket通讯
#poll( | [timeout]) |
(fd,
#event)
2-tuples for the descriptors that have events or errors to report. fd is the file #descriptor, and event is a bitmask with bits set for the reported events for that descriptor --
from bisect import insort
import socket
from cStringIO import StringIO
from traceback import print_exc
from errno import EWOULDBLOCK, EINTR
try:
from select import poll, error, POLLIN, POLLOUT, POLLERR, POLLHUP
timemult = 1000
except ImportError:
from selectpoll import poll, error, POLLIN, POLLOUT, POLLERR, POLLHUP
timemult = 1
from threading import Thread, Event
from time import time, sleep
import sys
from random import randrange
all = POLLIN | POLLOUT
#socket类,对基础socket类进行封装,这也是通讯的基础
class SingleSocket:
def __init__(self, raw_server, sock, handler):
self.raw_server = raw_server
self.socket = sock
self.handler = handler
self.buffer = []
self.last_hit = time()
self.fileno = sock.fileno()
self.connected = False
#得到连接对方的ip地址
def get_ip(self):
try:
return self.socket.getpeername()[0]
except socket.error:
return 'no connection'
#关闭socket连接,这里有点像window的closesocket()函数
def close(self):
sock = self.socket
self.socket = None
self.buffer = []
del self.raw_server.single_sockets[self.fileno]
self.raw_server.poll.unregister(sock)
sock.close()
#这就不用说了,是shutdown()了
def shutdown(self, val):
self.socket.shutdown(val)
#判断缓冲区列表是否为空
def is_flushed(self):
return len(self.buffer) == 0
#功能就是把数据写到缓冲区列表中,当列表元素为1时,发送数据
#给连接对方
def write(self, s):
assert self.socket is not None
self.buffer.append(s)
if len(self.buffer) == 1:
self.try_write()
#发送数据给对方
def try_write(self):
if self.connected:
try:
while self.buffer != []:
amount = self.socket.send(self.buffer[0])
if amount != len(self.buffer[0]):
if amount != 0:
self.buffer[0] = self.buffer[0][amount:]
break
del self.buffer[0]
except socket.error, e:
code, msg = e
if code != EWOULDBLOCK:
self.raw_server.dead_from_write.append(self)
return
#缓冲区为空,就只注册读数据事件
if self.buffer == []:
self.raw_server.poll.register(self.socket, POLLIN)
else:
#要不读写都注册
self.raw_server.poll.register(self.socket, all)
#服务器类
class RawServer:
def __init__(self, doneflag, timeout_check_interval, timeout, noisy = True, errorfunc = None):
self.timeout_check_interval = timeout_check_interval
self.timeout = timeout
self.poll = poll()
# {socket: SingleSocket}
self.single_sockets = {}
self.dead_from_write = []
self.doneflag = doneflag
self.noisy = noisy
self.errorfunc = errorfunc
self.funcs = []
self.externally_added = []
self.add_task(self.scan_for_timeouts, timeout_check_interval)
#增加一个任务到任务列表,最后运行时刻为time()+delay
def add_task(self, func, delay):
insort(self.funcs, (time() + delay, func))
#增加一个附加的任务到任务列表,最后运行时刻为time()+delay
def external_add_task(self, func, delay = 0):
self.externally_added.append((func, delay))
#检查服务器超时socket函数,如果超时关掉处理函数
def scan_for_timeouts(self):
self.add_task(self.scan_for_timeouts, self.timeout_check_interval)
t = time() - self.timeout
tokill = []
for s in self.single_sockets.values():
if s.last_hit < t:
tokill.append(s)
for k in tokill:
if k.socket is not None:
self._close_socket(k)
#捆绑一个端口,设置非阻塞方式,服务器socket与事件注册对应
def bind(self, port, bind = '', reuse = False):
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
if reuse:
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server.setblocking(0)
server.bind((bind, port))
server.listen(5)
self.poll.register(server, POLLIN)
self.server = server
#连接对方,设置非阻塞方式,socket与事件注册对应
def start_connection(self, dns, handler = None):
if handler is None:
handler = self.handler
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setblocking(0)
try:
sock.connect_ex(dns)
except socket.error:
raise
except Exception, e:
raise socket.error(str(e))
self.poll.register(sock, POLLIN)
s = SingleSocket(self, sock, handler)
self.single_sockets[sock.fileno()] = s
return s
#处理服务器和所有与服务器连接的数据请求,events是socket和关心事件对应列表
def handle_events(self, events):
for sock, event in events:
if sock == self.server.fileno():
#错误关闭服务器
if event & (POLLHUP | POLLERR) != 0:
self.poll.unregister(self.server)
self.server.close()
self.errorfunc('lost server socket')
else:
#服务器accept
try:
newsock, addr = self.server.accept()
newsock.setblocking(0)
nss = SingleSocket(self, newsock, self.handler)
self.single_sockets[newsock.fileno()] = nss
#注册读数据事件
self.poll.register(newsock, POLLIN)
self.handler.external_connection_made(nss)
except socket.error:
#accept失败sleep(1),然后继续
sleep(1)
else:
s = self.single_sockets.get(sock)
if s is None:
continue
s.connected = True
#错误关闭socket
if (event & (POLLHUP | POLLERR)) != 0:
self._close_socket(s)
continue
#读数据处理过程
if (event & POLLIN) != 0:
try:
s.last_hit = time()
data = s.socket.recv(100000)
if data == '':
self._close_socket(s)
else:
#调用处理函数
s.handler.data_came_in(s, data)
except socket.error, e:
code, msg = e
if code != EWOULDBLOCK:
self._close_socket(s)
continue
#写数据处理过程
if (event & POLLOUT) != 0 and s.socket is not None and not s.is_flushed():
s.try_write()
if s.is_flushed():
s.handler.connection_flushed(s)
#弹出附加任务
def pop_external(self):
try:
while True:
(a, b) = self.externally_added.pop()
self.add_task(a, b)
except IndexError:
pass
#download里调用的处理函数,这里主要是完成数据处理和调用处理
def listen_forever(self, handler):
self.handler = handler
try:
#如果完成标志被执就退出
while not self.doneflag.isSet():
try:
#加入一个附加任务
self.pop_external()
#任务列表为空
if len(self.funcs) == 0:
period = 2 ** 30
else:
#任务列表不为空
period = self.funcs[0][0] - time()
间隔小于零,就间隔执零
if period < 0:
period = 0
#设置注册事件超时
events = self.poll.poll(period * timemult)
#如果完成标志被执就退出
if self.doneflag.isSet():
return
#调用任务处理函数
while len(self.funcs) > 0 and self.funcs[0][0] <= time():
garbage, func = self.funcs[0]
del self.funcs[0]
try:
func()
except KeyboardInterrupt:
print_exc()
return
except:
if self.noisy:
data = StringIO()
print_exc(file = data)
self.errorfunc(data.getvalue())
#关闭无反映的socket
self._close_dead()
#处理socket请求或数据接收、发送
self.handle_events(events)
#如果完成标志被执就退出
if self.doneflag.isSet():
return
#关闭无反映的socket
self._close_dead()
except error:
if self.doneflag.isSet():
return
except KeyboardInterrupt:
print_exc()
return
except:
data = StringIO()
print_exc(file = data)
self.errorfunc(data.getvalue())
finally:
for ss in self.single_sockets.values():
ss.close()
self.server.close()
#关闭死的连接
def _close_dead(self):
while len(self.dead_from_write) > 0:
old = self.dead_from_write
self.dead_from_write = []
for s in old:
if s.socket is not None:
self._close_socket(s)
#关闭socket连接
def _close_socket(self, s):
sock = s.socket.fileno()
s.socket.close()
self.poll.unregister(sock)
del self.single_sockets[sock]
s.socket = None
s.handler.connection_lost(s)
#下面是测试用例,这里省略不写,接下来Storage类留到下次在分析吧。。。。。