python制作websocket服务器实例分享

一、开始的话

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

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

二、代码

  需求:在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('\r\n\r\n', 1)
  for line in header.split('\r\n')[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 Protocols\r\n" \
            "Upgrade:websocket\r\n" \
            "Connection: Upgrade\r\n" \
            "Sec-WebSocket-Accept: {1}\r\n" \
            "WebSocket-Origin: {2}\r\n" \
            "WebSocket-Location: ws://{3}/\r\n\r\n"

  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 ('\r\n\r\nWebsocket 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给服务端,所以可以看不同类型,不同机器上的日志,

页面代码如下:

<!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>

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

时间: 2016-11-18

Python内置的HTTP协议服务器SimpleHTTPServer使用指南

首先确保装了Python,我装的是2.x版本,对了,我的操作系统是WIN7,其实对于Python来说,什么操作系统并不重要.Python内置了一个简单的HTTP服务器,只需要在命令行下面敲一行命令,一个HTTP服务器就起来了: python -m SimpleHTTPServer 80 后面的80端口是可选的,不填会采用缺省端口8000.注意,这会将当前所在的文件夹设置为默认的Web目录,试着在浏览器敲入本机地址: http://localhost:80 如果当前文件夹有index.html文件

Python使用Paramiko模块编写脚本进行远程服务器操作

简介: paramiko是python(2.2或更高)的模块,遵循SSH2协议实现了安全(加密和认证)连接远程机器. 安装所需软件包: http://ftp.dlitz.net/pub/dlitz/crypto/pycrypto/pycrypto-2.5.tar.gz http://www.lag.net/paramiko/download/paramiko-1.7.7.1.tar.gz tar zxvf pycrypto-2.5.tar.gz cd pycrypto-2.5 python se

Python 搭建Web站点之Web服务器与Web框架

之前用 Django 做过一个小的站点,感觉Django太过笨重,于是就准备换一个比较轻量级的 Web 框架来玩玩.Web.py 作者已经挂掉,项目好久没有更新,所以不准备用它.而 Flask 也是一个成熟的轻量级 Web 框架,在 github 上有众多的 Star 和 Fork,文档和扩展也很丰富,值得学习. 学习一个框架最好的方式就是用框架做一个项目,在实战中理解掌握框架.这里我用 Flask 框架,使用 Mysql 数据库做了一个 论坛系统 .麻雀虽小,五脏俱全,论坛效果图如下: 论坛系

使用Python实现简单的服务器功能

socket接口是实际上是操作系统提供的系统调用.socket的使用并不局限于Python语言,你可以用C或者Java来写出同样的socket服务器,而所有语言使用socket的方式都类似(Apache就是使用C实现的服务器) Web框架就是提前写好了服务器.不能跨语言的使用框架.框架的好处在于帮你处理了一些细节,从而实现快速开发,但同时受到python本身性能的限制.我们已经看到,许多成功的网站都是利用动态语言(比如Python, Ruby或者PHP,比如twitter和facebook)快速

Python实现telnet服务器的方法

本文实例讲述了Python实现telnet服务器的方法.分享给大家供大家参考.具体实现方法如下: import threading class myThread(threading.Thread): def __init__(self,conn,add): threading.Thread.__init__(self) self.inputstr = '' self.connection=conn self.address=add def run(self): ii=0 while True:

Linux下将Python的Django项目部署到Apache服务器

这几天花了点时间,将把django开发好的web项目部署到Apache上,参考了官方的一些文档和互联网上的文档,还是花了比较多的时间,这里把配置的过程说一下. 方便有需要的朋友,可以参考,少走弯路! 1. django项目部署环境说明 操作系统 : Red Hat Enterprise Linux Server release 5.3 (Tikanga) x86_64 apache版本 : httpd-2.2.3-22.el5 mod_wsgi版本 : mod_wsgi-3.2-1.el5 fe

使用Python来编写HTTP服务器的超级指南

首先,到底什么是网络服务器? 简而言之,它是在物理服务器上搭建的一个网络连接服务器(networking server),永久地等待客户端发送请求.当服务器收到请求之后,它会生成响应并将 其返回至客户端.客户端与服务器之间的通信,是以HTTP协议进行的.客户端可以是浏览器,也可以是任何支持HTTP协议的软件. 那么,网络服务器的简单实现形式会是怎样的呢?下面是我对此的理解.示例代码使用Python语言实现,不过即使你不懂Python语言,你应该也可以从代码和下面的 解释中理解相关的概念: imp

在阿里云服务器上配置CentOS+Nginx+Python+Flask环境

项目运行环境 阿里云(单核CPU, 1G内存, Ubuntu 14.04 x64 带宽1Mbps), 具体购买和ssh连接阿里云本文不做描述. 实用工具 首先进入阿里云后先要升级下apt-get, 并下载所需软件 sudo apt-get update sudo apt-get install vim git wget tmux 我还会使用zsh和oh-my-zsh来替换bash sudo apt-get install zsh # 终端下打以下命令 wget --no-check-certif

通过Python使用saltstack生成服务器资产清单

SaltStack是一个服务器基础架构集中化管理平台,具备配置管理.远程执行.监控等功能,一般可以理解为简化版的puppet和加强版的func.SaltStack基于Python语言实现,结合轻量级消息队列(ZeroMQ)与Python第三方模块(Pyzmq.PyCrypto.Pyjinjia2.python-msgpack和PyYAML等)构建. 通过部署SaltStack环境,我们可以在成千上万台服务器上做到批量执行命令,根据不同业务特性进行配置集中化管理.分发文件.采集服务器数据.操作系统

python实现批量修改服务器密码的方法

求:机房.线上有多台主机,为了保障安全,需要定期修改密码.若手动修改,费时费力易出错. 程序应该满足如下需求 : 1.在现有的excel密码表格,在最后一个字段后面生成新的密码,另存为一个新的excel密码文件 2.根据新的excel密码文件,更新服务器密码,将更新后的结果保存到另外一个excel文件. a.原始excel文件字段格式,最后一个字段为原始密码 IP USER PORT pwd b.生成新的密码文件字段格式,最后一个字段为更新密码 IP USER PORT pwd pwd20180

利用Python如何批量更新服务器文件

前言 买了个Linux服务器,Centos系统,装了个宝塔搭建了10个网站,比如有时候要在某个文件上加点代码,就要依次去10个文件改动,虽然宝塔是可视化页面操作,不需要用命令,但是也麻烦,虽然还有git的hook方法,但是操作也麻烦,新建个目录的话还得操作一次,所以萌生了一个想法,用Python来批量更新服务器上的文件 序言 在网上搜索了一圈,发现Python有个库叫paramiko可以专门拿来干这个事,具体资料和安装就网上去搜索吧,我就直接上代码了,不到100行,其实还可以精简吧,后面再说了,

Python命令启动Web服务器实例详解

Python命令启动Web服务器实例详解 利用Python自带的包可以建立简单的web服务器.在DOS里cd到准备做服务器根目录的路径下,输入命令: python -m Web服务器模块 [端口号,默认8000] 例如: python -m SimpleHTTPServer 8080 然后就可以在浏览器中输入 http://localhost:端口号/路径 来访问服务器资源. 例如: http://localhost:8080/index.htm(当然index.htm文件得自己创建) 其他机器

python使用pil生成缩略图的方法

本文实例讲述了python使用pil生成缩略图的方法.分享给大家供大家参考.具体分析如下: 这段代码实现python通过pil生成缩略图的功能,会强行将图片大小修改成250x156 from PIL import Image img = Image.open('jb51.jpg') img = img.resize((250, 156), Image.ANTIALIAS) img.save('jb51_small.jpg') 希望本文所述对大家的Python程序设计有所帮助.

python实现从ftp服务器下载文件的方法

本文实例讲述了python实现从ftp服务器下载文件的方法.分享给大家供大家参考.具体实现方法如下: import ftplib ftp = ftblib.FTP("ftp.yourServer.com") ftp.login("username","password") filename = "index.html" ftp.storlines("STOR "+filename,open(filename

python连接远程ftp服务器并列出目录下文件的方法

本文实例讲述了python连接远程ftp服务器并列出目录下文件的方法.分享给大家供大家参考.具体如下: 这段python代码用到了pysftp模块,使用sftp协议,对数据进行加密传输 import pysftp srv = pysftp.Connection(host="your_FTP_server", username="your_username",password="your_password") # Get the directory

详解python脚本自动生成需要文件实例代码

python脚本自动生成需要文件 在工作中我们经常需要通过一个文件写出另外一个文件,然而既然是对应关系肯定可以总结规律让计算机帮我们完成,今天我们就通过一个通用文件生成的python脚本来实现这个功能,将大家从每日重复的劳动中解放! 定义一个函数 def produceBnf(infilename,outfilename): List=[] with open(infilename,'r') as inf: for line in inf.readlines(): List.append(re.

python登录pop3邮件服务器接收邮件的方法

本文实例讲述了python登录pop3邮件服务器接收邮件的方法.分享给大家供大家参考.具体实现方法如下: import poplib, string PopServerName = "mail.yourserver.com" PopServer = poplib.POP3(PopServerName) print PopServer.getwelcome() PopServer.user('yourName') PopServer.pass_('yourPass') r, items,