add python client

New
j 4 years ago
parent d2bab4a56d
commit ce045f0c86

@ -0,0 +1,74 @@
# python 版 weaving_client
#### 文件介绍:
**weaving_client.py:** python 版的 weaving_client 框架,使用 python3
**weaving_app.py:** 作为示例程序,调用了 weaving_client.py
#### 使用步骤:
##### 1.用一个IP地址加端口如 192.168.0.20:5678初始化一个 WeavingClinet 的对象:
```python
server_addr = '192.168.0.20:5678'
wc = WeavingClient(server_addr)
```
##### 2.使用 wc.reg_wcmd 为你感兴趣的命令字注册无返回值的回调函数(协议解析出的有效数据字节串将作为参数传递给它):
```python
WCMD_HEARTBEAT = 0x99 # WCMD 指 weaving 框架里的命令字 "weaving cmd"
WCMD_SOMECMD
def some_function(bdata:bytes):
print('解析出的有效数据字节序列:{}'.format(bdata))
wc.reg_wcmd(WCMD_HEARTBEAT,None) # 不处理心跳包,其实不使用 reg_wcmd 注册的命令字默认不处理
wc.reg_wcmd(WCMD_SOMECMD,some_function)
```
##### 3.指定连接到服务端时的回调函数,通常需要用这个来注册客户端
```python
reg_msg = {'cmd':'reg','id':'12345678'} # 注意这个 cmd 相对于 wcmd 只是一个普通数据的一部分
def send_data(bdata:bytes):
wc.send_data(CMD_SOMECMD,bdata)
def send_msg(msg:dict):
bdata = json.dumps(msg).encode()
send_data(bdata)
def reg_self():
self.send_msg(reg_msg)
wc.on_connect = reg_self
```
##### 4.现在完成了基本配置,可以启动了:
```python
def start():
wc.start()
print('Now we can do other things...')
print('This is just one example, if you want exit, you can:')
print('on windows: print Ctrl + Pause Break')
print('on linux: print Ctrl + C')
start()
```
##### 5.更详细的使用方法参见 weaving_app.py 或自由定制

@ -0,0 +1,70 @@
import weaving_client
from weaving_client import *
import json
flag_test = False
# ------------------ app define begin ------------------------------
WCMD_HEARTBEAT = 0x99
WCMD_SOMECMD = 0x02
server_addr = '192.168.0.20:5678'
reg_msg = {'cmd':'reg','id':'12345678'}
# ------------------ app define end --------------------------------
class WeavingApp():
def __init__(self, server_addr):
self.cmd_dict = {}
self.lock_playing = False
self.wc = WeavingClient(server_addr)
self.wc.reg_wcmd(WCMD_HEARTBEAT,None)
self.wc.reg_wcmd(WCMD_SOMECMD,self.proc_msg)
self.wc.on_connect = self.reg_self
self.reg_cmd('echo',self.cmd_echo)
def send_data(self,bdata:bytes):
self.wc.send_data(WCMD_SOMECMD,bdata)
def send_msg(self,msg:dict):
bdata = json.dumps(msg).encode()
self.send_data(bdata)
def reg_cmd(self,cmd,func): # this cmd is self cmd, the difference in weaving cmd(wcmd)
self.cmd_dict[cmd] = func
def start(self):
self.wc.start()
print('Now we can do other things...')
print('This is just one example, if you want exit, you can:')
print('on windows: print Ctrl + Pause Break')
print('on linux: print Ctrl + C')
def reg_self(self):
self.send_msg(reg_msg)
def proc_msg(self,bmsg:bytes):
dmsg = json.loads(bmsg.decode())
cmd = dmsg.get('cmd','')
data = dmsg.get('data','')
func = self.cmd_dict.get(cmd,None)
if(func):
func(data)
def cmd_echo(self,data:str):
wclog('data is: '+data)
if(data):
os.system('echo {}'.format(data))
def main():
weaving_client.flag_use_wclog = True # 可以在这种位置开关 weaving_client 里的 wclog 函数的打印功能
wa = WeavingApp(server_addr)
wa.start()
if __name__ == '__main__':
main()

