這是一個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