Giter VIP home page Giter VIP logo

blog's People

Contributors

bieberg0n avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

blog's Issues

江南小碧的C#教程:2、输入和输出

输出

System库里的Console.WriteLine()函数,在括号中加入字符串,就可以向终端输出指定的文字。比如上一篇中的“Hello world”。
Console.WriteLine()函数也可以通过大括号来接受多个字符串:

using System;

class HelloWorld {
    static void Main() {
        Console.WriteLine("{0} {1}, {0} {2}.", "too", "young", "simple");
    }
}

输出:

too young, too simple.

Console.WriteLine()也可以打印整数,或者计算结果:

using System;

class HelloWorld {
    static void Main() {
        Console.WriteLine(2 * 3 + 4);
        Console.WriteLine("1 + 2 = {0}", 1 + 2);
    }
}

输出:

10
1 + 2 = 3

输入

Console.ReadLine()函数的功能相反,可以让用户输入字符串,并存放到一个变量里。比如输入用户的名字:

using System;

class HelloWorld {
    static void Main() {
        Console.Write("Enter your name:");
        var Name = Console.ReadLine();
        Console.WriteLine("My name is {0}.", Name);
    }
}

其中Console.Write()功能与Console.WriteLine()接近,但它不会自动在字符串后面添加“/n”,即输出不会自动换行。
输出:

Enter your name:江南小碧
My name is 江南小碧.

江南小碧的C#教程:5、函数/递归/委托/匿名函数(Lambda)

函数

我们以自定义一个求绝对值的abs函数为例:

using static System.Console;

class TestAbs {
    static int abs(int x) {
        if (x >= 0) {
            return x;
        } else {
            return -x;
        }
    }

    static void Main() {
        var a = -100;
        WriteLine(abs(a));
    }
}

输出100。

递归

再来个经典的递归求斐波那契的函数:

using static System.Console;

class TestFib {
    static int Fib(int x) {
        if (x == 1) {
            return 0;
        } else if (x == 2) {
            return 1;
        } else {
            return Fib(x-1) + Fib(x-2);
        }
    }

    static void Main() {
        WriteLine(Fib(10));
    }
}

委托