@ -0,0 +1,177 @@
import socket
import threading
import time
import traceback
import os
# ------------------ function for weaving port begin ---------------------
flag_use_wclog = False
def get_time():
a = time.time() # such like 1579141285.7733445
b = int(a) # such like 1579141285
e = time.localtime(b)
f = time.strftime("%y%m%d-%H:%M:%S",e) # such like '200116102125'
return f
def wclog(*x):
if(flag_use_wclog):
s = ''.join(x)
print(get_time(),s,flush=True)
# crc16_xmodem
# 0x11 0x22 0x33 0x44 crc is 0xdd 0x33
# 0x12 0x34 0x56 0x78 crc is 0xb4 0x2c
def crc16_xmodem(bdata:bytes)->bytes:
wcrc = 0
for b in bdata:
for j in range(8):
treat = b & 0x80
b <<= 1
bcrc = (wcrc >> 8) & 0x80
wcrc <<= 1
wcrc = wcrc & 0xffff
if (treat != bcrc):
wcrc ^= 0x1021
return wcrc.to_bytes(2,'big')
def con_crc(bdata:bytes)->bytes:
return bdata + crc16_xmodem(bdata)
def chk_crc(bdata:bytes)->bool:
if(len(bdata)<3):
return False
if(bdata[-2:] == crc16_xmodem(bdata[:-2])):
return True
else:
return False
def weaving_pack(icmd:int,bdata:bytes)->bytes:
len_bdata = len(bdata)
blen = len_bdata.to_bytes(4,'little').rstrip(b'\x00')
len_blen = len(blen)
ret = bytes([icmd,len_blen]) + blen
ret = con_crc(ret) + bdata
return ret
def weaving_unpack(bdata:bytes)->(bool,int,bytes,bytes):
wclog('into weaving_unpack')
flag_result = False
icmd = 0x00
bmsg = b''
while(True):
if(len(bdata) < 4):
return flag_result,icmd,bmsg,bdata
len_blen = bdata[1]
if(len(bdata) < len_blen+4):
return flag_result,icmd,bmsg,bdata
blen = bdata[2:2+len_blen]
len_bdata = int.from_bytes(blen,'little')
if(len(bdata) < len_blen+4+len_bdata):
return flag_result,icmd,bmsg,bdata
if(not chk_crc(bdata[:4+len_blen])):
bdata = bdata[1:]
continue
else:
flag_result,icmd,bmsg,bdata = True, bdata[0], bdata[4+len_blen:4+len_blen+len_bdata], bdata[4+len_blen+len_bdata:]
return flag_result,icmd,bmsg,bdata
# ------------------ function for weaving port end ------------------------
class WeavingClient(threading.Thread):
def __init__(self, addr, recv_timeout=10, reconnection_delay=10, client_id='1'):
threading.Thread.__init__(self, name="WeavingClient" + client_id)
self.addr = addr
self.recv_timeout = recv_timeout
self.reconnection_delay = reconnection_delay
self.host, self.port = addr.split(':')
self.port = int(self.port)
self.all_bdata = b''
self.wcmd_dict = {} # wcmd is weaving cmd, the difference in app cmd
self.on_connect = None
def reg_wcmd(self,cmd,func):
self.wcmd_dict[cmd] = func
def run(self):
self.do_connect()
while True:
try:
wclog('recving data...')
self.recv_data()
except OSError:
traceback.print_exc()
wclog('{} connect error, reconnection after {}s'.format(self.addr,self.reconnection_delay))
time.sleep(self.reconnection_delay)
self.sck = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.do_connect()
except Exception as e:
traceback.print_exc()
wclog('other error, reconnection after {}s'.format(self.reconnection_delay))
time.sleep(self.reconnection_delay)
self.do_connect()
def do_connect(self):
while True:
try:
self.sck = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sck.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.sck.settimeout(self.recv_timeout)
wclog('try to connect {}'.format(self.addr))
self.sck.connect((self.host, self.port))
wclog('client start connect to {}'.format(self.addr))
if(callable(self.on_connect)):
self.on_connect()
break
except ConnectionRefusedError:
wclog('{} refused or not started, reconnection after {}s'.format(self.reconnection_delay, self.addr))
time.sleep(self.reconnection_delay)
except Exception as e:
traceback.print_exc()
wclog('do connect error: {}'.format(str(e)))
wclog('reconnection after {}s'.format(self.reconnection_delay))
time.sleep(self.reconnection_delay)
def send_data(self,cmd,bdata):
bdata = weaving_pack(cmd,bdata)
self.sck.send(bdata)
def recv_data(self):
try:
data = self.sck.recv(1024)
if data:
wclog('recv data:{}'.format(data))
self.all_bdata += data
flag_need_proc = True
while(flag_need_proc):
flag_need_proc = self.proc_data()
else:
wclog('the socket may be closed, reconnection after {}s'.format(self.reconnection_delay))
time.sleep(self.reconnection_delay)
self.do_connect()
except socket.timeout:
wclog('recv timeout, reconnection after {}s'.format(self.reconnection_delay))
time.sleep(self.reconnection_delay)
self.do_connect()
except Exception as e:
traceback.print_exc()
self.sck = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.do_connect()
def proc_data(self):
wclog('into proc_data')
wclog('all_bdata is: {}'.format(self.all_bdata))
flag_result, icmd, bmsg, self.all_bdata = weaving_unpack(self.all_bdata)
if(flag_result):
wclog('proc_data, flag_result is True')
func = self.wcmd_dict.get(icmd,None)
if(callable(func)):
threading.Thread(target=func,args=(bmsg,)).start()
return True
else:
return False
Loading…
Cancel
Save