python语言封装对tcp做一些简单的封装,采用异步通讯模式,事件式的编程; 让其他编程人员
不需要考虑通讯的具体细节,只要编写几个函数,将函数作为参数传给通讯基类,由通讯基类来触发
事件,调用这些业务函数,完成整个业务流程. 通讯可能采用短连接,也可能是长连接.
内部核心系统会采用消息中间件来通讯, 需要发送到外系统的数据, 会用
到通讯类; 所以通讯类一边要监听消息队列, 一边要和外系统通讯,这样,就会需要有两个线程来
处理,希望将线程的处理也封装在通讯基类中, 最好对业务层编写者不可见.
这个通讯基类我已经写了一部分,你先看看, 但是我写的还没有涉及到线程这块的处理.
#coding:gbk
import socket
import select
import time
#指令 源地址 目的地址 NAT地址 每个字段4个字节,不足后补空格
class YTClientSocket:
s=None
requestpacket='';
requesttime=0;
doonconnecterror=None;
doonreply=None;
doonreplytimeout=None;
def __init__(self,host,port):
self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.s.setblocking(0)
self.s.connect_ex((host,port))
def close(self):
self.s.close()
self.s=None
def setrequestpacket(self,packet):
self.requestpacket=packet
def onconnectsucess(self):
self.s.send(self.requestpacket)
def fileno(self):
if self.s!=None:
return self.s.fileno()
def setconnecterrorcallback(self,callback):
self.doonconnecterror=callback
def onconnecterror(self):
if (self.doonconnecterror!=None):
self.doonconnecterror()
def setonreplycallback(self,callback):
self.doonreply=callback
def onreply(self):
vars=locals()
if (vars['doreply']!=None):
self.doonreply()
def setonreplytimetoutcallback(self,callback):
self.doonreplytimeout=callback
def onreplytimeout(self):
vars=locals()
if (vars['doreplytimeout']!=None):
self.doonreplytimeout()
class YTShortLinkClientSocket:
epoll=None
sockets={}
connecting_sockets={}
socket_bg=None
def __init__(self):
self.epoll=select.epoll()
def connectbg(self):
self.socket_bg=YTClientSocket('127.0.0.1',2010)
self.epoll.register(self.socket_bg.fileno(), select.EPOLLOUT)
def newconnection(self,host,port):
cli_sock=YTClientSocket(host,port)
self.connecting_sockets[cli_sock.fileno()]=[cli_sock,time.time()]
self.epoll.register(cli_sock.fileno(), select.EPOLLOUT)
def mainloop(self):
while True:
es=self.epoll.poll(1)
print es
for fn,e in es:
if fn == self.socket_bg.fileno():
if e & select.EPOLLERR:
self.epoll.unregister(self.socket_bg.fileno())
self.socket_bg.close()
connectbg(self)
time.sleep(1)
break
if e & select.EPOLLOUT:
self.epoll.modify(self.socket_bg.fileno(),select.EPOLLIN)
self.socket_bg.setrequestpacket(self,'%-4s%-4s%-4s%-4s/0'%('LGN','101','10',''))
self.socket_bg.onconnectsucess(self)
continue
if fn in self.connecting_sockets:
if e & select.EPOLLERR:
#连接失败
cli_sock=self.connecting_sockets[fn][0]
cli_sock.onconnecterror()
cli_sock.close()
self.connecting_sockets.pop(fn)
self.epoll.unregister(fn)
if e & select.EPOLLOUT:
#连接成功
cli_sock=self.connecting_sockets[fn][0]
self.epoll.modify(cli_sock.fileno(),select.EPOLLIN)
cli_sock.onconnectsucess()
self.sockets[fn]=[cli_sock,time.time()]
if fn in self.sockets:
cli_sock=self.sockets[fn][0]
if e & select.EPOLLERR:
cli_sock.onreplytimeout()
if e & select.EPOLLIN:
cli_sock.onreply()
#处理超时的socket
for k,v in self.sockets.items():
if time.time()-v[1]>30:
print time.time(),v[1]
cli_sock=v[0]
cli_sock.close()
self.sockets.pop(k)
def close(self):
for k,v in self.connecting_sockets.items():
cli_sock=v[0]
cli_sock.close()
self.connecting_sockets={}
for k,v in self.sockets.items():
cli_sock=v[0]
cli_sock.close()
self.sockets={}
self.epoll.close()
yy=YTShortLinkClientSocket()
yy.newconnection('192.168.2.111',53)
yy.mainloop()