xml地图|网站地图|网站标签 [设为首页] [加入收藏]
来自 新濠国际登录平台 2020-01-01 11:19 的文章
当前位置: 新濠国际登录平台 > 新濠国际登录平台 > 正文

WebSocket协议是基于TCP的一种新的网络协议,相关

功能:用websocket技术,在运维工具的浏览器上实时显示远程服务器上的日志信息

前言:工作中在验证前端页面展示数据时,接触到websocket这一概念,这里粗略记录下关于websocket的理解和常用方式。

python制作websocket服务器实例分享,pythonwebsocket

一、开始的话

  使用python简单的实现websocket服务器,可以在浏览器上实时显示远程服务器的日志信息。

  之前做了一个web版的发布系统,但没实现在线看日志,每次发布版本后,都需要登录到服务器上查看日志,非常麻烦,为了偷懒,能在页面点几下按钮完成工作,这几天查找了这方面的资料,实现了这个功能,瞬间觉的看日志什么的,太方便了,以后也可以给开发们查日志,再也不用麻烦运维了,废话少说,先看效果吧。

新濠国际登录平台 1

二、代码

  需求:在web上弹出iframe层来实时显示远程服务器的日志,点击stop按钮,停止日志输出,以便查看相关日志,点start按钮,继续输出日志,点close按钮,关闭iframe层。

  在实现这功能前,google了一些资料,发现很多只能在web上显示本地的日志,不能看远程服务器的日志,能看远程日志的是引用了其他框架(例如bottle,tornado)来实现的,而且所有这些都是要重写thread的run方法来实现的,由于本人技术太菜,不知道怎么改成自己需要的样子,而且我是用django这个web框架的,不想引入其他框架,搞的太复杂,所以用python简单的实现websocket服务器。recv_data方法和send_data是直接引用别人的代码。由于技术问题,代码有点粗糙,不过能实现功能就行,先将就着用吧。

执行下面命令启动django和websocketserver

nohup python manage.py runserver 10.1.12.110 &
nohup python websocketserver.py &

  启动websocket后,接收到请求,起一个线程和客户端握手,然后根据客户端发送的ip和type,去数据库查找对应的日志路径,用paramiko模块ssh登录到远程服务器上tail查看日志,再推送给浏览器,服务端完整代码如下:

# coding:utf-8
import os
import struct
import base64
import hashlib
import socket
import threading
import paramiko


def get_ssh(ip, user, pwd):
  try:
    ssh = paramiko.SSHClient()
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    ssh.connect(ip, 22, user, pwd, timeout=15)
    return ssh
  except Exception, e:
    print e
    return "False"


def recv_data(conn):  # 服务器解析浏览器发送的信息
  try:
    all_data = conn.recv(1024)
    if not len(all_data):
      return False
  except:
    pass
  else:
    code_len = ord(all_data[1]) & 127
    if code_len == 126:
      masks = all_data[4:8]
      data = all_data[8:]
    elif code_len == 127:
      masks = all_data[10:14]
      data = all_data[14:]
    else:
      masks = all_data[2:6]
      data = all_data[6:]
    raw_str = ""
    i = 0
    for d in data:
      raw_str += chr(ord(d) ^ ord(masks[i % 4]))
      i += 1
    return raw_str


def send_data(conn, data):  # 服务器处理发送给浏览器的信息
  if data:
    data = str(data)
  else:
    return False
  token = "x81"
  length = len(data)
  if length < 126:
    token += struct.pack("B", length)  # struct为Python中处理二进制数的模块,二进制流为C,或网络流的形式。
  elif length <= 0xFFFF:
    token += struct.pack("!BH", 126, length)
  else:
    token += struct.pack("!BQ", 127, length)
  data = '%s%s' % (token, data)
  conn.send(data)
  return True


def handshake(conn, address, thread_name):
  headers = {}
  shake = conn.recv(1024)
  if not len(shake):
    return False

  print ('%s : Socket start handshaken with %s:%s' % (thread_name, address[0], address[1]))
  header, data = shake.split('rnrn', 1)
  for line in header.split('rn')[1:]:
    key, value = line.split(': ', 1)
    headers[key] = value

  if 'Sec-WebSocket-Key' not in headers:
    print ('%s : This socket is not websocket, client close.' % thread_name)
    conn.close()
    return False

  MAGIC_STRING = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'
  HANDSHAKE_STRING = "HTTP/1.1 101 Switching Protocolsrn" 
            "Upgrade:websocketrn" 
            "Connection: Upgradern" 
            "Sec-WebSocket-Accept: {1}rn" 
            "WebSocket-Origin: {2}rn" 
            "WebSocket-Location: ws://{3}/rnrn"

  sec_key = headers['Sec-WebSocket-Key']
  res_key = base64.b64encode(hashlib.sha1(sec_key + MAGIC_STRING).digest())
  str_handshake = HANDSHAKE_STRING.replace('{1}', res_key).replace('{2}', headers['Origin']).replace('{3}', headers['Host'])
  conn.send(str_handshake)
  print ('%s : Socket handshaken with %s:%s success' % (thread_name, address[0], address[1]))
  print 'Start transmitting data...'
  print '- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -'
  return True


