客户端代码:
# -*-coding:utf8-*-
import threading
import time
from autobahn.asyncio.websocket import WebSocketClientProtocol
from autobahn.asyncio.websocket import WebSocketClientFactory
import asyncio
class BaseSipClientProtocol(WebSocketClientProtocol):
KEEPALIVE_INTERVAL = 5
def check_keepalive(self):
last_interval = time.time() - self.last_ping_time
if last_interval > 2 * self.KEEPALIVE_INTERVAL:
# drop connection
self.dropConnection(abort=True)
else:
# reschedule next check
self.schedule_keepalive()
def schedule_keepalive(self):
""" Store the future in the class to cancel it later. """
try:
import asyncio
except ImportError:
# Trollius >= 0.3 was renamed
import trollius as asyncio
loop = asyncio.get_event_loop()
self.keepalive_fut = loop.call_later(self.KEEPALIVE_INTERVAL,
self.check_keepalive)
def onConnect(self, response):
print("Server connected: {0}".format(response.peer))
# save connection to server handle on factory
self.factory.saveConnectionToServer(self)
self.onConnectToServer(response.peer)
def onOpen(self):
""" Start scheduling the keepalive check. """
self.last_ping_time = time.time()
self.schedule_keepalive()
def onPing(self, payload):
""" Respond to the ping request. """
self.last_ping_time = time.time()
self.sendPong(payload)
print('Ping == ', payload)
def connection_lost(self, exc):
""" Cancel the scheduled future. """
self.keepalive_fut.cancel()
try:
import asyncio
except ImportError:
# Trollius >= 0.3 was renamed
import trollius as asyncio
loop = asyncio.get_event_loop()
loop.stop()
def onMessage(self, payload, isBinary):
# 做一些处理,peer mapping msg
self.onMsgReceived(self.peer, payload, isBinary)
def onClose(self, wasClean, code, reason):
print("WebSocket connection closed: {0}".format(reason))
# remove connection to server
self.factory.delConnectionToServer()
self.onDisConnectFromServer(wasClean, code, reason)
# client连接上server的时候回调
def onConnectToServer(self, peer):
pass
# client断开与server的连接的时候回调
def onDisConnectFromServer(self, wasClean, code, reason):
pass
# 收到Msg消息时回调
def onMsgReceived(self, peer, data, isBinary):
print('received {0} from {1}'.format(data, peer))
# 保存一个与server连接的句柄
class BaseSipClientFactory(WebSocketClientFactory):
_connectionToServer = None
# save connection to server
def saveConnectionToServer(self, connectedHandle):
self._connectionToServer = connectedHandle
# remove connection to server
def delConnectionToServer(self):
self._connectionToServer = None
def getConnectionToServer(self):
return self._connectionToServer
# support sendMsg to client
def sendMsg(self, data):
if self._connectionToServer is not None:
if isinstance(data,bytes):
self._connectionToServer.sendMessage(data, True)
else:
self._connectionToServer.sendMessage(data.encode('utf-8'))
else:
raise Exception('与server的连接不存在')
if __name__ == '__main__':
try:
import asyncio
except ImportError:
# Trollius >= 0.3 was renamed
import trollius as asyncio
factory = BaseSipClientFactory(u"ws://192.168.88.3:9009")
factory.protocol = BaseSipClientProtocol
loop = asyncio.get_event_loop()
while True:
fut = loop.create_connection(factory, '192.168.88.3', 9009)
try:
transport, protocol = loop.run_until_complete(
asyncio.wait_for(fut, 5))
loop.run_forever()
except asyncio.TimeoutError:
print('TimeoutError')
continue
except OSError as err:
print('OSError == ' + str(err))
# a little timeout before trying again
loop.run_until_complete(asyncio.sleep(5))
loop.close()
服务端代码:
# -*-coding:utf8-*-
from autobahn.asyncio.websocket import WebSocketServerFactory
from autobahn.asyncio.websocket import WebSocketServerProtocol
class BaseSipServerProtocol(WebSocketServerProtocol):
def onConnect(self, request):
print("Client connecting: {0}".format(request.peer))
# save connection in factory _connectionSets
self.factory.addConnection(request.peer, self)
self.onClientConnected(request.peer)
def onOpen(self):
print("WebSocket connection open.")
def onMessage(self, payload, isBinary):
# 做一些处理,peer mapping msg
self.onMsgReceived(self.peer, payload, isBinary)
def onClose(self, wasClean, code, reason):
print("WebSocket connection closed: {0}".format(reason))
# remove connection from factory _connectionSets
self.factory.removeConnection(self)
self.onClientLostConnected(wasClean, code, reason)
# client连接上来的时候回调
def onClientConnected(self, peer):
pass
# client断开连接的时候回调
def onClientLostConnected(self, wasClean, code, reason):
pass
# 收到Msg消息时回调
def onMsgReceived(self, peer, data, isBinary):
print('received {0} from {1}'.format(data, peer))
class BaseSipServerFactory(WebSocketServerFactory):
_connectionSets = dict()
# save connection
def addConnection(self, peer, connectedHandle):
self._connectionSets.setdefault(peer, connectedHandle)
# remove connection
def removeConnection(self, connectedHandle):
removePeer = None
for k, v in self._connectionSets.items():
if v == connectedHandle:
removePeer = k
break
if removePeer is not None:
del self._connectionSets[removePeer]
def getConnectionByPeer(self, peer):
return self._connectionSets.get(peer)
def getConnections(self):
return self._connectionSets
# support sendMsg to client
def sendMsg(self, peer, data):
connectedHandle = self.getConnectionByPeer(peer)
if connectedHandle is not None:
if isinstance(data,bytes):
connectedHandle.sendMessage(data, True)
else:
connectedHandle.sendMessage(data.encode('utf-8'))
else:
raise Exception('peer的连接不存在')
启动Server:
class CommunicationTool:
Server = 1
Client = 0
def __init__(self):
self.isAutoReconnect = False
# 设置创建的Server还是Client
def setFlag(self, flag):
self.flag = flag
# 创建server
def createServer(self, addr, port):
# 先判断创建的类型
if self._isServer():
if isinstance(addr, str) and isinstance(port, int):
self.addr = addr
self.port = port
else:
raise Exception('createServer的参数类型有误')
else:
raise Exception('不支持client类型执行此方法')
def startListen(self):
# 先判断必填参数是否都填了
if self._isServer():
if self.serverProtocol is None:
raise Exception('未设置protocol')
if self.serverFactory is None:
raise Exception('未设置factory')
if self.addr is None or self.port is None:
raise Exception('未设置createServer')
else:
raise Exception('未设置flag或不支持此方法')
# 开启服务器,应该在子线程中一直运行
# 调用父类的startListen方法,将数据传入
factory = self.serverFactory
factory.protocol = self.serverProtocol
if self.isAutoReconnect: # set auto-reconnection
factory.setProtocolOptions(autoPingInterval=5, autoPingTimeout=2)
loop = asyncio.get_event_loop()
coro = loop.create_server(factory, self.addr, self.port)
server = loop.run_until_complete(coro)
serverThread = threading.Thread(target=self._run, args=(loop, server), name='serverThread')
serverThread.start()
def _run(self, loop, server):
try:
loop.run_forever()
except KeyboardInterrupt:
pass
finally:
server.close()
loop.close()
# 设置是否自动断线重连
def setAutoReconnect(self, isAutoReconnect):
if isinstance(isAutoReconnect, bool):
self.isAutoReconnect = isAutoReconnect
else:
raise Exception('参数类型错误')
def setServerProtocol(self, protocol):
if self._isServer():
self.serverProtocol = protocol
else:
raise Exception('Client类型不能调用此方法')
def setServerFactory(self, factory):
if self._isServer():
self.serverFactory = factory
else:
raise Exception('Client类型不能调用此方法')
def _isServer(self):
if self.flag == self.Server:
return True
if self.flag == self.Client:
return False
else:
raise Exception('未设置flag')
if __name__ == '__main__':
cTool = CommunicationTool() # 传入webSocket的地址
cTool.setFlag(CommunicationTool.Server) # 设置类型
cTool.setServerProtocol(BaseSipServerProtocol)
factory = BaseSipServerFactory(u"ws://127.0.0.1:9009")
cTool.setServerFactory(factory)
factory.setProtocolOptions(autoPingInterval=5)
cTool.setAutoReconnect(True) # 设置是否自动断线重连
cTool.createServer('0.0.0.0', 9009) # 创建server
cTool.startListen() # 开启server监听