python epoll模型实现类似redis缓存数据库,先把功能实现了。争用问题暂没弄,看代码。server.py:
import socketimport selectimport reimport urllib2from py_db import auth as auth_infoEOL1 = b'exit'EOL2 = b'quit'EOL3 = b'\n'class Database(): def __init__(self): self.data = {} def get(self, key): if key in self.data.keys(): return self.data[key] else: return None def set(self, key, value): if key in self.data.keys(): self.data[key] = value else: self.data.setdefault(key, value) return 'ok'def fetch(url): request = urllib2.Request(url) request.get_method = lambda: 'HEAD' response = urllib2.urlopen(request) return response.code, response.info()["Content-Length"]class Server(): def __init__(self, host='localhost', port=5678): self.host = host self.port = port self.username = auth_info["username"] self.password = auth_info["password"] self.authenticated = False def auth(self, username, password): if username == self.username and password == self.password: self.authenticated = True return True else: self.authenticated = False return False def start(self): serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) serversocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) serversocket.bind((self.host, self.port)) serversocket.listen(1) serversocket.setblocking(0) epoll = select.epoll() epoll.register(serversocket.fileno(), select.EPOLLIN) try: connections = {} requests = {} responses = {} while True: events = epoll.poll(1) for fileno, event in events: if fileno == serversocket.fileno(): connection, address = serversocket.accept() connection.setblocking(0) epoll.register(connection.fileno(), select.EPOLLIN) connections[connection.fileno()] = connection requests[connection.fileno()] = b'' responses[connection.fileno()] = 'hello' elif event & select.EPOLLIN: requests[fileno] = connections[fileno].recv(1024) if EOL3 in requests[fileno] and re.search("[set \w+ \w+|get \w+|AUTH \w+ \w+|URL \w+ \w+]", requests[fileno]): try: data = requests[fileno].decode()[:-2].split() method = data[0].strip() ret = None if method == "set": ret = db.set(data[1], data[2]) if method == "get": ret = db.get(data[1]) if method == "AUTH": username, password = data[1], data[2] if self.auth(username, password): ret = 'ok' else: ret = 'bad' if method == "URL": name, url = data[1], data[2] if self.authenticated: if name in db.data.keys(): ret = db.data[name] else: code, size = fetch(url) db.data[name] = {"code": code, "size": size} ret = "ok" else: ret = "unauthenticated user" byteswritten = connections[fileno].send(bytes('%s\n' % ret)) responses[fileno] = responses[fileno][byteswritten:] except: byteswritten = connections[fileno].send(bytes('bad\n')) finally: print db.data if EOL1 in requests[fileno] or EOL2 in requests[fileno]: epoll.modify(fileno, select.EPOLLOUT) elif event & select.EPOLLOUT: responses[fileno] = responses[fileno][byteswritten:] if len(responses[fileno]) == 0: epoll.modify(fileno, 0) connections[fileno].shutdown(socket.SHUT_RDWR) elif event & select.EPOLLHUP: epoll.unregister(fileno) connections[fileno].close() del connections[fileno] finally: epoll.unregister(serversocket.fileno()) epoll.close() serversocket.close()if __name__ == "__main__": db = Database() ss = Server() ss.start()
auth.py
#!/usr/bin/env python# -*- coding: utf-8 -*- # tanyewei@gmail.com# 2014/03/18 21:15auth = { "username" : "redis", "password" : "redis123"}
效果图:
原文地址:python epoll模型实现类似redis缓存, 感谢原作者分享。 人生就是一次充满未知的旅行,在乎的是沿途的风景,