def dojob(conn, address, thread_name):
  handshake(conn, address, thread_name)   # 握手
  conn.setblocking(0)            # 设置socket为非阻塞

  ssh = get_ssh('192.168.1.1', 'root', '123456')  # 连接远程服务器
  ssh_t = ssh.get_transport()
  chan = ssh_t.open_session()
  chan.setblocking(0)  # 设置非阻塞
  chan.exec_command('tail -f /var/log/messages')

  while True:
    clientdata = recv_data(conn)
    if clientdata is not None and 'quit' in clientdata:  # 但浏览器点击stop按钮或close按钮时,断开连接
      print ('%s : Socket close with %s:%s' % (thread_name, address[0], address[1]))
      send_data(conn, 'close connect')
      conn.close()
      break
    while True:
      while chan.recv_ready():
        clientdata1 = recv_data(conn)
        if clientdata1 is not None and 'quit' in clientdata1:
          print ('%s : Socket close with %s:%s' % (thread_name, address[0], address[1]))
          send_data(conn, 'close connect')
          conn.close()
          break
        log_msg = chan.recv(10000).strip()  # 接收日志信息
        print log_msg
        send_data(conn, log_msg)
      if chan.exit_status_ready():
        break
      clientdata2 = recv_data(conn)
      if clientdata2 is not None and 'quit' in clientdata2:
        print ('%s : Socket close with %s:%s' % (thread_name, address[0], address[1]))
        send_data(conn, 'close connect')
        conn.close()
        break
    break


def ws_service():

  index = 1
  sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  sock.bind(("127.0.0.1", 12345))
  sock.listen(100)

  print ('rnrnWebsocket server start, wait for connect!')
  print '- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -'
  while True:
    connection, address = sock.accept()
    thread_name = 'thread_%s' % index
    print ('%s : Connection from %s:%s' % (thread_name, address[0], address[1]))
    t = threading.Thread(target=dojob, args=(connection, address, thread_name))
    t.start()
    index += 1


ws_service()

get_ssh的代码如下:

import paramiko
def get_ssh(ip, user, pwd):
  try:
    ssh = paramiko.SSHClient()
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    ssh.connect(ip, 22, user, pwd, timeout=15)
    return ssh
  except Exception, e:
    print e
    return "False"

打开页面时,自动连接websocket服务器,完成握手,并发送ip和type给服务端,所以可以看不同类型,不同机器上的日志,

新濠国际登录平台 2

 页面代码如下:

<!DOCTYPE html>
<html>
<head>
  <title>WebSocket</title>

  <style>
  #log {
    width: 440px;
    height: 200px;
    border: 1px solid #7F9DB9;
    overflow: auto;
  }
  pre {
    margin: 0 0 0;
    padding: 0;
    border: hidden;
    background-color: #0c0c0c;
    color: #00ff00;
  }
  #btns {
    text-align: right;
  }
  </style>

  <script>
    var socket;
    function init() {
      var host = "ws://127.0.0.1:12345/";

      try {
        socket = new WebSocket(host);
        socket.onopen = function () {
          log('Connected');
        };
        socket.onmessage = function (msg) {
          log(msg.data);
          var obje = document.getElementById("log");  //日志过多时清屏
          var textlength = obje.scrollHeight;
          if (textlength > 10000) {
            obje.innerHTML = '';
          }
        };
        socket.onclose = function () {
          log("Lose Connection!");
          $("#start").attr('disabled', false);
          $("#stop").attr('disabled', true);
        };
        $("#start").attr('disabled', true);
        $("#stop").attr('disabled', false);
      }
      catch (ex) {
        log(ex);
      }
    }
    window.onbeforeunload = function () {
      try {
        socket.send('quit');
        socket.close();
        socket = null;
      }
      catch (ex) {
        log(ex);
      }
    };
    function log(msg) {
      var obje = document.getElementById("log");
      obje.innerHTML += '<pre><code>' + msg + '</code></pre>';
      obje.scrollTop = obje.scrollHeight;  //滚动条显示最新数据
    }
    function stop() {
      try {
        log('Close connection!');
        socket.send('quit');
        socket.close();
        socket = null;
        $("#start").attr('disabled', false);
        $("#stop").attr('disabled', true);
      }
      catch (ex) {
        log(ex);
      }
    }
    function closelayer() {
      try {
        log('Close connection!');
        socket.send('quit');
        socket.close();
        socket = null;
      }
      catch (ex) {
        log(ex);
      }
      var index = parent.layer.getFrameIndex(window.name); //先得到当前iframe层的索引
      parent.layer.close(index); //再执行关闭
    }
  </script>

</head>


<body onload="init()">
  <div >
    <div >
      <div id="log" ></div>
      <br>
    </div>
  </div>
  <div >
    <div >
      <div id="btns">
        <input disabled="disabled" type="button" value="start" id="start" onclick="init()">
        <input disabled="disabled" type="button" value="stop" id="stop" onclick="stop()" >
        <input type="button" value="close" id="close" onclick="closelayer()" >
      </div>
    </div>
  </div>
