arklearn 发表于 2020-7-21 15:55

使用Bottle实现websocket和http同端口复用

本帖最后由 arklearn 于 2020-7-22 08:16 编辑

因为工作时候,有需求,同一个端口去接收websocket数据和http请求。
这个需求让我愁得掉了好些头发,没有办法硬着头皮去查资料。
一开始一发狠,用socket来做,反正http和websocket实际上也是一种socket,拼了。
后面发现脑袋大了,这是一个无底洞啊,时间有限,不符合python开发。pyhton里有那多框架,完全不用再造轮子。
突然,Bottle框架出现在我的眼前,忽如一夜春风来,千树万树梨花开,哈哈!!
bottle框架只是搭起了一个架子,实际websocket 还是用了gevent,这个用来解决websocket的。


from gevent.pywsgi import WSGIServer
from geventwebsocket import WebSocketError
from geventwebsocket.handler import WebSocketHandler

部分代码,附件里还加了线程:
'''
Bottle服务,绑定websocket和http服务
'''

class MyBottleServer(Bottle):
    def __init__(self, ip="127.0.0.1", port=8737):
      Bottle.__init__(self)

      self.ip = ip
      self.port = port

    def __del__(self):
      try:
            if (self.server != None):
                self.server.close_server()
      except:
            pass

    def start_server(self):
      self.server = WSGIServer((self.ip, self.port), self, handler_class=WebSocketHandler)
      self.server.serve_forever()

    def close_server(self):
      if (self.server != None):
            self.server.close()
            self.server = None

    def register_websocket_server(self):
      @self.route('/wspost')
      def handle_websocket():
            wsock = request.environ.get('wsgi.websocket')
            if not wsock:
                abort(400, '此功能只能处理websocket')
            message = ""
            while True:
                try:
                  if wsock.closed:
                        break
                  message = wsock.receive()

                  result = {
                        "flag": False,
                        "msg": ""
                  }
                  if message == None or message.strip() == "":
                        msg = u"获取websocket消息失败"
                        result["msg"] = msg
                        break
                  
                  ### 处理其他业务

                  if wsock.closed != True:
                        wsock.close()
                  break

                except WebSocketError, ex:
                  logging.error(u"WebSocket异常信息")
                  logging.exception(ex)
                  # 如果异常报错,则断开连接
                  break

    def register_http_server(self):
      @self.route('/')
      def index():
            return template('<b>Hello {{name}}</b>!', name="xx")

      @self.route('/datapost', method="POST")
      def do_printform():
            response.headers['Access-Control-Allow-Origin'] = '*'
            response.headers['Access-Control-Allow-Methods'] = 'GET,POST,PUT,OPTIONS'
            allow_headers = 'Referer, Accept, Origin, User-Agent'
            response.headers[
                'Access-Control-Allow-Headers'] = "Content-Type,Content-Length, Authorization, Accept,X-Requested-With"
            response.content_type = "application/javascript; charset=utf-8"

            message = request.params.get("message")
            if message is None:
                message = ""
            try:
                message = urllib.unquote(message);
            except Exception, ex:
                pass

            ##处理单据业务

            time.sleep(5)

    def register_error(self):
      @self.error(404)
      def error404(error):
            return u'404'

    def response_header(self):

      # set cross headers
      headers = {'Content-type': 'application/json'}
      headers['Access-Control-Allow-Origin'] = '*'
      headers['Access-Control-Allow-Methods'] = 'GET,POST,PUT,OPTIONS'
      allow_headers = 'Referer, Accept, Origin, User-Agent'
      headers['Access-Control-Allow-Headers'] = allow_headers

我把代码上传到附件里,去除工作所用的业务逻辑,只留下框架的实现,希望能给大家带来思路。

因为工作时间的关系,没有优化,感觉后面可以去掉bottle框架,只使用gevent框架。
页: [1]
查看完整版本: 使用Bottle实现websocket和http同端口复用