这是一个interface上通过脚本扩展短链接第三方登录的例子,这个类可以看成是一个poller,每一个登陆请求可以创建一个这样的poller,也可以在外部设计一个回收池来回收。完全看你自己想要怎么管理。 初始化以后使用start方法来连接并通过socket模拟http发送消息,发送完毕之后会等待接受返回。示例中通过解析json串来得到返回信息,用户可以根据自己的需要修改成其他的方式。 这个示例中通过使用向底层注册fd的方式实现了异步发送和异步接收。 可能的问题:该示例中connet这一步依然是阻塞的,在极限情况下可能存在性能问题。 |
# -*- coding: utf-8 -*-
import KBEngine
import Functor
import socket
from KBEDebug import *
import json
class LoginPoller:
def __init__(self, _callback, _host, _page, _port, _overtime = 5):
"""
@param _callback: 数据处理完毕之后调用的外部回调, 注意不可在外部回调中销毁这个LoginPoller自己
@param _host: 主机地址, 可以是域名也可以是ip地址
@param _page: 请求页面
@param _port: 请求端口
@param _overtime: 超时秒数
"""
self._socket = None
self._request_str = ""
self._recv_str = ""
self._recv_data = {}
self._callback = _callback
self._host = _host
self._page = _page
self._port = _port
self._overtime = _overtime
self._registerRead = False
self._registerWrite = False
def start(self, _commitName, _realAccountName, _datas, _param_data, _tid):
"""
@param _commitName, _realAccountName, _datas: 这三个参数来自于requestAccountLogin,记在这个LoginPoller中,
数据请求完毕之后可以从外部重新拿到这些数据
@param _param_data: http请求参数
@param _tid: 可视为这个LoginPoller的Id, 回调时会返回这个id, 便于外部管理
"""
self._commitName = _commitName
self._realAccountName = _realAccountName
self._datas = _datas
self._tid = _tid
self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
DEBUG_MSG("self._host: %s, self._port: %d" % (self._host, self._port))
self._socket.connect((self._host, self._port))
self.registerRead()
_rstr = "GET " + self._page + "?" + _param_data + " HTTP/1.1\r\n"
_rstr += "Host: %s\r\n" % self._host
_rstr += "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:43.0) Gecko/20100101 Firefox/43.0\r\n"
_rstr += "Connection: close\r\n"
_rstr += "\r\n"
self._request_str = _rstr.encode()
_sendAll = self.send()
if _sendAll != True:
self.registerWrite()
def stop(self):
self.deregisterRead()
self.deregisterWrite()
if self._socket != None:
self._socket.close()
self._socket = None
def send(self):
_send_lenth = self._socket.send(self._request_str)
self._request_str = self._request_str[_send_lenth:]
if len(self._request_str) == 0:
return True
else:
return False
def checkValidity(self):
# 检查有效性, 超时检查
if self._overtime > 0 and self._socket != None:
self._overtime -= 1
return True
else:
return False
def onWrite(self, fileno):
_sendAll = self.send()
if _sendAll == True:
self.deregisterWrite()
def onRecv(self, fileno):
_data = self._socket.recv(2048)
DEBUG_MSG("onRecv: %s" % _data)
if self.checkRecv(_data) == True:
self.processData()
self.stop()
self._callback(self._tid)
def checkRecv(self, _data):
self._recv_str += _data.decode()
DEBUG_MSG("checkRecv: %s" % self._recv_str)
_count1 = self._recv_str.count('{')
_count2 = self._recv_str.count('}')
if _count1 == _count2 and _count1 > 0:
return True
return False
def processData(self):
"""
处理接收数据
从接收数据中截取json串并解析
"""
_index1 = self._recv_str.find('{')
_index2 = self._recv_str.rfind('}')
_bodyStr = self._recv_str[_index1: _index2 + 1]
DEBUG_MSG("_bodyStr: %s" % _bodyStr)
self._recv_data = json.loads(_bodyStr)
DEBUG_MSG("self._recv_data: %s" % str(self._recv_data))
def getPollerInfos(self):
return self._commitName, self._realAccountName, self._datas, self._recv_data
def registerRead(self):
if self._registerRead == False:
KBEngine.registerReadFileDescriptor(self._socket.fileno(), self.onRecv)
self._registerRead = True
def registerWrite(self):
if self._registerWrite == False:
KBEngine.registerWriteFileDescriptor(self._socket.fileno(), self.onWrite)
self._registerWrite = True
def deregisterRead(self):
if self._registerRead == True:
KBEngine.deregisterReadFileDescriptor(self._socket.fileno())
self._registerRead = False
def deregisterWrite(self):
if self._registerWrite == True:
KBEngine.deregisterWriteFileDescriptor(self._socket.fileno())
self._registerWrite = False