委托类似于C++的函数指针,通过它可以方便地把一个方法塞到另一个方法的参数中。
参见[C#] 委托与事件(1)
另附一个Python的map函数的C#类似实现:

using static System.Console;

class Test {
    delegate void del(int i);

    static void map(del func, int[] i) {
        foreach (int j in i) {
            func(j);
        }
    }

    static void Main() {
        // del myDelegate = x => x * x;
        // WriteLine(myDelegate(5));
        int[] i = {1,2,3};
        map(WriteLine, i);
    }
}

输出

1
2
3

匿名函数

Lambda简单用法参见微软官方教程Lambda 表达式(C# 编程指南)

在上面代码的基础上,通过匿名函数快速对数组中的数进行平方:

using static System.Console;

class Test {
    delegate int del(int i);

    static void map(del func, int[] i) {
        foreach (int j in i) {
            WriteLine(func(j));
        }
    }

    static void Main() {
        del myDelegate = x => x * x;
        int[] i = {1,2,3};
        map(myDelegate, i);
    }
}

江南小碧的C#教程:3、数据类型与字符串编码

数据类型

无脑贴代码,展示一些常见的数据类型:

using System;

class HelloWorld {
    static void Main() {
        Console.WriteLine("整数:{0}", 233);
        Console.WriteLine("浮点数:{0}", 233.33);
        Console.WriteLine("字符串:{0}", "Niconi");
        Console.WriteLine("布尔值:{0}, {1}", true, false);
        Console.WriteLine("比较:{0}, {1}, {2}", 1 < 2, (2 > 3) && (3 < 4), (4 > 5) || (5 < 6));
        Console.WriteLine("空值:null", null); //空值不能被字符串格式化
        const double PI = 3.14;
        Console.WriteLine("常量:{0}", PI);
    }
}

输出:

整数:233
浮点数:233.33
字符串:Niconi
布尔值:True, False
比较:True, False, True
空值:null
常量:3.14

字符串编码

C#默认使用Unicode编码。
把字符串编码成二进制,比如UTF8:

using System;
using System.Text;

class HelloWorld {
    static void Main() {
        var str = "测试";
        byte[] str_bytes = Encoding.UTF8.GetBytes(str);
        // 转回String
        var str2 = Encoding.UTF8.GetString(str_bytes);
        Console.WriteLine(str2);
    }
}

Erlang 各种 Socket 服务器 Demo

TCP Echo server(只接收一次连接):

-module(echo).
-export([main/1, start_serv/0]).


start_serv() ->
    {ok, Listen} = gen_tcp:listen(2345, [binary, {reuseaddr, true}]),
    {ok, Socket} = gen_tcp:accept(Listen),
    loop(Socket),
    gen_tcp:close(Listen).


loop(Socket) ->
    receive
        {tcp, Socket, Bin} ->
            io:format("~p~n", [Bin]),
            ok = gen_tcp:send(Socket, Bin),
            loop(Socket);
        {tcp_closed, Socket} ->
            io:format("closed~n")
    end.


main(_) ->
    start_serv().

TCP Echo server(接受多次连接,处理完一个连接后才能处理第二个连接):

-module(echo).
-compile(export_all).

start_serv() ->
    {ok, Listen} = gen_tcp:listen(2345, [binary, {reuseaddr, true}]),
    tcp_listen(Listen).


tcp_listen(Listen) ->
    {ok, Socket} = gen_tcp:accept(Listen),
    handle_loop(Socket),
    tcp_listen(Listen).


handle_loop(Socket) ->
    receive
        {tcp, Socket, Bin} ->
            io:format("~p~n", [Bin]),
            ok = gen_tcp:send(Socket, Bin),
            handle_loop(Socket);
        {tcp_closed, Socket} ->
            io:format("closed~n")
    end.


main(_) ->
    start_serv().

TCP Echo server(并发型,可同时处理多条连接):

-module(echo).
-compile(export_all).

start_serv() ->
    {ok, Listen} = gen_tcp:listen(2345, [binary, {reuseaddr, true}]),
    tcp_listen(Listen).


tcp_listen(Listen) ->
    {ok, Socket} = gen_tcp:accept(Listen),
    spawn(fun() -> tcp_listen(Listen) end),
    handle_loop(Socket).


handle_loop(Socket) ->
    receive
        {tcp, Socket, Bin} ->
            io:format("~p~n", [Bin]),
            ok = gen_tcp:send(Socket, Bin),
            handle_loop(Socket);
        {tcp_closed, Socket} ->
            io:format("closed~n")
    end.


main(_) ->
    start_serv().

TCP Echo server(半阻塞):

-module(echo).
-compile(export_all).

start_serv() ->
    {ok, Listen} = gen_tcp:listen(2345, [binary,
                                         {active, once},
                                         {reuseaddr, true}]),
    tcp_listen(Listen).


tcp_listen(Listen) ->
    {ok, Socket} = gen_tcp:accept(Listen),
    spawn(fun() -> tcp_listen(Listen) end),
    handle_loop(Socket).


handle_loop(Socket) ->
    inet:setopts(Socket, [{active, once}]),
    receive
        {tcp, Socket, Bin} ->
            io:format("~p~n", [Bin]),
            ok = gen_tcp:send(Socket, Bin),
            handle_loop(Socket);
        {tcp_closed, Socket} ->
            io:format("closed~n")
    end.


main(_) ->
    start_serv().

UDP Echo server:

-module(echo).
-compile(export_all).

server() ->
    {ok, Socket} = gen_udp:open(2345, [binary]),
    loop(Socket).


loop(Socket) ->
    receive
        {udp, Socket, Host, Port, Bin} ->
            gen_udp:send(Socket, Host, Port, Bin),
            loop(Socket)
    end.

未完待续

快速上手一个语言的学习路线(Go语言描述):二

第二章:简单字符串处理,函数


1 字符串处理

包括查找、替换、正则等内容。

字符串操作参见:strings — 字符串操作
正则参见:正则处理

2 函数

函数的定义,闭包,递归等内容。

3 练习:递归求阶乘,闭包函数打印斐波那契数列

阶乘:

package main

import "fmt"

func _f(n int, result int) int {
	if n == 1 {
		return result
	} else {
		return _f(n-1, result*n)
	}
}

func f(n int) int {
	return _f(n, 1)
}

func main() {
	fmt.Println(f(6))
}

斐波那契:

package main

import "fmt"

func nextNum() func() int {
	i, j := 0, 1
	return func() int {
		i, j = j, i+j
		return i
	}
}

func main() {
	nextNumFunc := nextNum()
	for i := 0; i < 10; i++ {
		fmt.Println(nextNumFunc())
	}
}

4 异常、错误处理

网易云音乐登录API(2016.04) Python3版

目前网上大多数提供的API均来自网易云音乐新版WebAPI分析现已失效.新API在此帖的基础上增加了MD5加密.

以下为可以登录的代码(Python3首先需要安装PyCrypto模块:sudo pip3 install PyCrypto)

#filename: api.py
import requests
import json
import os
import base64
import binascii
import hashlib
from Crypto.Cipher import AES

def aesEncrypt(text, secKey):
    pad = 16 - len(text) % 16
    text = text + pad * chr(pad)
    encryptor = AES.new(secKey, 2, '0102030405060708')
    ciphertext = encryptor.encrypt(text)
    ciphertext = base64.b64encode(ciphertext)
    return ciphertext.decode()


def rsaEncrypt(text, pubKey, modulus):
    text = text[::-1].encode()
    rs = int(binascii.hexlify(text), 16)**int(pubKey, 16) % int(modulus, 16)
    return format(rs, 'x').zfill(256)


def createSecretKey(size):
    return ''.join( [ hex(x)[2:] for x in os.urandom(size) ] )[0:16]


def login(username,password):
    url = 'http://music.163.com/weapi/login/'
    headers = {
        'Cookie': 'appver=2.7.1;',
        'Referer': 'http://music.163.com/'
    }
    text = {
        'username': username,
        'password': hashlib.md5(password.encode()).hexdigest(),
        'rememberLogin': 'true'
    }
    modulus = '00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7'
    nonce = '0CoJUm6Qyw8W8jud'
    pubKey = '010001'
    text = json.dumps(text)
    secKey = createSecretKey(16)
    encText = aesEncrypt(aesEncrypt(text, nonce), secKey)
    encSecKey = rsaEncrypt(secKey, pubKey, modulus)
    data = {
        'params': encText,
        'encSecKey': encSecKey
    }
    s = requests.session()
    r = s.post(url, headers=headers, data=data)
    cookies = dict(r.cookies)
    return cookies

调用方式:

import api
cookies = api.login('[email protected]','xxxxxxx')

其他API见网易云音乐API分析
网易云音乐api整理(神坑慎入)
网易云音乐常用API浅析

论如何用Python实现反向代理1024

现在实现反向代理主要都是使用Nginx,google一下用Python实现的版本,多数都是靠Flask+requests.这样实现,too young.遇到post请求怎么办?

下面示范一下如何用无脑tcp转发实现反向代理,实例网站为1024,基于Python3.

首先,开一个tcp server服务器,监听1024端口:

import socket
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(('0.0.0.0', 1024))
s.listen(1500)

然后,接受一个浏览器发来的连接,无脑接收http请求包:

while 1:
  conn ,addr = s.accept()
  headers = ''
  while 1:
    buf = conn.recv(2048).decode('utf-8')
    headers += buf
    if len(buf) < 2048:
      break

修改一下headers,把目标host(127.0.0.1:1024)改成1024的域名,关闭长连接和压缩,方便修改服务器返回的网页:

headers = headers.replace('127.0.0.1:1024', 't66y.com')\
                 .replace('keep-alive', 'close')\
                 .replace('gzip','')

新开一个tcp,连接1024,发送http请求:

s1 = socket.socket()
s1.connect(('t66y.com', 80))
s1.sendall(headers.encode())

接收网页:

while 1:
  try:
    buf = s1.recv(1024*8)
  except socket.timeout as e:
    print(e)
    break
  resp += buf
  if not buf or\
    buf.startswith(b'WebSocket') and buf.endswith(b'\r\n\r\n'):
    break

修改网页内容,替换host为本机:

resp = resp.replace(b'Content-Encoding: gzip\r\n', b'')\
           .replace(b'Transfer-Encoding: chunked\r\n', b'')\
           .replace(b't66y.com', b'bjgong.tk:1024')

最后,把网页返回给浏览器:

conn.sendall(resp)
conn.close()

代码跑起来后,浏览器打开 http://127.0.0.1:1024/index.php ,呈现出来的就是1024的主页,excited!
代码全文如下:

import socket

def main():
    s = socket.socket()
    s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    s.bind(('0.0.0.0', 1024))
    s.listen(1500)
    while 1:
        conn, addr = s.accept()
        print(addr)
        headers = ''
        while 1:
            buf = conn.recv(2048).decode('utf-8')
            headers += buf
            if len(buf) < 2048:
                break

        headers = headers.replace('127.0.0.1:1024', 't66y.com')\
                         .replace('keep-alive', 'close')\
                         .replace('gzip','')
        print(headers)
        s1 = socket.socket()
        s1.connect(('t66y.com', 80))
        s1.sendall(headers.encode())

        resp = b''
        while 1:
            try:
                buf = s1.recv(1024*8)
            except socket.timeout as e:
                print(e)
                break

            resp += buf
            if not buf or\
               buf.startswith(b'WebSocket') and buf.endswith(b'\r\n\r\n'):
                break

        resp = resp.replace(b'Content-Encoding: gzip\r\n', b'')\
                   .replace(b't66y.com', b'bjgong.tk:1024')
        print('send to', addr)
        conn.sendall(resp)
        conn.close()


main()

这个简陋的反向代理不支持https的网站,性能也不好,有待优化.自己在家示范时请把1024的域名(t66y.com)改成其他网站,不然是上不去的2333
想挂到vps上的话改127.0.0.1为你的域名或ip(没有域名的话)就行了.

EOF

<西厢计划>研究小结

西厢计划第一季通过tcp包欺骗的方式穿透gfw,原理见:“西厢计划”原理小解.这种级别的的漏洞难以修补,所以本人猜测gfw因此才开始部署封ip方式的系统.

第二季主要为单向代理.
前两季内容涉及到的技术难度较高,像手动实现tcp三次握手,即使本人也难以用Python重新造轮子.

第三季主要靠构造畸形http请求包瞒过关键词检测.本人也发现了少数可穿透的构造方式,见
关于http请求中LF/CRLF作为分割符对gfw的关键词检测的影响
通过魔改http报文逃过gfw关键词检测

根据其http检测漏洞不会百分百触发可猜测,此系统修补漏洞纯靠添加节点,再在新节点上使用修补过的模块,旧节点不下线不更新.

总体来说,像传统未加密http,可以走直线穿透路线,而让被封的https再走代理,会有更好的速度.但按照现在的发展趋势,走代理仍然为最便捷的出墙方式.

Ubuntu 12.04 PyQt5 安装指南

#1 Python3.5

sudo add-apt-repository ppa:fkrull/deadsnakes
sudo apt-get update
sudo apt-get install python3.5

#2 Qt5

wget http://mirror.bit.edu.cn/qtproject/official_releases/qt/5.5/5.5.1/qt-opensource-linux-x64-5.5.1.run
chmod a+x qt-opensource-linux-x64-5.5.1.run
sudo ./qt-opensource-linux-x64-5.5.1.run
sudo ln -s /opt/Qt5.5.1/5.5/gcc_64/bin/qmake /usr/bin/

安装完成后配置一下PATH,在当前用户主目录下的.bashrc (or .zshrc)文件中加入:

export QTDIR=/opt/Qt5.5.1/5.5/gcc_64/
export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}${QTDIR}lib
export PATH=${QTDIR}bin:${PATH}                                          
export QT_QPA_PLATFORM_PLUGIN_PATH=${QTDIR}plugins/

#3 SIP

下载:http://www.riverbankcomputing.com/software/sip/download

tar xvf sip-4.16.4.tar.gzcd sip-4.16.4
python3 configure.py 
make
sudo make install

#4 PyQt5

下载:http://www.riverbankcomputing.com/software/pyqt/download5

tar xvf PyQt-gpl-5.3.2.tar.gz
cd PyQt-gpl-5.3.2
python3 configure.py

注意:此命令生成各种Qt模块后,其中的QtWebKitWidgets模块由于Qt4和Qt5的qprinter.h所属模块的调整(Qt4存在于 QtGui中,Qt5将其调整到QtPrintSupport中了),QtWebKitWidgets的Makefile中缺失了对 QtPrintSupport的头文件目录引用,会导致后面编译PyQt5时无法找到qprinter.h头文件,编译失败(编译过程非常漫长):qprinter.h: No such file or directory
解决方案:在 /opt/Qt5.5.1/5.5/gcc_64/include/QtPositioning/ 和 /opt/Qt5.5.1/5.5/Src/qtlocation/include/QtPositioning/ 以及目录中放置qgeolocation.h文件

wget https://raw.githubusercontent.com/RSATom/Qt/master/qtlocation/src/positioning/qgeolocation.h
sudo cp qgeolocation.h /opt/Qt5.5.1/5.5/gcc_64/include/QtPositioning/
sudo mkdir -p /opt/Qt5.5.1/5.5/Src/qtlocation/include/QtPositioning/
sudo cp qgeolocation.h /opt/Qt5.5.1/5.5/Src/qtlocation/include/QtPositioning/ 

编译

make
sudo make install

安装完成后进入Python3环境验证是否安装成功:

python3
>>> from PyQt5.QtCore import PYQT_VERSION_STR
>>> print(PYQT_VERSION_STR)

写 http 代理服务器遇过的坑

(ps:本文用于交学校素质扩展课作业)


我从大二开始学习关于 http 代理服务器的实现,http 代理服务器(http proxy server)是一个如果你写 tiny 版会很简单,但写成 squid 会很难的东西。

1 原理

要想明白 http 代理就得先明白 http 协议。
http 协议的 request(请求)内容,简单说就是向 web 服务器提交对某个资源的请求,比如“GET /index.html HTTP/1.1”,然后 web 服务器返回资源(比如首页)。
而在浏览器中勾上了 http 代理的选项后,浏览器会向代理服务器发送请求“GET example.com/index.html HTTP/1.1”,即命令代理服务器向 example.com 请求 index.html 资源并把资源转发过来。
参考资料:HTTP 代理原理及实现(一)

2 实现

通过对客户端的请求报文的解析,就能够了解到客户端想要的资源在哪台 web 服务器上,然后将请求报文稍加修改,变成一个普通的 http 协议报文,跟 web 服务器连接,发送报文,并把返回的内容转发给客户端就行了。(对于 https 网站的代理方式不同,这里略过,可见上面参考资料)
参考资料:用python写一个http代(和谐)理

3 坑

  • 坑1:微信朋友圈的图片服务器,对于请求报文中含有 Proxy-Connection 键就拒绝(polipo 就会被它坑到)...
  • 坑2:Win10 的 Edge 浏览器请求报文中 keep-alive 是首字母大写(Keep-alive)...
  • 坑3:http 请求报文中行与行的分割符不一定是“\r\n”,还可以是“\n”...
  • 坑4:如何处理高并发问题(多进程 / 多线程 / 异步)...
  • 坑5:微信朋友圈的图片资源请求 URL 可能是 IPv6 格式的(http://[::ffff:ip]/xxx)...
  • 坑6:待续...

cocos2d-python中文教程:1 Hello World

前言

相信有很多Python党像我一样,在多年的Python生涯中,编出了各种各样改善生活的小程序.突然有一天,我脑海中浮现了一个idea:为什么不用Python写一个游戏呢?

于是乎,我在不存在的网站Google中搜索Python用来写游戏的库,发现了一个知乎问答:为什么针对python的cocos2d教程那么少啊,还有关于cocos2d和pygame的一些疑问?这个回答阐述了比起pygame,用cocos2d-python写游戏的方便性.

但是,Google一搜索,pygame的中文教程一大把,cocos2d-python的中文教程基本为零.
我的心中突然涌现出使命感.我不下地狱,谁下地狱?所以,我作为一个英语四级都没过的人,打开了cocos2d-python英文文档,尽我所能憋出一个中文版,为像我这样的英语渣们谋福利.

(本教程使用Python3作为示范)


本章纯属cocos2d-python的展示,给大家复制代码跑起来爽一把.基础内容等第二章.
对应英文文档:Writing a cocos2d application

1 安装

安装直接用pip安装就很方便了.Linux下:

sudo pip3 install cocos2d

windows的话管理员权限运行cmd然后pip install cocos2d.

2 Hello World

本节内容,展示一段文字.
helloworld
完整代码:

import cocos

#自定义一个层
class HelloWorld(cocos.layer.Layer):
    def __init__(self):
        super( HelloWorld, self ).__init__()

        #新建文字标签用于显示Hello World
        label = cocos.text.Label('Hello, world',
                             #如果要显示中文,需要使用支持中文的字体,比如"微软雅黑"
                             font_name = 'Times New Roman',  
                             font_size=32,
                             #设置锚点为正中间
                             anchor_x='center', anchor_y='center')
        #设置文字标签在层的位置.由于锚点为正中间,即"用手捏"标签的正中间,放到(320,240)的位置
        label.position = 320,240
        #把文字标签添加到层
        self.add( label )


#"导演诞生",即建一个窗口,默认是640*480,不可调整大小
cocos.director.director.init()

#建一个"场景",场景里只有一个hello_layer层,层里已自带文字
main_scene = cocos.scene.Scene( HelloWorld() )
#"导演说Action",让场景工作
cocos.director.director.run(main_scene)

(英文文档不给出完整代码,所以我就自行辛苦调试出来了,带完整注释.)

3 Hello Actions

本节的主要内容是展现"旋转"和"放大缩小".
Hello Actions
完整代码:

import cocos
from cocos.actions import Repeat,Reverse,ScaleBy,RotateBy

#继承了带颜色属性的层类
class HelloWorld(cocos.layer.ColorLayer):
    def __init__(self):
        #层调成蓝色
        super(HelloWorld, self).__init__(64, 64, 224, 255)
        label = cocos.text.Label('Hello, World!',
                                 font_name='Times New Roman',
                                 font_size=32,
                                 anchor_x='center', anchor_y='center')
        label.position = 320,240
        self.add(label)

        #新建一个精灵,在这里是一个小人(英文文档没有给示范图片,所以这个icon.png请自行找个q版小人图片,放在代码同目录下)
        sprite = cocos.sprite.Sprite('icon.png')
        #精灵锚点默认在正中间,只设置位置就好
        sprite.position = 320,240
        #放大三倍,添加到层,z轴设为1,比层更靠前
        sprite.scale = 3
        self.add(sprite, z=1)

        #定义一个动作,即2秒内放大三倍
        scale = ScaleBy(3, duration=2)
        #标签的动作:重复执行放大三倍缩小三倍又放大三倍...Repeat即为重复动作,Reverse为相反动作
        label.do(Repeat(scale + Reverse(scale)))
        #精灵的动作:重复执行缩小三倍放大三倍又缩小三倍...
        sprite.do(Repeat(Reverse(scale) + scale))
        #层的动作:重复执行10秒内360度旋转
        self.do(RotateBy(360, duration=10))


cocos.director.director.init()
main_scene = cocos.scene.Scene( HelloWorld() )             
cocos.director.director.run(main_scene)

4 Handling Events

本节展示键盘鼠标事件.
Handling Events
完整代码:

import cocos
from cocos.director import director
import pyglet

class KeyDisplay(cocos.layer.Layer):

    is_event_handler = True

    def __init__(self):
        super(KeyDisplay,self).__init__()

        self.text = cocos.text.Label('Keys: ', font_size=18, x=100, y=280)
        self.add(self.text)

        self.keys_pressed = set()

    def update_text(self):
        key_names = [pyglet.window.key.symbol_string(k) for k in self.keys_pressed]
        self.text.element.text = 'Keys: ' + ','.join(key_names)

    def on_key_press(self, key, modifiers):
        #按下按键自动触发本方法
        self.keys_pressed.add(key)
        self.update_text()

    def on_key_release(self, key, modifiers):
        #松开按键自动触发本方法
        self.keys_pressed.remove(key)
        self.update_text()


class MouseDisplay(cocos.layer.Layer):

    is_event_handler = True

    def __init__(self):
        super(MouseDisplay, self).__init__()

        self.text = cocos.text.Label('Mouse @', font_size=18,
                                     x=100, y=240)
        self.add(self.text)

    def on_mouse_motion(self, x, y, dx, dy):
        #dx,dy为向量,表示鼠标移动方向
        self.text.element.text = 'Mouse @ {}, {}, {}, {}'.format(x, y, dx, dy)

    def on_mouse_drag(self, x, y, dx, dy, buttons, modifiers):
        self.text.element.text = 'Mouse @ {}, {}, {}, {}'.format(x, y,buttons, modifiers)

    def on_mouse_press(self, x, y, buttons, modifiers):
        #按下鼠标按键不仅更新鼠标位置,还改变标签的位置.这里使用director.get_virtual_coordinates(),用于保证即使窗口缩放过也能正确更新位置,如果直接用x,y会位置错乱,原因不明
        self.text.element.text = 'Mouse @ {}, {}, {}, {}'.format(x, y,buttons, modifiers)
        self.text.element.x, self.text.element.y = director.get_virtual_coordinates(x, y)


#这次创建的窗口带调整大小的功能
director.init(resizable=True)
main_scene = cocos.scene.Scene( KeyDisplay(), MouseDisplay() )
director.run(main_scene)

默认快捷键

一些默认的快捷键:
Ctrl+f:全屏
Ctrl+s:截图
Ctrl+p:暂停
Ctrl+w:开启/关闭以线框方式显示元素的模式
Ctrl+x:在左下角显示fps帧数
Ctrl+i:启动/关闭内嵌的Python解释器
英文文档:Default Handlers

总结

本章给了三种Hello World的姿势让各位先愉悦起来.下章开始放出一些基础姿势...
(我会努力搬运cocos2d-x版中文手册的链接过来,虽然里面的代码是c++,但各位只要对着中文手册,再阅读我放出的Python版代码就行啦哈哈哈)
(不定期更新)

解决DNS污染与劫持之使用特殊DNS端口

os:ubuntu 12.04 LTS

软件:dnsmasq

dns测试:

dig www.facebook.com @8.8.8.8 +short  
37.61.54.158  

在wiki词条域名服务器缓存污染中可以发现37.61.54.158在虚假ip地址中,说明此dns已遭污染。

dig www.facebook.com @208.67.222.222 -p 443  
31.13.79.49  

31.13.79.49为facebook的正确地址。google的dns服务不支持特殊端口查询,但opendns支持,其ip为208.67.222.222,208.67.222.220,支持的特殊端口为443,5353。

在ubuntu中,我们可以用dnsmasq来指定被污染ip用特殊端口查询.

从Ubuntu 12.04开始网络管理器默认开启了dnsmasq,但出于安全的考虑没有开启其缓存功能。这个改动至少在我这里导致了一些问题,比如偶尔出现网速变慢。经过尝试,可以完全禁用该服务,或者设置使用谷歌DNS服务,同时开启dnsmasq的本地缓存(可以大幅提高重复访问网站时的响应速度)。

完全禁用的方法:

sudo vim /etc/NetworkManager/NetworkManager.conf

注释掉里面的dns=dnsmasq
然后重启网络管理器

sudo restart network-manager

重新安装完整dnsmasq:

sudo apt-get install dnsmasq

然后

sudo vi /etc/resolv.conf

确保resolv.conf内容为:

nameserver 127.0.0.1

然后

sudo vim /etc/dnsmasq.conf

直接在文件最后添加:

listen-address=127.0.0.1    
bind-interfaces  
cache-size=100000  
domain-needed  
resolv-file=/etc/resolv.dnsmasq  
server=/facebook.com/208.67.222.222#5353 

其中

server=/facebook.com/208.67.222.222#5353

即可指定访问facebook网站时向opendns的5353端口进行dns请求,以此类推。
这个设置支持泛解析,比如

server=/com/208.67.222.222#5353

即指定所有.com域名。


重启dnsmasq:

sudo service dnsmasq restart

再测试dns:

dig www.facebook.com +short

若返回31.13.79.49或其他不在虚假ip表里的ip即成功。


ps:用命令

ps -fC dnsmasq|more

查阅得知dnsmasq在ubuntu中的dns设置在/var/run/dnsmasq/resolv.conf中。
dnsmasq的日志记录在/var/log/syslog中。


参考链接:
Ubuntu开启dnsmasq缓存并使用谷歌DNS服务

OpenWRT路由器unbound+dnsmasq解决DNS污染与劫持

关于修改 NetworkManager 托管下 dnsmasq 的问题

cocos2d-python中文教程:2 基础概念介绍——导演、场景、层、精灵

本章改编自基础概念介绍——导演、场景、层、精灵
对应英文文档:Basic Concepts


在Cocos2d引擎中,采用节点树形结构来管理游戏对象,一个游戏可以划分为不同的场景,一个场景又可以分为不同的层,一个层又可以拥有任意个可见的游戏节点(即对象,游戏中基本上所有的类都派生于节点类CocosNode)。可以执行do来修改游戏节点的属性,使其移动、旋转、放大、缩小等等。

导演(Director)

每一个时刻都有一个场景在独立运行,通过切换不同的场景来完成一个游戏流程,游戏流程的管理由Director来执行,其基本框架类图如下:
Paste_Image.png
一款游戏好比一部电影,只是游戏具有更强的交互性,不过它们的基本原理是一致的。所以在Cocos2d中把统筹游戏大局的类抽象为导演(Director),Director是整个cocos2d引擎的核心,是整个游戏的导航仪,游戏中的一些常用操作就是由Director来控制的,比如OpenGL的初始化,场景的转换,游戏暂停继续的控制,世界坐标和GL坐标之间的切换,对节点(游戏元素)的控制等,还有一些游戏数据的保存调用,屏幕尺寸的获取等都要由Director类来管理控制的。

因为Director是游戏项目的总导演,会经常调用进行一些控制,所以该Director利用了单件设计模式,也就是项目里取到的director都是同一个。
获取Director的实例:

import cocos
from cocos.director import director

场景(Scene)

Scene场景也是cocos2d中必不可少的元素,游戏中通常我们需要构建不同的场景(至少一个),游戏里关卡、版块的切换也就是一个一个场景的切换,就像在电影中变换舞台和场地一样。
Paste_Image.png
场景的一个重要的作用就是流程控制的作用,我们可以通过Director的一系列方法控制游戏中不同的场景的自由切换。
下面是Director控制场景的常用方法:

run( Scene *scene ) 启动游戏,并运行scene场景。本方法在主程序第一次启动主场景的时候调用。如果已有正在运行的场景则不能调用该方法;会调用push-->startAnimation。
push( Scene *scene ) 将当前运行中的场景暂停并压入到代码执行场景栈中,再将传入的scene设置为当前运行场景,只有存在正在运行的场景时才调用该方法;
replace( Scene *scene ) 直接使用传入的scene替换当前场景来切换画面,当前场景被释放。这是切换场景时最常用的方法。
pop() 释放当前场景,再从代码执行场景中弹出栈顶的场景,并将其设置为当前运行场景。如果栈为空,直接结束应用。和Push结对使用
end() 释放和终止执行场景,同时退出应用
pause() 暂停当前运行场景中的所有计时器和动作,场景仍然会显示在屏幕上
resume() 恢复当前运行场景的所有计时器和动作,场景仍然会显示在屏幕上

同时场景是层的容器,包含了所有需要显示的游戏元素。通常,当我们需要完成一个场景时候,会创建一个Scene的子类,并在子类中实现我们需要的功能。比如,我们可以在子类的初始化中载入游戏资源,为场景添加层,启动音乐播放等等。

层(Layer)

Layer是处理玩家事件响应的Node子类。与场景不同,层通常包含的是直接在屏幕上呈现的内容,并且可以接受用户的输入事件,包括触摸,加速度计和键盘输入等。我们需要在层中加入精灵,文本标签或者其他游戏元素,并设置游戏元素的属性,比如位置,方向和大小;设置游戏元素的动作等。通常,层中的对象功能类似,耦合较紧,与层中游戏内容相关的逻辑代码也编写在层中,在组织好层后,只需要把层按照顺序添加到场景中就可以显示出来了。要向场景添加层,我们可以使用add方法。

add( Node _child )
add( Node _child, int z )
add( Node *child, int z, int tag )

其中,Child参数就是节点。对于场景而言,通常我们添加的节点就是层。先添加的层会被置于后添加的层之下。如果需要为它们指定先后次序,可以使用不同的z值。tag是元素的标识号码,如果为子节点设置了tag值,就可以在它的父节点中利用tag值就可以找到它了。层可以包含任何Node作为子节点,包括Sprites(精灵), Labels(标签),甚至其他的Layer对象。
一些高级的Layer类:

MultiplexLayer
, a group of layers where only one is seen at a time
ScrollingManager
ScrollableLayer
; does the logic to limit scroll to viewable areas
RectMapLayer
HexMapLayer
; displays a group of rectangular or hexagonal tiles
Menu
, implements simple menus
ColorLayer
, a solid color rectangle
PythonInterpreterLayer
, used by director to pop up an interactive console to peek and poke at the objects in our scene ( ctrl + I to toggle on-off)

Paste_Image.png
上图的场景中有三个不同层,实现类似效果的代码:

import cocos

class LayerBlue(cocos.layer.ColorLayer):
    def __init__(self):
        super(LayerBlue, self).__init__(0, 128, 128, 255,
                                         width=120,height=80)
        self.position = (50, 50)


class LayerRed(cocos.layer.ColorLayer):
    def __init__(self):
        super(LayerRed, self).__init__(128, 0, 128, 255,
                                         width=120,height=80)
        self.position = (100, 80)


class LayerYellow(cocos.layer.ColorLayer):
    def __init__(self):
        super(LayerYellow, self).__init__(128, 128, 0, 255,
                                         width=120,height=80)
        self.position = (150, 110)


cocos.director.director.init()
main_scene = cocos.scene.Scene()
main_scene.add( LayerBlue(),z=0)
main_scene.add( LayerRed(),z=1)
main_scene.add( LayerYellow(),z=2 )
cocos.director.director.run( main_scene )

精灵

Cocos2d中的精灵和其他游戏引擎中的精灵相似,它可以移动,旋转,缩放,执行动画,并接受其他转换。Cocos2d的Sprite由Texure,frame和animation组成,简单过程可描述为:使用Texture2D加载图片,可以用Texture2D生成对应的SpriteFrame(精灵帧),将SpriteFrame添加到Animation生成动画数据,用Animation生成Animate(就是最终的动画动作),最后用Sprite执行这个动作。

折半查找和斐波那契查找的对比测试笔记

先上两者的 Python 代码。
折半查找:

def bin_search_(find_num, list_, k):
    split_pos = len(list_) // 2
    if find_num == list_[split_pos]:
        return split_pos + k
    elif len(list_) == 0:
        return None
    elif find_num < list_[split_pos]:
        return bin_search_(find_num, list_[:split_pos], k)
    else:
        return bin_search_(find_num, list_[split_pos+1:], k+split_pos+1)


def bin_search(find_num, list_):
    return bin_search_(find_num, list_, 0)


if __name__ == '__main__':
    list_ = [1, 2, 4, 5, 9, 11, 20, 33, 44, 50]
    find_num = 20
    print(bin_search(find_num, list_))

斐波那契查找:

def get_fib(list_len):
    a, b = 0, 1
    fib = []
    while True:
        fib.append(a)
        if a > list_len:
            return fib
        else:
            a, b = b, a + b


def fib_find(find_num, index, list_, fib, k):
    split_pos = fib[index-1] - 1
    if find_num == list_[split_pos]:
        return split_pos + k
    elif len(list_) == 0:
        return None
    elif find_num < list_[split_pos]:
        return fib_find(find_num, index-1, list_[:split_pos+1], fib, k)
    else:
        return fib_find(find_num, index-2, list_[split_pos+1:], fib, k+fib[index-1])


def fib_search_(find_num, list_, fib):
    list_len = len(list_)
    index, good_len = len(fib)-1, fib[-1]
    [list_.append(list_[-1]) for i in range(good_len-list_len)]
    final_index = fib_find(find_num, index, list_, fib, 0)
    [list_.pop() for i in range(good_len-list_len)]
    if final_index > list_len - 1:
        return list_len - 1
    else:
        return final_index


def fib_search(find_num, list_):
    fib = get_fib(len(list_))
    return fib_search_(find_num, list_, fib)


if __name__ == '__main__':
    list_ = [1, 2, 4, 5, 9, 11, 20, 33, 44, 50]
    find_num = 20
    print(fib_search(find_num, list_))
    find_num = 50
    print(fib_search(find_num, list_))

根据资料显示,斐波那契查找的平均效率会比折半查找更高。但在 Python 中,根据测试发现,使用斐波那契查找时,列表的 append 和 pop 操作比较消耗时间;除此之外,递归次数也比折半查找要多。
总之,在大多数时候,有序线性表查找时直接使用折半查找足以使用。

tig 命令快捷键功能翻译

tig 常用操作见:颠覆 Git 命令使用体验的神器 -- tig
以下是按h后显示的帮助文档的汉化。

通用:

视图切换

   m 主视图(显示当前分支)
   d 异视图(显示该commit修改了什么)
   l 日志视图(类似于git log)
   t 文件树视图(用于查阅当前commit的各个文件)
   f 过滤视图(快速搜索当前commit的文件名并查阅)
   b 追责视图(在文件树视图下使用,查看文件的每一行是在哪个commit产生的)
   r 参考视图(查阅各个分支)
s, S 状态视图(即git status)
   c 描述视图(类似于差异视图)
   y 藏匿视图(git stash相关,不太懂)
   g grep视图(在整个项目中搜索关键词)   
   p 呼叫视图(不知道干嘛的)  
   h 帮助视图(即本文)

视图操作

                 <Enter> 进入              进入和打开所选的行
                       < 返回              返回到上一个视图
     <Down>, <Ctrl-N>, J 下                向下移动
       <Up>, <Ctrl-P>, K 上                向上移动
                     ',' 父节点(不知道干嘛的) 移动到父节点
                   <Tab> 视图切换           当有两个视图同时显示的时候可切换焦点,操作另一个视图
                 R, <F5> 刷新              重载和刷新视图
                       O 最大化             最大化当前视图
                       q 关闭视图           关闭当前视图
                       Q 退出              关闭所有视图并退出

光标导航

                       k 上移
                       j 下移
     <PageDown>, <Space> 向下翻页      
             <PageUp>, - 向下翻页
                <Ctrl-D> 向下翻半页
                <Ctrl-U> 向上翻半页
                  <Home> 移到首行
                   <End> 移到尾行

滚动

      <Insert>, <Ctrl-Y> 向上滚动一行
      <Delete>, <Ctrl-E> 向下滚动一行
            <ScrollBack> 页面上滚
             <ScrollFwd> 页面下滚
                       | scroll-first-col    Scroll to the first line columns
                  <Left> 向左滚动两列
                 <Right> 向右滚动两列

搜索

/ 搜索              在当前视图下搜索(类似Vim)
? 往前搜索
n 下一个匹配结果
N 上一个匹配结果

杂项

e 编辑                打开编辑器(默认Vim)
: 命令提示符           类似Vim的命令提示符
o 选项             打开选项菜单
<Ctrl-L> 屏幕重绘
z 停止所有视图的加载
v 显示版本号

选项切换:

I :开关 顺/逆排序(文件视图时使用)
i :开关 排序依据
# :开关 行数显示
D :开关 日期显示
A :开关 作者显示
~ :开关 分支线条效果切换
F :开关 文件名显示
W :开关 忽略空白
X :开关 commit ID显示
$ :开关 commit 信息滚动显示
% :开关 文件过滤

搜索快捷键

Searching
  <Down>, <Ctrl-N>, <Ctrl-J> find-next           Find next search match
    <Up>, <Ctrl-P>, <Ctrl-K> find-prev           Find previous search match

主视图快捷键

选项开关:
    G :分支线条效果切换
    F :开关 分支名显示
调用外界命令:
    C ?git cherry-pick %(commit)

差异视图快捷键

选项切换:
                           [ :显示详细程度 -1
                           ] :显示详细程度 +1
调用内置命令:
                           @ :/^@@

参考视图快捷键

调用外部命令:
    C ?git checkout %(branch)
    ! ?git branch -D %(branch)

状态视图快捷键

视图详细操作
    u 添加/取消到待提交(类似于git add)
    ! 撤销文件的修改
    M 使用外部工具合并文件
调用外部命令:
    C !git commit

描述视图快捷键

视图详细操作
    u 添加/取消到待提交
    ! 撤销文件的修改
    1 stage-update-line   Stage/unstage single line
    \ stage-split-chunk   Split current diff chunk
选项开关:
    [ :显示详细程度 -1
    ] :显示详细程度 +1
调用内置命令:
    @ :/^@@

藏匿视图快捷键

调用外部命令:
    A ?git stash apply %(stash)
    P ?git stash pop %(stash)
    ! ?git stash drop %(stash)

附注:gfw对不同网站的关键词封锁条件探究结果

1: t66y.com

最短触发条件:

GET / HTTP\r\nHost:t66y.com\r\n

把\r\n改成\n后不触发.

2: sis001.com

最短触发条件:

GET / \nHost sis001.com\n

请求修改为

GET / \n?\nHost sis001.com\n

后不触发.里面的"?"可用其他非空白字符代替,但不能换成两个以上字符.

3: fqrouter.tumblr.com

最短触发条件:

GET / \nHost fqrouter.tumblr.com\n

这个网址的封锁条件非常厉害,在网址前加任意字符串,比如abcdfqrouter.tumblr.com,依然被封.

按照上一种更改请求的方式可以顺利通过,但tumblr服务器不响应内容.

时间有限,暂时只测试这些.

在vps中编译和运行蓝灯

新的 lantern(蓝灯) release 版需要有图形界面环境,如果需要在纯命令行环境中运行lantern需要手动编译.

我的 vps 为 Ubuntu 14.04 server amd64.


== 1 安装编译环境 ==

sudo apt-get install gcc make git build-essential libc6-dev libc6-dev-i386

== 2 安装Node.js ==

curl -sL https://deb.nodesource.com/setup_6.x | sudo -E bash -
sudo apt-get install nodejs

安装成功后执行 nodejs -v 输出 v6.2.1 或更高版本

== 3 安装gulp ==

sudo npm i gulp-cli -g

安装成功后执行 gulp -v 输出 CLI version 1.2.1 或更高版本

== 4 安装Go ==

wget "https://storage.googleapis.com/golang/go1.6.2.linux-amd64.tar.gz"
tar -xvf go1.6.2.linux-amd64.tar.gz
mv go ~/go1.4
export GOROOT=$HOME/go1.4
export PATH=$PATH:$GOROOT/bin

安装成功后执行 go version 输出 go version 输出 go1.6.2 linux/amd64 或更高版本

== 5 安装lantern定制版Go ==

git clone [email protected]:getlantern/go.git --depth 1
cd go/src
./all.bash #编译成功会显示 all tests passed
cd ../../
mv go ~/go

退出,重新ssh登录

export GOROOT=$HOME/go
export PATH=$PATH:$GOROOT/bin

安装成功后执行 go version 输出 go version go1.6.2_lantern_20160503 linux/amd64 或更高版本

== 6 编译lantern ==

git clone [email protected]:getlantern/lantern.git --depth 1
cd lantern
HEADLESS=true make linux

编译成功会在当前目录生成 lantern_linux_386 和 lantern_linux_amd64

== 8 运行lantern ==

./lantern_linux_amd64 -addr 0.0.0.0:8787 -startup=false -proxyall

运行成功后,在本地电脑或移动设备设置 http 代理,ip 为 vps 的 ip,端口8787,然后就可以使用蓝灯了.
在 vps 中可以借助 byobu 等程序让 lantern 在后台运行.

快速上手一个语言的学习路线(Go语言描述):一

这条学习路线出自:快速掌握一个语言最常用的50%
Go语言示例部分出自:GO 语言简介(上)— 语法

本系列将以Go语言为例,详细实践这条路线,展示上手一个语言基本内容的主要过程。
本系列主要针对的是具有编程经验的人,且只适用于学习支持过程式/函数式编程的语言。


第一章:基本数据类型,基本语法和主要语言构造,主要数学运算符和print函数的使用;数组和其他集合类的使用。


1 Hello World

第一步即是最经典的Hello World,展现print函数的使用。从这步也可以最快地了解该语言写出来的最简单的程序形式。

package main

import "fmt"

func main() {
	fmt.Println("Hello World")
}

然后是格式化的输出:

package main

import "fmt"

func main() {
	fmt.Printf("%t\n", 1 == 2)
	fmt.Printf("二进制:%b\n", 255)
	fmt.Printf("八进制:%o\n", 255)
	fmt.Printf("十六进制:%X\n", 255)
	fmt.Printf("十进制:%d\n", 255)
	fmt.Printf("字符串:%s\n", "hello world")
}

2 基本数学运算

学习基本的加减乘除,能够将该语言作为计算器使用。

package main

import "fmt"

func main() {
	fmt.Println(1 + 1)
	fmt.Println(2.0 - 1.1)
	fmt.Println(2 * 1024)
	fmt.Println(256 / 128)
	fmt.Println(2 ^ 1)          // 移位
	fmt.Println(math.Pow(2, 3)) // 次方
	// 高级的数学计算参见math包。
}

3 变量声明

package main

import "fmt"

func main() {
	var a int = 1
	i := 1
	j, k := 1.1, 2.1
	l := true
	const m = "hello" // 常量
	fmt.Println(a, i, j, k, l, m)

}

4 分支循环语句

图灵完备所需要的流程控制语法。
判断:

if x % 2 == 0 {
    //...
}
//if - else
if x % 2 == 0 {
    //偶数...
} else {
    //奇数...
}
 
//多分支
if num < 0 {
    //负数
} else if num == 0 {
    //零
} else {
    //正数
}

循环:

//经典的for语句 init; condition; post
for i := 0; i<10; i++{
     fmt.Println(i)
}
 
//精简的for语句 condition
i := 1
for i<10 {
    fmt.Println(i)
    i++
}
 
//死循环的for语句 相当于for(;;)
i :=1
for {
    if i>10 {
        break
    }
    i++
}

5 练习:用循环求斐波那契数列第n个数

package main

import "fmt"

func main() {
	n := 7

	a := 0
	b := 1
	for n >= 2 {
		a, b = b, a+b
		n -= 1
	}

	fmt.Println(a)
}

6 数组

func main() {
    var a [5]int
    fmt.Println("array a:", a)
 
    a[1] = 10
    a[3] = 30
    fmt.Println("assign:", a)
 
    fmt.Println("len:", len(a))
 
    b := [5]int{1, 2, 3, 4, 5}
    fmt.Println("init:", b)
 
    var c [2][3]int
    for i := 0; i < 2; i++ {
        for j := 0; j < 3; j++ {
            c[i][j] = i + j
        }
    }
    fmt.Println("2d: ", c)
}

7 数组切片

a := [5]int{1, 2, 3, 4, 5}
 
b := a[2:4] // a[2] 和 a[3],但不包括a[4]
fmt.Println(b)
 
b = a[:4] // 从 a[0]到a[4],但不包括a[4]
fmt.Println(b)
 
b = a[2:] // 从 a[2]到a[4],且包括a[2]
fmt.Println(b)

8 map

func main(){
    m := make(map[string]int) //使用make创建一个空的map
 
    m["one"] = 1
    m["two"] = 2
    m["three"] = 3
 
    fmt.Println(m) //输出 map[three:3 two:2 one:1] (顺序在运行时可能不一样)
    fmt.Println(len(m)) //输出 3
 
    v := m["two"] //从map里取值
    fmt.Println(v) // 输出 2
 
    delete(m, "two")
    fmt.Println(m) //输出 map[three:3 one:1]
 
    m1 := map[string]int{"one": 1, "two": 2, "three": 3}
    fmt.Println(m1) //输出 map[two:2 three:3 one:1] (顺序在运行时可能不一样)
 
    for key, val := range m1{
        fmt.Printf("%s => %d \n", key, val)
        /*输出:(顺序在运行时可能不一样)
            three => 3
            one => 1
            two => 2*/
    }
}

Xamarin forms 爬坑指南

本文将收录一些遇到的坑如何爬出来的解决方案。


1. 生成解决方案时DLL被占用

清理解决方案。

2. 修改APP名称 / Change App name

参见 Xamarin Android App name not setting

3. Agent 无法远程到 Mac / Can't connect to Mac with Xamarin Mac Agent

检查 Xamarin 日志(帮助-Xamarin-打开日志)。
一般是因为本地的Xamarin.iOS 和 Mac 上的版本不一致,更新版本即可。
参见 I can't connect to Mac with Xamarin Mac Agent from Visual Studio 2015

4. Can not resolve reference: C:/Windows/Microsoft.NET/Framework/v4.0.30319/de/mscorlib.resources.dll

参见 Can not resolve reference: C:/Windows/Microsoft.NET/Framework/v4.0.30319/de/mscorlib.resources.dll

Python 正则表达式(re模块)简易上手指南

在Google翻了许多关于Python正则表达式的教程,但多数教程的易读性都不太好,所以我决定自个儿撸一篇可以快速上手的教程出来,以备未来忘记的的时候回来参考。

关于正则表达式的基础,推荐《鸟哥的私房菜:基础学习篇》第346页的正则相关章节,或者http://vbird.dic.ksu.edu.tw/linux_basic/0330regularex.php ,并使用grep/sed来练习。本指南只阐述re模块的简单使用。
附:正则语法规则

正则语法规则

1

首先是最简单的两大用途:查找:re.findall(),和替换:re.sub()。

#一堆单词
animal = 'dog cat bird cat dog cat duck fuck'

#匹配cat
import re
re.findall('cat', animal)
#返回['cat', 'cat', 'cat']

#匹配两个dog之间的内容
re.findall('dog.+dog', animal)
#返回['dog cat bird cat dog']

#匹配?uck
re.findall('.uck', animal)
#返回['duck', 'fuck']
#替换cat为mouse
re.sub('cat', 'mouse', animal)
#返回'dog mouse bird mouse dog mouse duck fuck'

#调换bird和duck
re.sub('(bird)(.+)(duck)', '\\3\\2\\1', animal)
#返回'dog cat duck cat dog cat bird fuck'

2

另一种使用方式:预先编译好正则关键词再调用,方便同一关键词多次使用。

#匹配?uck
p = re.compile('.uck')
p.findall(animal)
#返回['duck', 'fuck']

#调换bird和duck
p = re.compile('(bird)(.+)(duck)')
p.sub('\\3\\2\\1', animal)
#返回'dog cat duck cat dog cat bird fuck'

3

分割字符串:re.split()

#字符串
string = 'hello1world2!3learning4python'
#将数字作为分割符
p = re.compile('\d+')
p.split(string)
#返回['hello', 'world', '!', 'learning', 'python']

未完待续

Linux nc命令用法收集

ps.ubuntu自带的nc是netcat-openbsd版,不带-c/-e参数。
pss.在线Markdown编辑器的bug是怎么回事...“#”号依然显示着

参数


想要连接到某处: nc [-options] hostname port[s] [ports] …
绑定端口等待连接: nc -l port [-options] [hostname] [port]

  • -g<网关>:设置路由器跃程通信网关,最多设置8个;
  • -G<指向器数目>:设置来源路由指向器,其数值为4的倍数;
  • -h:在线帮助;
  • -i<延迟秒数>:设置时间间隔,以便传送信息及扫描通信端口;
  • -l:使用监听模式,监控传入的资料;
  • -n:直接使用ip地址,而不通过域名服务器;
  • -o<输出文件>:指定文件名称,把往来传输的数据以16进制字码倾倒成该文件保存;
  • -p<通信端口>:设置本地主机使用的通信端口;
  • -r:指定源端口和目的端口都进行随机的选择;
  • -s<来源位址>:设置本地主机送出数据包的IP地址;
  • -u:使用UDP传输协议;
  • -v:显示指令执行过程;
  • -w<超时秒数>:设置等待连线的时间;
  • -z:使用0输入/输出模式,只在扫描通信端口时使用。

## 用法

[A Server(192.168.1.1) B Client(192.168.1.2)]

0.


连接到远程主机:
$nc -nvv 192.168.x.x 80

连到192.168.x.x的TCP80端口.

监听本地主机:
$nc -l 80

监听本机的TCP80端口.

超时控制:

多数情况我们不希望连接一直保持,那么我们可以使用 -w 参数来指定连接的空闲超时时间,该参数紧接一个数值,代表秒数,如果连接超过指定时间则连接会被终止。

Server
$nc -l 2389
Client
$ nc -w 10 localhost 2389

该连接将在 10 秒后中断。
注意: 不要在服务器端同时使用 -w 和 -l 参数,因为 -w 参数将在服务器端无效果。

1.端口扫描


端口扫描经常被系统管理员和黑客用来发现在一些机器上开放的端口,帮助他们识别系统中的漏洞。

$nc -z -v -n 192.168.1.1 21-25

可以运行在TCP或者UDP模式,默认是TCP,-u参数调整为udp.
z 参数告诉netcat使用0 IO,连接成功后立即关闭连接, 不进行数据交换.
v 参数指详细输出.
n 参数告诉netcat 不要使用DNS反向查询IP地址的域名.
以上命令会打印21到25 所有开放的端口。

$nc -v 127.0.0.1 22
localhost [127.0.0.1] 22 (ssh) open
SSH-2.0-OpenSSH_5.9p1 Debian-5ubuntu1.4

"SSH-2.0-OpenSSH_5.9p1 Debian-5ubuntu1.4"为Banner信息。Banner是一个文本,Banner是一个你连接的服务发送给你的文本信息。当你试图鉴别漏洞或者服务的类型和版本的时候,Banner信息是非常有用的。但是,并不是所有的服务都会发送banner.一旦你发现开放的端口,你可以容易的使用netcat 连接服务抓取他们的banner。

2.Chat Server


假如你想和你的朋友聊聊,有很多的软件和信息服务可以供你使用。但是,如果你没有这么奢侈的配置,比如你在计算机实验室,所有的对外的连接都是被限制的,你怎样和整天坐在隔壁房间的朋友沟通那?不要郁闷了,netcat提供了这样一种方法,你只需要创建一个Chat服务器,一个预先确定好的端口,这样子他就可以联系到你了。

Server
$nc -l 20000

netcat 命令在20000端口启动了一个tcp 服务器,所有的标准输出和输入会输出到该端口。输出和输入都在此shell中展示。

Client
$nc 192.168.1.1 20000

不管你在机器B上键入什么都会出现在机器A上。

3.文件传输


大部分时间中,我们都在试图通过网络或者其他工具传输文件。有很多种方法,比如FTP,SCP,SMB等等,但是当你只是需要临时或者一次传输文件,真的值得浪费时间来安装配置一个软件到你的机器上嘛。假设,你想要传一个文件file.txt 从A 到B。A或者B都可以作为服务器或者客户端.

Server
$nc -l 20000 < file.txt
Client
$nc -n 192.168.1.1 20000 > file.txt

这里我们创建了一个服务器在A上并且重定向netcat的输入为文件file.txt,那么当任何成功连接到该端口,netcat会发送file的文件内容。
在客户端我们重定向输出到file.txt,当B连接到A,A发送文件内容,B保存文件内容到file.txt.
没有必要创建文件源作为Server,我们也可以相反的方法使用。像下面的我们发送文件从B到A,但是服务器创建在A上,这次我们仅需要重定向netcat的输出并且重定向B的输入文件。
B作为Server

Server
$nc -l 20000 > file.txt
Client
$nc 192.168.1.2 20000 < file.txt

#### 4.目录传输

发送一个文件很简单,但是如果我们想要发送多个文件,或者整个目录,一样很简单,只需要使用压缩工具tar,压缩后发送压缩包。
如果你想要通过网络传输一个目录从A到B。

Server
$tar -cvf – dir_name | nc -l 20000
Client
$nc -n 192.168.1.1 20000 | tar -xvf -

这里在A服务器上,我们创建一个tar归档包并且通过-在控制台重定向它,然后使用管道,重定向给netcat,netcat可以通过网络发送它。
在客户端我们下载该压缩包通过netcat 管道然后打开文件。
如果想要节省带宽传输压缩包,我们可以使用bzip2或者其他工具压缩。

Server
$tar -cvf – dir_name| bzip2 -z | nc -l 20000

通过bzip2压缩

Client
$nc -n 192.168.1.1 20000 | bzip2 -d |tar -xvf -

#### 5. 加密你通过网络发送的数据

如果你担心你在网络上发送数据的安全,你可以在发送你的数据之前用如mcrypt的工具加密。

Server
$nc localhost 20000 | mcrypt –flush –bare -F -q -d -m ecb > file.txt

使用mcrypt工具加密数据。

Client
$mcrypt –flush –bare -F -q -m ecb < file.txt | nc -l 20000

使用mcrypt工具解密数据。
以上两个命令会提示需要密码,确保两端使用相同的密码。
这里我们是使用mcrypt用来加密,使用其它任意加密工具都可以。

6.流视频


虽然不是生成流视频的最好方法,但如果服务器上没有特定的工具,使用netcat,我们仍然有希望做成这件事。

Server
$cat video.avi | nc -l 20000

这里我们只是从一个视频文件中读入并重定向输出到netcat客户端

Client
$nc 192.168.1.1 20000 | mplayer -vo x11 -cache 3000 -

这里我们从socket中读入数据并重定向到mplayer。

7,克隆一个设备


如果你已经安装配置一台Linux机器并且需要重复同样的操作对其他的机器,而你不想在重复配置一遍。不在需要重复配置安装的过程,只启动另一台机器的一些引导可以随身碟和克隆你的机器。
克隆Linux PC很简单,假如你的系统在磁盘/dev/sda上

Server
$dd if=/dev/sda | nc -l 20000
Client
$nc -n 192.168.1.1 20000 | dd of=/dev/sda

dd是一个从磁盘读取原始数据的工具,我通过netcat服务器重定向它的输出流到其他机器并且写入到磁盘中,它会随着分区表拷贝所有的信息。但是如果我们已经做过分区并且只需要克隆root分区,我们可以根据我们系统root分区的位置,更改sda 为sda1,sda2.等等。

8.打开一个shell


我们已经用过远程shell-使用telnet和ssh,但是如果这两个命令没有安装并且我们没有权限安装他们,我们也可以使用netcat创建远程shell。
假设你的netcat支持 -c -e 参数(原生 netcat)

Server
$nc -l 20000 -e /bin/bash -i
Client
$nc 192.168.1.1 20000

这里我们已经创建了一个netcat服务器并且表示当它连接成功时执行/bin/bash
假如netcat 不支持-c 或者 -e 参数(openbsd netcat),我们仍然能够创建远程shell

Server
$mkfifo /tmp/tmp_fifo
$cat /tmp/tmp_fifo | /bin/sh -i 2>&1 | nc -l 20000 > /tmp/tmp_fifo

这里我们创建了一个fifo文件,然后使用管道命令把这个fifo文件内容定向到shell 2>&1中。是用来重定向标准错误输出和标准输出,然后管道到netcat 运行的端口20000上。至此,我们已经把netcat的输出重定向到fifo文件中。
说明:
从网络收到的输入写到fifo文件中
cat 命令读取fifo文件并且其内容发送给sh命令
sh命令进程受到输入并把它写回到netcat。
netcat 通过网络发送输出到client
至于为什么会成功是因为管道使命令平行执行,fifo文件用来替代正常文件,因为fifo使读取等待而如果是一个普通文件,cat命令会尽快结束并开始读取空文件。
在客户端仅仅简单连接到服务器

Client
$nc -n 192.168.1.1 20000

你会得到一个shell提示符在客户端

9.反向shell


反向shell是指在客户端打开的shell。反向shell这样命名是因为不同于其他配置,这里服务器使用的是由客户提供的服务。

Server
$nc -l 20000

在客户端,简单地告诉netcat在连接完成后,执行shell。

Client
$nc 192.168.1.1 20000 -e /bin/bash

现在,什么是反向shell的特别之处呢
反向shell经常被用来绕过防火墙的限制,如阻止入站连接。例如,我有一个专用IP地址为192.168.1.1,我使用代理服务器连接到外部网络。如果我想从网络外部访问 这台机器如1.2.3.4的shell,那么我会用反向外壳用于这一目的。

10.指定源端口


假设你的防火墙过滤除25端口外其它所有端口,你需要使用-p选项指定源端口。

Server
$nc -l 20000
Client
$nc 192.168.1.1 20000 25

使用1024以内的端口需要root权限。
该命令将在客户端开启25端口用于通讯,否则将使用随机端口。

11.指定源地址


假设你的机器有多个地址,希望明确指定使用哪个地址用于外部数据通讯。我们可以在netcat中使用-s选项指定ip地址。

Server
$nc -u -l 20000 < file.txt
Client
$nc -u 192.168.1.1 20000 -s 172.31.100.5 > file.txt

该命令将绑定地址172.31.100.5。

12.静态web页面服务器


新建一个网页,命名为somepage.html;
新建一个shell script:

while true; do
    nc -l 80 -q 1 < somepage.html;
done

用root权限执行,然后在浏览器中输入127.0.0.1打开看看是否正确运行。
nc 指令通常都是給管理者進行除錯或測試等動作用的,所以如果只是單純需要臨時的網頁伺服器,使用 Python 的 SimpleHTTPServer 模組會比較方便。

13.模拟HTTP Headers


$nc www.huanxiangwu.com 80
GET / HTTP/1.1
Host: ispconfig.org
Referrer: mypage.com
User-Agent: my-browser

HTTP/1.1 200 OK
Date: Tue, 16 Dec 2008 07:23:24 GMT
Server: Apache/2.2.6 (Unix) DAV/2 mod_mono/1.2.1 mod_python/3.2.8 Python/2.4.3 mod_perl/2.0.2 Perl/v5.8.8
Set-Cookie: PHPSESSID=bbadorbvie1gn037iih6lrdg50; path=/
Expires: 0
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Cache-Control: private, post-check=0, pre-check=0, max-age=0
Set-Cookie: oWn_sid=xRutAY; expires=Tue, 23-Dec-2008 07:23:24 GMT; path=/
Vary: Accept-Encoding
Transfer-Encoding: chunked
Content-Type: text/html
[......]

在nc命令后,输入红色部分的内容,然后按两次回车,即可从对方获得HTTP Headers内容。

13.Netcat支持IPv6


netcat 的 -4 和 -6 参数用来指定 IP 地址类型,分别是 IPv4 和 IPv6:

Server
$ nc -4 -l 2389
Client
$ nc -4 localhost 2389

然后我们可以使用 netstat 命令来查看网络的情况:

$ netstat | grep 2389
tcp        0      0 localhost:2389          localhost:50851         ESTABLISHED
tcp        0      0 localhost:50851         localhost:2389          ESTABLISHED

接下来我们看看IPv6 的情况:

Server
$ nc -6 -l 2389
Client
$ nc -6 localhost 2389

再次运行 netstat 命令:

$ netstat | grep 2389
tcp6       0      0 localhost:2389          localhost:33234         ESTABLISHED
tcp6       0      0 localhost:33234         localhost:2389          ESTABLISHED

前缀是 tcp6 表示使用的是 IPv6 的地址。

14.在 Netcat 中禁止从标准输入中读取数据


该功能使用 -d 参数,请看下面例子:

Server
$ nc -l 2389
Client
$ nc -d localhost 2389
Hi

你输入的 Hi 文本并不会送到服务器端。

15.强制 Netcat 服务器端保持启动状态


如果连接到服务器的客户端断开连接,那么服务器端也会跟着退出。

Server
$ nc -l 2389
Client
$ nc localhost 2389
^C
Server
$ nc -l 2389
$

上述例子中,但客户端断开时服务器端也立即退出。
我们可以通过 -k 参数来控制让服务器不会因为客户端的断开连接而退出。

Server
$ nc -k -l 2389
Client
$ nc localhost 2389
^C
Server
$ nc -k -l 2389

#### 16.配置 Netcat 客户端不会因为 EOF 而退出

Netcat 客户端可以通过 -q 参数来控制接收到 EOF 后隔多长时间才退出,该参数的单位是秒:

Client
$nc  -q 5  localhost 2389

现在如果客户端接收到 EOF ,它将等待 5 秒后退出。

17.手動使用 SMTP 協定寄信


在測試郵件伺服器是否正常時,可以使用這樣的方式手動寄送 Email:

$nc localhost 25 << EOF
HELO host.example.com
MAIL FROM: <[email protected]>
RCPT TO: <[email protected]>
DATA
Body of email.
.
QUIT
EOF

#### 18.透過代理伺服器(Proxy)連線

這指令會使用 10.2.3.4:8080 這個代理伺服器,連線至 host.example.com 的42端口。

$nc -x10.2.3.4:8080 -Xconnect host.example.com 42

#### 19.使用 Unix Domain Socket

這行指令會建立一個 Unix Domain Socket,並接收資料:

$nc -lU /var/tmp/dsocket

参考链接:

Linux Netcat 命令——网络工具中的瑞士军刀
nc/netcat命令
linux nc (NetCat) 命令详解
Linux nc (netcat) 详解
8 个实用的 Linux netcat 命令示例
Netcat(Linux nc 指令)網路管理者工具實用範例
Linux下利用nc命令来监控检测服务器的端口使用情况
[讨论] 求解:linux下nc的转发port的用法

江南小碧的C#教程:1、第一个C#程序

  • 本教程系列其实是我的学习笔记。参考了廖雪峰的《Python 教程》的编排目录。

  • 本教程推荐给有别的编程语言基础(比如 Python)的同学阅读。

  • 这个教程不会涉及到编辑器/IDE 的选择和使用,不知道使用什么编辑器好的同学可以自行研究宇宙第一IDE:Visual Studio 的使用方式。

  • 本人使用 Mac OS + Spacemacs。


Hello World

以下是C# 版 Hello World 的代码:

using System;


class HelloWorld {
    static void Main() {
        Console.WriteLine("Hello world!");
    }
}

完(逃


为了不让本文太短,补充一些内容:

  • C#的命名方式:大驼峰,参见本文代码命名 “HelloWorld”;
  • using 即类似于 Python 的import;
  • void 表示该函数不返回任何东西;
  • 命名为 Main 的函数默认是整个程序的第一入口;
  • Console.WriteLine 即类似于 Python 的 print 函数,它会自动在结尾加上“/n”。

江南小碧的C#教程:4、各种集合类与循环

C#的集合类中包括列表、字典和其他常用的数据类型。

列表

C#中比较类似于Python里的list的数据类型是ArrayList。
以下代码展现了ArrayList的增删改查:

using System;
using System.Collections;

class HelloWorld {
    static void Main() {
        ArrayList list_1 = new ArrayList(); // 新建列表

        // 在列表尾部添加元素
        list_1.Add(1);
        list_1.Add("abc");
        list_1.Add(true);

        // 查看任意一个元素
        Console.WriteLine(list_1[1]);

        // 查看列表长度
        Console.WriteLine(list_1.Count);

        // 修改元素
        list_1[1] = 2;

        // 插入元素
        list_1.Insert(1, "ABC");

        // 删除元素
        list_1.RemoveAt(2);
    }
}

更多关于列表和类似数据类型的资料见C#中数组、ArrayList和List三者的区别

字典和其他

参见C#中的Dictionary字典类介绍
C# 集合(Collection)

循环

通过循环可以方便地把列表中的每一个元素打印出来。

using System;
using System.Collections;

class HelloWorld {
    static void Main() {
        ArrayList list_1 = new ArrayList(); // 新建列表

        // 添加元素
        list_1.Add(1);
        list_1.Add("abc");
        list_1.Add(true);

        foreach (var i in list_1) {
            Console.WriteLine(i);
        }
    }
}

输出:

1
abc
True

foreach...in类似于Python的for用法。C#还有原始的类似C的for循环。

用for循环计算1+2+....+100:

using static System.Console;

class HelloWorld {
    static void Main() {
        var sum = 0;
        for (var i = 1; i <= 100 ; i++) {
            sum += i;
        }
        WriteLine(sum);
    }
}

cocos2d-python中文教程:3 动作,转场和特效

本章对应英文文档:Actions, Transformations and Effects


动作

"动作"即对CocosNode对象下达命令.这些动作常见的有调整对象的属性,旋转,比例等.
比如"MoveBy"动作用来命令某对象在指定时间内进行移动.

首先一张rocket.png,放在与代码同目录下
rocket.png

示范代码:

import cocos
from cocos.actions import MoveBy

class Fly(cocos.layer.Layer):

    def __init__(self):
        super(Fly,self).__init__()

        rocket = cocos.sprite.Sprite('rocket.png')
        rocket.position = 128,128
        rocket.scale = 0.5
        #在5秒内往右上方移动,最终横竖坐标分别增加50                                 
        rocket.do( MoveBy( (320,240), duration=2) )
        self.add(sprite, z=0)

cocos.director.director.init()
scene = cocos.scene.Scene(Fly())
cocos.director.director.run(scene)

效果:
1.png

火箭往右上方移动.

动作根据所花费的时间不同可分为三类:

  • 瞬间动作: 顾名思义,瞬间完成的动作,比如瞬移:
#把精灵瞬移到坐标(120, 330)
sprite.do( Place( (120, 330) ))
  • 持续动作: 在一定时间内完成的动作,比如MoveBy
  • 时长未知的动作: 完成时间未知的动作

已知时长的持续型动作有些有趣的特性:
  • 执行一些修改时间的动作可以调节时间流速

  • 所有使用相对坐标的动作(以"By"结尾)和一些使用绝对坐标的动作(以"To"结尾)可以叠加"Reverse"(相反)效果以实现反方向的动作,比如顺时针旋转变成逆时针.
    (作者ps:第一章有示范代码)


## 基础动作 基础动作会修改精灵的一些基础属性,比如:

特殊动作

**时间相关:**在一段时间内待命

**流程控制:**调用一个指定的函数

**网格助手:**帮忙执行一些网格动作

摄影机相关:

动作的组合与修饰

Cocos也提供了一些强大的操作符用来组合和修饰动作,重点便是下面所列出的.

顺序执行操作符: action_1 + action_2 -> action_result
action_result的效果就是在action_1完成后执行action_2

例子:

import cocos
from cocos.actions import MoveTo

class Fly(cocos.layer.Layer):

    def __init__(self):
        super(Fly,self).__init__()

        rocket = cocos.sprite.Sprite('rocket.png')
        rocket.position = 128,128
        rocket.scale = 0.5

        move = MoveTo((100, 100), 2) + MoveTo((200, 200), 3)                     
        rocket.do( move )
        self.add(sprite, z=0)

cocos.director.director.init()
scene = cocos.scene.Scene(Fly())
cocos.director.director.run(scene)

火箭花2秒时间到达(100,100)坐标,再花3秒时间到达(200,200)坐标.

同时执行操作符: action_1 | action_2 -> action_result
即action_1和action_2同时发生.
例子:

import cocos
from cocos.actions import MoveTo, RotateBy

class Fly(cocos.layer.Layer):

    def __init__(self):
        super(Fly,self).__init__()

        rocket = cocos.sprite.Sprite('rocket.png')
        rocket.position = 128,128
        rocket.scale = 0.5

        move = MoveTo((400, 400), 5) | RotateBy(360, 5)                      
        rocket.do( move )
        self.add(sprite, z=0)

cocos.director.director.init()
scene = cocos.scene.Scene(Fly())
cocos.director.director.run(scene)

火箭往右上方翻滚.

**循环操作符:**action_1 * n -> action_result
action_1将执行n次(n是一个合法的大于等于0的整数)
例子:
将上面代码中move=那行替换为

move = RotateBy(360, 5) * 2

效果就是火箭顺时针旋转2次.

无限重复: Repeat(action_1) -> action_result
无限重复动作
例子:

import cocos
from cocos.actions import RotateBy,Repeat

class Fly(cocos.layer.Layer):

    def __init__(self):
        super(Fly,self).__init__()

        rocket = cocos.sprite.Sprite('rocket.png')
        rocket.position = 128,128
        rocket.scale = 0.5

        move = Repeat( RotateBy(360, 5) )                  
        rocket.do( move )
        self.add(sprite, z=0)

cocos.director.director.init()
scene = cocos.scene.Scene(Fly())
cocos.director.director.run(scene)

火箭不停地旋转.

时间流速修改器

网格辐度修改器


特效

(待续)


创建自定义动作

(待续)

Python 时间相关函数速查

引入模块

from datetime import datetime

当前时间

获取当前时间的datetime对象

now = datetime.now()

1 查看当前时间

now.ctime()
# 'Wed Nov 22 11:00:11 2017'

2 获取当前时间的时间戳(1970年到现在的秒数)

now.timestamp()
# 1511319722.87419

3 打印自定义格式的时间

(strftime:string format time 的缩写)

# 格式化成2009-03-20 11:45:39形式
now.strftime('%Y-%m-%d %H:%M:%S')
# '2017-11-22 11:11:35'

# 格式化成Sat Mar 28 22:24:24 2009形式
now.strftime('%a %b %d %H:%M:%S %Y')
# 'Wed Nov 22 11:11:55 2017'

时间格式转换

1 读取各种格式的时间字符串,转成 datetime 对象

(strptime:string parse time 的缩写)

# 读取‘Wed Nov 22 11:11:55 2017'
dt = datetime.strptime('Wed Nov 22 11:11:55 2017', '%a %b %d %H:%M:%S %Y')
# datetime.datetime(2017, 11, 22, 11, 11, 55)

2 时间戳转 datetime 对象

dt = datetime.fromtimestamp(1511322862.666288)

2 查看该时间的时间戳

dt.timestamp()
# 1511322862.666288

3 datetime对象转自定义格式的字符串

TODO


Xamarin forms 爬坑指南

本文将收录一些遇到的坑如何爬出来的解决方案。


1. 生成解决方案时DLL被占用

清理解决方案。

2. 修改APP名称 / Change App name

参见 Xamarin Android App name not setting

3. Agent 无法远程到 Mac / Can't connect to Mac with Xamarin Mac Agent

检查 Xamarin 日志(帮助-Xamarin-打开日志)。
一般是因为本地的Xamarin.iOS 和 Mac 上的版本不一致,更新版本即可。
参见 I can't connect to Mac with Xamarin Mac Agent from Visual Studio 2015

4. Can not resolve reference: C:/Windows/Microsoft.NET/Framework/v4.0.30319/de/mscorlib.resources.dll

参见 Can not resolve reference: C:/Windows/Microsoft.NET/Framework/v4.0.30319/de/mscorlib.resources.dll

关于http请求中LF/CRLF作为分割符对gfw的关键词检测的影响

事情的起因出自一次用nc向1024发送请求包的经历:

$ nc t66y.com 80
GET / HTTP/1.1
Host: t66y.com

HTTP/1.1 200 OK
...

奇迹般顺利地收到了1024的网页,没有接收到来自gfw的tcp reset干扰.

已知nc手动发送http请求,分割符为LF(\n),并参阅深入理解GFW:内部结构,可知通过LF作为分割符躲避gfw的关键词检测的bug至今未修复.

用Python测试:

import socket

s = socket.socket()
s.connect(('t66y.com', 80))
s.send(b'GET / HTTP/1.1\nHost:t66y.com\n\n')
buf = 1
while buf:
  buf = s.recv(2048).decode('gbk')
  print(buf)

通过一系列的测试,把请求修改为"GET / HTTP/1.1\r\nHost:t66y.com\r\n\n"后终于收到了gfw发来的reset包.
但是把t66y.com修改为sis001.com后就算分割符是LF也照样被过滤,收到reset包.

再换用多个域名进行测试,依旧是有些被过滤有些没有.原因是什么?

本人的猜想:gfw的过滤系统为分布式服务器,请求包同时进入多个服务器进行分析,每个服务器有不同的黑名单.早期部署的服务器带有这个bug,后来增加的设备修复了,但老设备没有修复,所以导致了这种现象的发生.

据此原理可以写一个部署在本地的正向代理,把请求中的"\r"去掉,这样就相当于直连1024了.

通过魔改http报文逃过gfw关键词检测

受到西厢计划第三季的启发,本人在近日不停地构造乱七八糟的http报文,测试能否逃过gfw的关键词检测.实验站点为sis001.

已知关键词检测分三步:协议检测,拆包,关键词匹配.通过缩小范围,本人发现其协议判断基于头部关键词"GET / ",匹配逻辑可能为:
GET -> 第一个回车 -> 是否为键值对(a:b) -> a是否为host -> 是的话开始匹配后面的域名,否的话跳到下一个回车,继续第三步.
也就是说,就算请求的是sis001.com.cn也会触发封锁.

所以能够逃过检测的报文可以这样:

(报头GET前有内容,如果是回车的话部分服务器勉强能响应这种报文)
\nGET / HTTP/1.1\nHost:sis001.com.cn\nConnection:close\n\n

或者这样:

(夹了一个非键值对的内容,多数服务器可以正常响应这种报文)
GET / HTTP/1.1\na\nHost:sis001.com.cn\nConnection:close\n\n

发送了这种报文后包括sis001等网站就能正常返回页面而不会被reset了.

如果gfw要修补这种漏洞,我觉得其实可以直接匹配第一个遇到的"\nHost:",再匹配后面的域名就行了.

参考资料:
HTTP URL/深度关键词检测
翻墙路由器的原理与实现

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.