</body>

</html>

以上就是本文的全部内容了,希望大家能够喜欢

一、开始的话 使用python简单的实现websocket服务器,可以在浏览器上实时显示远程服务器的日...

web socket 接收器:webSocket.py 

一般我们在运维工具部署环境的时候,需要实时展现部署过程中的信息,或者在浏览器中实时显示程序日志给开发人员看。你还在用ajax每隔段时间去获取服务器日志?out了,试试用websocket方式吧

(1)什么是websocket?

相关依赖

我用bottle框架,写了个websocket服务端,浏览器连接到websocket server,再用python subprocess获取远程服务器的日志信息,subprocess,就是用Popen调用shell的shell命令而已,这样可以获取到实时的日志了,然后再send到websocket server中,那连接到websocket server的浏览器,就会实时展现出来了

命名:看起来好像和socket有某种关系,但是根据查询了解到,WebSocket只是借用了这一概念,使用方面,完全两个东西,大概因为Socket早在它之前已经是一个深入人心的概念。

# pip install bottle gevent gevent-websocket argparse

from bottle import request, Bottle, abort
from geventwebsocket import WebSocketError
from gevent.pywsgi import WSGIServer
from flask import request
from geventwebsocket.handler import WebSocketHandler
from bottle import get, post, request
app = Bottle()
users = {}
@app.get('/websocket/<token>/<senduser>')
def handle_websocket(token,senduser):
    wsock = request.environ.get('wsgi.websocket')
    users[token] = wsock
    if not wsock:
        abort(400, 'Expected WebSocket request.')
    while True:
        try:
            message = wsock.receive()
        except WebSocketError:
            breakif message:
try:
                users[senduser].send(message)
           except WebSocketError:
                print u'kill'
server = WSGIServer(("0.0.0.0", 1019), app,handler_class=WebSocketHandler)
server.serve_forever()

用二台服务器来实现这个场景,A服务器是websocket服务端,B服务器是日志端

官方解释:WebSocket协议是基于TCP的一种新的网络协议。它实现了浏览器与服务器全双工(full-duplex)通信——允许服务器主动发送信息给客户端。--百度百科

 

A服务器是我浏览器本机,websocket服务端也是这台机,IP是:192.168.2.222

简单理解:WebSocket是一种为了满足浏览器与服务器端实时数据交互需要而制订的一种新的网络协议。

服务端:logs.py

B服务器是要远程查看日志的服务器,我这里用:192.168.2.224

可以把WebSocket想象成HTTP,同为应用层协议,在与服务器通信过程扮演角色类似。但是WebSocket是基于TCP的应用层协议,只需要一次连接(握手),以后传输数据不需要重新建立连接,可以直接发送数据,这里就区分了和http协议的不同(每次都要重新请求,服务端返回数据后结束)。javascript中常用的ajax技术所做的工作也是完成前端和服务器的数据交互,但是Ajax技术需要客户端发起请求,而WebSocket服务器和客户端可以相互推送信息,更为灵活的支撑业务需要。

新濠国际登录平台,相关依赖:

以下是在A服务器的操作(Python2)

(2)前端常用方式?

pip install websocket-client

import subprocess
from websocket import create_connection
ws_server = "ws://172.18.30.19:1010/websocket/<token>/<senduser>" 
ws = create_connection(ws_server) command='sshpass -p 123456 ssh 192.168.20.200 -p 32776 -o StrictHostKeychecking=no "tail -f /root/tomcat-8.0/logs/catalina.out"' 
popen=subprocess.Popen(command,stdout=subprocess.PIPE,stderr=subprocess.PIPE,shell=True) 

while True: 
    line=popen.stdout.readline().strip() 
    ws.send(line)

安装:

前端比较常用的是在javascript中使用WebSocket,建立与服务端WebSocket服务的通信,从而请求服务端或者监听服务端推送数据消息,达到实时数据交互的需要。

应用前端:logs.html

    pip install bottle

一个参考网上使用python+bottle+javascript的例子

<!DOCTYPE html>
<html>
<head>
    <title>LOG+</title>
    <style>
        html, body {
            font: normal 0.9em arial, helvetica;
        }
        #log {
            width: 440px;
            height: 200px;
            border: 1px solid #7F9DB9;
            overflow: auto;
        }
        #msg {
            width: 330px;
        }
    </style>
    <script>
        var socket;
        function init() {
            var host = "ws://172.18.30.19:1010/websocket/<token>/<senduser>";
            try {
                socket = new WebSocket(host);
                socket.onopen = function (msg) {
                    log('Connected');
                };
                socket.onmessage = function (msg) {
                    log(msg.data);
                };
                socket.onclose = function (msg) {
                    log("Lose Connection!");
                };

    pip install websocket-client

前端:

     socket.onerror = function(msg) {
      log("websocket error!");
                };

本文由新濠国际登录平台发布于新濠国际登录平台,转载请注明出处:WebSocket协议是基于TCP的一种新的网络协议,相关

关键词: