oracle 存储过程解题示例一

问题概述

某一个报表数据来自一个复杂业务的查询,其中某类资产的数据需要按百分比展示。同时这类资产的百分比总和加起来应该是100% 。问题比如这个分类是2,2,2 百分比是0.33,0.33,0.33 最终给出的结果是需要修正的即走后一条数据应该修正为0.34;同理的 如果是 1,2,3,1 的百分比计算也需要修正最后一条数据。当时的业务场景下只能用存储过程

问题简化解析

首先加一些简单的测试数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
-- Create table
create table OOTEST
(
id NVARCHAR2(16),
types NVARCHAR2(16),
shares NUMBER
)
insert into ootest (ID, TYPES, SHARES)
values ('1', 'aa', 1);
insert into ootest (ID, TYPES, SHARES)
values ('2', 'aa', 1);
insert into ootest (ID, TYPES, SHARES)
values ('3', 'aa', 1);
insert into ootest (ID, TYPES, SHARES)
values ('4', 'bb', 1);
insert into ootest (ID, TYPES, SHARES)
values ('5', 'bb', 2);
select t.id,t.types,t.shares, rowid from ootest t ;

eg:
| ID | TYPES | SHARES |
| ————- |:————-:| ——-:|
| 1 | aa | 1 |
| 2 | aa | 1 |
| 3 | aa | 1 |
| 4 | bb | 1 |
| 5 | bb | 2 |

存储过程实现 (Version 1.0)

初步想法需要搞个临时表,先筛选数据进去,再遍历修改,之后再查询临时表返回数据即可。为了简单实现这里就不用临时表了,直接查询,然后循环处理数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/*
---
--
-- 当过程中含有输出参数时,调用时必须通过BEGIN END块,不能通过EXEC或CALL调用。如:
DECLARE
retcode NUMBER(7,2);
retnote varchar(4000);
BEGIN
queryPercentOne(retcode,retnote,'aa');
DBMS_OUTPUT.PUT_LINE(retcode);
DBMS_OUTPUT.PUT_LINE(retnote);
END;
---
*/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
create or replace procedure queryPercentOne(o_code out int, o_msg out varchar2,v_types in varchar2) is
v_count number := 0; -- 总记录数
v_total number := 0;
v_last number := 0;
v_last_per number :=0;
v_cid NVARCHAR2(16);
v_ctypes NVARCHAR2(16);
v_cshares number;
v_rownum number :=0;
v_cpercent number(3,2) :=0.0;
v_percent number(3,2) :=0.0;
v_crownum number :=1;
CURSOR cur IS SELECT t.* FROM ootest t where t.types= v_types;
begin
begin
select count(*) into v_count from ootest t where t.types= v_types;
select sum(t.shares) into v_total from ootest t where t.types= v_types;
EXCEPTION WHEN NO_DATA_FOUND THEN
v_count :=0;
v_total :=0;
end ;
open cur;
LOOP
fetch cur into v_cid,v_ctypes,v_cshares ;
exit when cur%notfound;
v_cpercent := v_cshares/v_total;
if v_crownum = v_count then
v_cshares := v_total;
v_cpercent := (1 - v_percent);
else
v_percent := v_percent + (v_cshares/v_total);
end if ;
dbms_output.put_line(v_crownum||' . '||v_cid||' . '||v_ctypes||' . '||v_cshares||' .'|| to_char(v_cpercent,'0.99'));
v_crownum := v_crownum+1;
end LOOP;
o_code :=-1;
o_msg :='nothing';
end queryPercentOne;

测试存储过程

1
2
3
4
5
6
begin
-- Call the procedure
querypercentone(o_code => :o_code,
o_msg => :o_msg,
v_types => :v_types);
end;

测试 aa

1 . 1 . aa . 1 . 0.33
2 . 2 . aa . 1 . 0.33
3 . 3 . aa . 3 . 0.34

测试 bb

1 . 4 . bb . 1 . 0.33
2 . 5 . bb . 3 . 0.67

复杂SQL也可以做到 (Version2.0)

使用下列oracle自带函数

ratio_to_report

主要完成对百分比的计算,语法为
ratio_to_report(exp) over()
也就是根据over窗口函数的作用区间,求出作用区间中的单个值在整个区间的总值的比重

decode

decode(条件,值1,返回值1,值2,返回值2,…值n,返回值n,缺省值)

该函数的含义如下:
IF 条件=值1 THEN
    RETURN(翻译值1)
ELSIF 条件=值2 THEN
    RETURN(翻译值2)
    ……
ELSIF 条件=值n THEN
    RETURN(翻译值n)
ELSE
    RETURN(缺省值)
END IF

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
select d.id,
d.shares,
d.ratio,
d.cnt,
d.total,
decode(d.cnt, 1, d.tail_rt + d.rate, d.rate) rate,
d.tail_rt
from (select c.id,
c.shares,
c.ratio, -- 份额
c.total,
round(c.ratio, 4) rate, --占比
1 - sum(round(c.ratio, 4)) over() tail_rt, --尾差
row_number() over(partition by c.types order by c.id) cnt
from (select t.id,
t.shares,
t.types,
b.total,
ratio_to_report((t.shares)) OVER(partition by t.types) ratio
from ootest t
left join((select t.types, sum(t.shares) total
from ootest t
group by t.types) b)
on t.types = b.types
where t.types = 'bb') c) d;

Android 开发最佳实践

总结

使用 Gradle 和他推荐的工程结构

把密码和敏感数据放在 gradle.properties 配置文件中

使用 Jackson 库解析 JSON 数据

不要自己实现 Http client 使用 Volley 库或者 OkHttp 库

避免使用 Guava 库,由于 65k 方法限制使用其他少数库

在选择 Activities 和 Fragments 时特别小心

布局XML也是代码,请也好好组织编排

使用样式避免布局的XML中有重复多余的属性

使用多个样式文件避免单个大文件样式

保持你的颜色定义xml简短整洁,甚至定义一个调色板

Do not make a deep hierarchy of ViewGroups

避免客户端处理 WebViews 特别小心内存泄漏

使用 Robolectric 做单元测试,Robotium 做UI 测试

使用 Genymotion 作为你的模拟器

使用 ProGuard 或者 DexGuard

使用 SharedPreferences 做简单的持久化,否则使用 ContentProviders

使用 Stetho 调试你的应用

Android SDK

把你的Android SDK 放到你的Home目录或者应用的独立目录,不要和IDE放在一起,避免某些原因IDE升级或者重装导致长时间的SDK重新下载安装。

编译系统

你的默认编译工具应该是 Gradle

java jpda 远程调试

Java Platform Debugger Architecture(JPDA:Java平台调试架构) 由Java虚拟机后端和调试平台前端组成

对 执行java 或者java -jar 进行远程调试

添加 -agentlib:jdwp=transport=dt_socket,address=9000,server=y,suspend=n 即可

  • 注意一 transport=dt_socket 不可随意更改
  • 注意二 address 是端口,不是ip地址或者host地址

例子 java MainClass ,这里MainClass是要运行的class名字包括包名称

“C:\Program Files\Java\jdk1.6.0_45\bin\java.exe” \
-agentlib:jdwp=transport=dt_socket,address=9000,server=y,suspend=n \
-classpath .;”\E:\V1.0_ZJ\webmodel\otcp\cif\src\conf” \
“-Djava.ext.dirs=\E:\V1.0_ZJ\webmodel\otcp\cif\src\lib” MainClass
rem Listening for transport dt_socket at address: 9000
rem jpda program started

Tomcat 远程调试

不改文件进行远程调试,可以通过命令”catalia.bat jpda start”,用调试状态启动tomcat,


linux则是"./catalia.sh jpda start"。看catalia.bat 和 catalia.sh的区别,大致相同jpda参数是   

JPDA_TRANSPORT  (Optional) JPDA transport used when the "jpda start"   
                command is executed. The default is "dt_socket".   

JPDA_ADDRESS    (Optional) Java runtime options used when the "jpda start"   
                command is executed. The default is 8000.   

JPDA_SUSPEND    (Optional) Java runtime options used when the "jpda start"   
                command is executed. Specifies whether JVM should suspend   
                execution immediately after startup. Default is "n".

这里默认的jpda端口号为8000

E:\GIT\apache-tomcat-6.0.44\bin>start “Tomcat” “D:\Program Files\Java\jdk1.8.0_51\bin\java.exe” \
-Djava.util.logging.config.file=”E:\GIT\apache-tomcat-6.0.44\conf\logging.properties” \
-Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager \
-agentlib:jdwp=transport=dt_socket,address=8000,server=y,suspend=n \
-Djava.endorsed.dirs=”E:\GIT\apache-tomcat-6.0.44\endorsed” \
-classpath “E:\GIT\apache-tomcat-6.0.44\bin\bootstrap.jar” \
-Dcatalina.base=”E:\GIT\apache-tomcat-6.0.44”
-Dcatalina.home=”E:\GIT\apache-tomcat-6.0.44” \
-Djava.io.tmpdir=”E:\GIT\apache-tomcat-6.0.44\temp” \
org.apache.catalina.startup.Bootstrap start

Sun 官方文档说明

DESCRIPTION

The Java Debugger, jdb, is a simple command-line debugger for Java classes. It is a demonstration of the Java Platform Debugger Architecture that provides inspection and debugging of a local or remote Java Virtual Machine.

Starting a jdb Session

There are many ways to start a jdb session. The most frequently used way is to have jdb launch a new Java Virtual Machine (VM) with the main class of the application to be debugged. This is done by substituting the command jdb for java in the command line. For example, if your application’s main class is MyClass, you use the following command to debug it under JDB:

C:> jdb MyClass

When started this way, jdb invokes a second Java VM with any specified parameters, loads the specified class, and stops the VM before executing that class’s first instruction.

Another way to use jdb is by attaching it to a Java VM that is already running. A VM that is to be debugged with jdb must be started with the following options. These options load in-process debugging libraries and specify the kind of connection to be made.

-agentlib:jdwp=transport=dt_shmem,server=y,suspend=n

For example, the following command will run the MyClass application, and allow jdb to connect to it at a later time.

C:> java -agentlib:jdwp=transport=dt_shmem,address=jdbconn,server=y,suspend=n MyClass

You can then attach jdb to the VM with the following commmand:

C:> jdb -attach jdbconn

Note that “MyClass” is not specified in the jdb command line in this case because jdb is connecting to an existing VM instead of launching a new one.

There are many other ways to connect the debugger to a VM, and all of them are supported by jdb. The Java Platform Debugger Architecture has additional documentation on these connection options. For information on starting a J2SE 1.4.2 or early VM for use with jdb see 1.4.2 documentation

动手安装 Haskell koans 笔记

下载源代码

编译安装

1
2
cabal update
cabal build Setup.hs -v

报错了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Package has never been configured. Configuring with default flags. If this
fails, please run configure manually.
/usr/local/bin/ghc --numeric-version
looking for tool ghc-pkg near compiler in /usr/local/bin
found ghc-pkg in /usr/local/bin/ghc-pkg
/usr/local/bin/ghc-pkg --version
/usr/local/bin/ghc --supported-languages
/usr/local/bin/ghc --info
Reading available packages...
Choosing modular solver.
Resolving dependencies...
Could not resolve dependencies:
trying: HaskellKoans-0.1 (user goal)
next goal: testloop (dependency of HaskellKoans-0.1)
Dependency tree exhaustively searched.
Configuring HaskellKoans-0.1...
cabal: At least the following dependencies are missing:
HUnit -any,
attoparsec -any,
hspec -any,
mtl -any,
testloop -any,
text -any

缺少依赖,接着安装依赖

1
2
3
4
5
6
7
8
9
10
11
cabal install HUnit
Resolving dependencies...
Configuring HUnit-1.3.1.1...
Failed to install HUnit-1.3.1.1
Build log ( /root/.cabal/logs/HUnit-1.3.1.1.log ):
cabal: Error: some packages failed to install:
HUnit-1.3.1.1 failed during the configure step. The exception was:
user error ('/usr/local/bin/ghc' exited with an error:
/usr/bin/ld: cannot find -lgmp
collect2: ld returned 1 exit status
)

根据提示,缺少libgmp.so

1
2
3
4
5
6
7
8
9
10
11
12
gcc -lgmp --verbose
Using built-in specs.
Target: x86_64-redhat-linux
Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-bootstrap --enable-shared --enable-threads=posix --enable-checking=release --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-languages=c,c++,objc,obj-c++,java,fortran,ada --enable-java-awt=gtk --disable-dssi --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-1.5.0.0/jre --enable-libgcj-multifile --enable-java-maintainer-mode --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --disable-libjava-multilib --with-ppl --with-cloog --with-tune=generic --with-arch_32=i686 --build=x86_64-redhat-linux
Thread model: posix
gcc version 4.4.7 20120313 (Red Hat 4.4.7-17) (GCC)
COMPILER_PATH=/usr/libexec/gcc/x86_64-redhat-linux/4.4.7/:/usr/libexec/gcc/x86_64-redhat-linux/4.4.7/:/usr/libexec/gcc/x86_64-redhat-linux/:/usr/lib/gcc/x86_64-redhat-linux/4.4.7/:/usr/lib/gcc/x86_64-redhat-linux/:/usr/libexec/gcc/x86_64-redhat-linux/4.4.7/:/usr/libexec/gcc/x86_64-redhat-linux/:/usr/lib/gcc/x86_64-redhat-linux/4.4.7/:/usr/lib/gcc/x86_64-redhat-linux/
LIBRARY_PATH=/usr/lib/gcc/x86_64-redhat-linux/4.4.7/:/usr/lib/gcc/x86_64-redhat-linux/4.4.7/:/usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../lib64/:/lib/../lib64/:/usr/lib/../lib64/:/usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../:/lib/:/usr/lib/
COLLECT_GCC_OPTIONS='-v' '-mtune=generic'
/usr/libexec/gcc/x86_64-redhat-linux/4.4.7/collect2 --eh-frame-hdr --build-id -m elf_x86_64 --hash-style=gnu -dynamic-linker /lib64/ld-linux-x86-64.so.2 /usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../lib64/crt1.o /usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../lib64/crti.o /usr/lib/gcc/x86_64-redhat-linux/4.4.7/crtbegin.o -L/usr/lib/gcc/x86_64-redhat-linux/4.4.7 -L/usr/lib/gcc/x86_64-redhat-linux/4.4.7 -L/usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../lib64 -L/lib/../lib64 -L/usr/lib/../lib64 -L/usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../.. -lgmp -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/gcc/x86_64-redhat-linux/4.4.7/crtend.o /usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../lib64/crtn.o
/usr/bin/ld: cannot find -lgmp
collect2: ld returned 1 exit status

试着安装一下

1
2
3
4
5
6
7
8
9
10
11
12
yum -y install gmp
Failed to set locale, defaulting to C
Loaded plugins: fastestmirror, security
Setting up Install Process
Loading mirror speeds from cached hostfile
...
base | 3.7 kB 00:00
extras | 3.4 kB 00:00
nginx | 2.9 kB 00:00
updates | 3.4 kB 00:00
Package gmp-4.3.1-10.el6.x86_64 already installed and latest version
Nothing to do

貌似已经安装了

1
2
3
4
5
6
# find / -name libgmp.so*
/opt/gitlab/embedded/lib/engines/libgmp.so
/usr/lib64/libgmp.so.3.5.0
/usr/lib64/libgmp.so.3
/usr/lib64/openssl/engines/libgmp.so
/usr/lib64/libgmp.so.10

建立一个符号链接试试

1
2
ln -sv /usr/lib64/libgmp.so.3.5.0 /usr/lib64/libgmp.so
`/usr/lib64/libgmp.so' -> `/usr/lib64/libgmp.so.3.5.0'

在看看结果

1
2
3
4
5
6
7
ls -al /usr/lib64/libgmp*
lrwxrwxrwx. 1 root root 26 Aug 15 07:18 /usr/lib64/libgmp.so -> /usr/lib64/libgmp.so.3.5.0
lrwxrwxrwx. 1 root root 11 Jul 26 05:07 /usr/lib64/libgmp.so.10 -> libgmp.so.3
lrwxrwxrwx. 1 root root 15 Jun 21 01:58 /usr/lib64/libgmp.so.3 -> libgmp.so.3.5.0
-rwxr-xr-x. 1 root root 376792 Nov 18 2015 /usr/lib64/libgmp.so.3.5.0
lrwxrwxrwx. 1 root root 17 Jun 21 01:58 /usr/lib64/libgmpxx.so.4 -> libgmpxx.so.4.1.0
-rwxr-xr-x. 1 root root 17992 Nov 18 2015 /usr/lib64/libgmpxx.so.4.1.0

ldconfig

接着安装,竟然可以

1
2
3
4
5
cabal install HUnit
Resolving dependencies...
Configuring HUnit-1.3.1.1...
Building HUnit-1.3.1.1...
Installed HUnit-1.3.1.1

然后 testloop 编译不过去了

cabal install testloop
Resolving dependencies...
Configuring testloop-0.1.1.0...
Building testloop-0.1.1.0...
Failed to install testloop-0.1.1.0
Build log ( /root/.cabal/logs/testloop-0.1.1.0.log ):
Configuring testloop-0.1.1.0...
Building testloop-0.1.1.0...
Preprocessing library testloop-0.1.1.0...
[1 of 6] Compiling System.TestLoop.Internal.Signal ( src/System/TestLoop/Internal/Signal.hs, dist/build/System/TestLoop/Internal/Signal.o )
[2 of 6] Compiling System.TestLoop.Util ( src/System/TestLoop/Util.hs, dist/build/System/TestLoop/Util.o )
[3 of 6] Compiling System.TestLoop.Internal.Types ( src/System/TestLoop/Internal/Types.hs, dist/build/System/TestLoop/Internal/Types.o )
[4 of 6] Compiling System.TestLoop.Internal.Watcher ( src/System/TestLoop/Internal/Watcher.hs, dist/build/System/TestLoop/Internal/Watcher.o )
[5 of 6] Compiling System.TestLoop.Internal.Cabal ( src/System/TestLoop/Internal/Cabal.hs, dist/build/System/TestLoop/Internal/Cabal.o )
[6 of 6] Compiling System.TestLoop  ( src/System/TestLoop.hs, dist/build/System/TestLoop.o )

src/System/TestLoop.hs:47:23:
    Couldn't match type `FS.FilePath' with `[Char]'
    Expected type: FilePath
      Actual type: FS.FilePath
    In the second argument of `treeExtExists', namely
      `(FS.decodeString path)'
    In a stmt of a 'do' block:
      treeExtExists
        manager
        (FS.decodeString path)
        "hs"
        (reloadTestSuite moduleName modulePath paths)

src/System/TestLoop.hs:49:23:
    Couldn't match type `[Char]' with `FS.FilePath'
    Expected type: FilePath -> IO ()
      Actual type: FS.FilePath -> IO ()
    In the fourth argument of `treeExtExists', namely
      `(reloadTestSuite moduleName modulePath paths)'
    In a stmt of a 'do' block:
      treeExtExists
        manager
        (FS.decodeString path)
        "hs"
        (reloadTestSuite moduleName modulePath paths)
cabal: Error: some packages failed to install:
testloop-0.1.1.0 failed during the building phase. The exception was:
ExitFailure 1

awesome koans

awesome-koans

What is Kōan

Koan(公案)是佛教禅宗的术语,乃是佛教禅宗祖师的一段言行或者一个小故事,用于引导和开悟。

编程语言的学习也有一种公案形式的学习方法,是我见过的最好的学习一门新的编程语言的方式。以TDD的形式,预先编写好每一个知识点的测试代码,引导学习者使用相关的知识编写代码以通过测试。这种像闯关一样的形式让人充满的学习的动力,也解决了很多人学习过程中只有纸上谈兵而没有动手机会的问题。

这个Repo用于收集各种语言可用的koans方便学习。

AngularJS

https://github.com/bjpbakker/angular-koans

Bash

https://github.com/marcinbunsch/bash_koans

Clojure

https://github.com/lazerwalker/clojurescript-koans

Cpp

https://github.com/torbjoernk/CppKoans

ColdFusion

https://github.com/nodoherty/ColdFusion-Koans

CoffeeScript

https://github.com/sleepyfox/coffeescript-koans

CSharp

https://github.com/jtigger/csharp-koans

Dart

https://github.com/butlermatt/dart_koans

DotNet

https://github.com/CoryFoy/DotNetKoans

Elixir

https://github.com/elixirkoans/elixir-koans

Erlang

https://github.com/patrickgombert/erlang-koans

FSharp

https://github.com/ChrisMarinos/FSharpKoans

Go

https://github.com/cdarwin/go-koans

Groovy

https://github.com/nadavc/groovykoans

Haskell

https://github.com/HaskVan/HaskellKoans

Java

https://github.com/matyb/java-koans

Javascript

https://github.com/mrdavidlaing/javascript-koans

Kotlin

https://github.com/Kotlin/kotlin-koans

Lisp

https://github.com/google/lisp-koans

Lua

https://github.com/kikito/lua_missions

Objective-C

https://github.com/joecannatti/Objective-C-Koans

Perl

https://github.com/forcedotcom/PerlKoans

Prolog

https://github.com/araneforseti/prolog-koans

Python

https://github.com/gregmalcolm/python_koans

R

https://github.com/DASpringate/Rkoans

ReactJS

https://github.com/arkency/reactjs_koans

Ruby

http://rubykoans.com/

Scala

https://github.com/rubbish/scala-koans

Smalltalk

https://github.com/sl4m/gnu_smalltalk_koans

Swift

https://github.com/mokagio/Swift-Koans

BT种子嗅探器原理

前言

之前看到 lantern 这个十分火的翻墙工具,其利用了P2P的思想,就想了解一下P2P相关的协议。看了下最流行的BT协议官方文档,就产生了实现BT协议的想法,顺便根据协议实现了一个BT种子嗅探器。

也有人将BT种子嗅探器称为BT种子爬虫,个人觉得其行为特性和传统的web爬虫相差较大,反而和嗅探器很类似,因此暂且称之为BT种子嗅探器吧。

接下来将写一系列文章来介绍其原理和具体实现方式。这篇文章先提纲挈领,介绍其工作原理,以对全局有一个把握。后序的文章再介绍具体细节。

背景知识

在讲原理之前首先你得具备BitTorrent(简称BT)协议的一些基本知识,以便于理解接下来要讲的嗅探器。BT协议其实是一个协议簇,BEP-3 是其基本协议内容,其他的大部分都是围绕这个来进行扩展或补充。要想从BT网络中下载一个资源,必须具备以下部分:

种子文件(也就是我们常说的种子,后缀是 .torrent,本质上是一个由bencode编码的文本文件,其把资源分成很多虚拟块,并记录每个块的hash值,另外上面还记录着其他信息,比如文件大小、名字、Tracker服务器等)
BT客户端(需要有专门解析BT协议的程序,这样才能下载,比如迅雷,电驴)
Tracker服务器 (记录着peer和种子相关信息,起着中心调控的作用)
下载资源的时候,客户端首先根据bencode(bencode是BT协议中的编码方式)解码种子文件,得到Tracker服务器的地址和资源信息,通过和Tracker服务器沟通得到其他已经下载该资源的peers信息(其他已经拥有该资源的客户端或者发布该资源的人),然后再和这些peers沟通得到自己想要的部分,即互通有无。由于把文件分成很多块来同时从不同的地方下载,这也就是为什么BT通常下载快的原因。

DHT协议

通过上面我们知道,Tracker服务器在资源下载的过程中起着至关重要的作用,只有通过它我们才能得到其他peers的信息,才能够下载,但这同时也成了BT协议的一个弱点,如果Tracker服务器挂掉了或者被封被屏蔽,整个网络也就瘫痪了。由于一些资源都是有版权的,还有一些资源是限制级的,比如色情资源,Tracker服务器很容易被迫关闭或被墙。后来聪明的人类发明了另外一种协议,就是 Distributed hash table, 简称DHT,这个协议就是用来弥补这个弱点的。

BT协议簇中的DHT协议 是基于 Kademlia协议 建立的,其基本思想很好理解。DHT 由很多节点组成,每个节点保存一张表,表里边记录着自己的好友节点。当你向一个节点A查询另外一个节点B的信息的时候,A就会查询自己的好友表,如果里边包含B,那么A就返回B的信息,否则A就返回距离B距离最近的k个节点。然后你再向这k个节点再次查询B的信息,这样循环一直到查询到B的信息,查询到B的信息后你应该向之前所有查询过的节点发个通知,告诉他们,你有B的信息。

举个例子,比如我现在想要Angelababy的微信号(额…我要干嘛),我就从自己的微信好友中挑出k个最可能认识她的人,然后依次问他们有没有Angelababy的微信号,假如其中一个认识,那么他就会给我Angelababy的微信号,我也就不继续问其他人了。假如他不认识,他就给我推荐k个他微信好友中最有可能认识Angelababy的k个人,然后我再继续这k个人,就这样循环一直到我问到为止。OK,现在我已经得到了Angelababy的微信号,我就会告诉之前所有我问过的人,我有Angelababy的微信号。

当客户端下载资源的时候,他会利用上述方式查找peers信息,这样每个人都充当了Tracker的作用,也就解决了上面那个问题。

嗅探器原理

终于到核心部分了。

BT种子嗅探器就是利用了DHT协议得到peer信息后会向他之前查询过的节点发送通知这一点,这就是嗅探器的核心。

剩下的工作就是我们要让更多的节点发给我们通知。那么如何让更多的节点发给我们通知呢?

我们要不断的查询自己的好友节点表,并对返回回来的节点进行查询,这样才会有更多的人认识我们
别人向我们查询Target的时候,我们要伪装成Target的好友,返回结果里边包括自己,这样会有更多被查询、收到通知的机会
这就是BT种子嗅探器的原理,简单吧 :)

种子下载器

在BT网络中,通过上述原理收到信息并不是种子,而是发送消息者的ip和port、种子infohash(可以理解为种子的id)。我们如果想要得到种子的话,还需要做一番工作。这里涉及到另外一个非常重要的协议 BEP-09,BEP-09规定了如何通过种子infohash得到种子。

这里不铺开讲,仅说下大致过程。首先同我们收到的消息里边的 ip:port 建立TCP连接,然后发送握手消息,并告知对方自己支持BEP-09协议,然后向对方请求种子的信息,收到对方返回的种子信息后,依次或同时请求每一个块。最有所有块收集完后,对其进行拼接并通过sha1算法计算其infohash,如果和我们请求的infohash值相同则保存起来,否则丢掉。

应用

这样你可以得到非常多的种子信息,你可以对其进行索引建立自己的BT种子搜索引擎,建立自己的海盗湾。但你需要注意版权问题和色情资源问题。

BT种子嗅探器–DHT篇

背景知识

DHT全称 Distributed Hash Table,中文翻译过来就是分布式哈希表。它是一种去中心化的分布式系统,特点主要有自动去中心化,强大的容错能力,支持扩展。另外它规定了自己的架构,包括keyspace和overlay network(覆盖网络)两部分。但是他没有规定具体的算法细节,所以出现了很多不同的实现方式,比如Chord,Pastry,Kademlia等。BitTorrent中的DHT是基于Kademlia的一种变形,它的官方名称叫做 Mainline DHT。

DHT人如其名,把它看成一个整体,从远处看它,它就是一张哈希表,只不过这张表是分布式的,存在于很多机器上。它同时支持set(key, val),get(key)操作。DHT可以用于很多方面,比如分布式文件系统,DNS,即时消息(IM),以及我们最熟悉的点对点文件共享(比如BT协议)等。

下面我们提到的DHT默认都是Mainline DHT,例子都是用伪代码来表示。读下面段落的时候要时刻记着,DHT是一个哈希表。

Mainline DHT
Mainline DHT遵循DHT的架构,下面我们分别从Keyspace和Overlay network两方面具体说明。

Keyspace
keyspace主要是关于key的一些规定。

Mainline dht里边的key长度为160bit,注意是bit,不是byte。在常见的编译型编程语言中,最长的整型也才是64bit,所以用整型是表示不了key的,我们得想其他的方式。我们可以用数组方式表示它,数组类型你可以选用长度不同的整型,比如int8,int16,int32等。这里为了下边方便计算,我们采用长度为20的byte数组来表示。

在mainline dht中,key之间唯一的一种计算是xor,即异或(还记得异或的知识吧?)。我们的key是用长度为20的byte数组来表示,因此我们应该从前往后依次计算两个key的相对应的byte的异或值,最终结果得到的是另外一个长度为20的byte数组。算法如下:

1
2
3
​for i = 0; i < 20; i++ {
​ result[i] = key1[i] ^ key2[i];
​}

读到这里,你是不是要问xor有啥用?还记得原理篇中DHT的工作方式吗?

xor是为了找到好友表中离key最近的k个节点,什么样的节点最近?就是好友中每个节点和key相异或,得到的结果越小就越近。这里又衍生另外一个问题,byte数组之间怎么比较大小?很简单,从前往后,依次比较每一个byte的大小即可。

在Mainline DHT中,我们用160bit的key来代表每个节点和每个资源的ID,我们查找节点或者查找资源的时候实际上就是查找他们的ID。回想一下,这是不是很哈希表? :)

另外聪明的你可能又该问了,我们怎么样知道每个节点或者每个资源的ID是多少?在Mainline DHT中,节点的ID一般是随机生成的,而资源的ID是用sha1算法加密资源的内容后得到的。

OK,关于key就这么多,代码实现你可以查考这里。

Overlay network

Overlay network主要是关于DHT内部节点是怎么存储数据的,不同节点之间又是怎样通信的。

首先我们回顾一下原理篇中DHT的工作方式:

DHT 由很多节点组成,每个节点保存一张表,表里边记录着自己的好友节点。当你向一个节点A查询另外一个节点B的信息的时候,A就会查询自己的好友表,如果里边包含B,那么A就返回B的信息,否则A就返回距离B距离最近的k个节点。然后你再向这k个节点再次查询B的信息,这样循环一直到查询到B的信息,查询到B的信息后你应该向之前所有查询过的节点发个通知,告诉他们,你有B的信息。
整个DHT是一个哈希表,它把自己的数据化整为零分散在不同的节点里。OK,现在我们看下,一个节点内部是用什么样的数据结构存储数据的。

节点内部数据存储 - Routing Table
用什么样的数据结构得看支持什么样的操作,还得看各种操作的频繁程度。从上面工作方式我们知道,操作主要有两个:

在我(注意:“我”是一个节点)的好友节点中查询离一个key最近的k个节点(在Mainline DHT中,k=8),程度为频繁
把一个节点保存起来,也就是插入操作,程度为频繁
首先看到“最近”、“k”,我们会联想到top k问题。一个很straightforward的做法是,用一个数组保存节点。这样的话,我们看下算法复杂度。top k问题用堆解决,查询复杂度为O(k + (n-k)*log(k)),当k=8时,接近于O(n);插入操作为O(1)。注:n为一个节点的好友节点总数。

当n很大的时候,操作时间可能会很长。那么有没有O(log(n))的算法呢?

联想到上面堆的算法,你可能说,我们可以维护一个堆啊,插入和查询的时候都是O(log(n))。这种做法堆是根据堆中元素与某一个固定不变的key的距离来维护的,但是通常情况下,我们查询的key都是变化的,因此这种做法不可行。

那还有其他O(log(n))的算法吗?

经验告诉我们,很多O(log(n))的问题都和二叉树相关,比如各种平衡二叉树,我们能不能用二叉树来解决呢?联想到每个ID都是一个160bit的值,而且我们知道key之间的距离是通过异或来计算的,并且两个key的异或结果大小和他们的共同前缀无关,我们应该想到用Trie树(或者叫前缀树)来解决。事实上,Mainline DHT协议中用的就是Trie树,但是与Trie树又稍微有所不同。在Trie树里边,插入一个key时,我们要比对key的每一个char和Trie里边路径,当不一致时,会立刻分裂成一个子树。但是在这里,当不一致时,不会立刻分裂,而是有一个长度为k的buffer(在Mainline DHT中叫bucket)。分两种情况讨论:

如果bucket长度小于k,那么直接插入bucket就行了。
如果bucket长度大于或等于k,又要分两种情况讨论:
第一种情况是当前的路径是该节点ID(注意不是要插入的key,是“我”自己的ID)的前缀,那么就分裂,左右子树的key分别是0和1,并且把当前bucket中的节点根据他们的当前char值分到相应的子树的bucket里边。
第二种情况是当前路径不是该节点ID的前缀,这种情况下,直接把这个key丢掉。
如果还没有理解,你可以参照Kademlia这篇论文上面的图。

插入的时候,复杂度为O(log(n))。查询离key最近的k个节点时,我们可以先找到当前key对应的bucket,如果bucket里边不够k个,那么我们再查找该节点前驱和后继,最后根据他们与key的距离拍一下序即可,平均复杂度也为O(log(n))。这样插入和查询都是O(log(n))。

代码实现你可以查考这里。

节点之间的通信 - KRPC

KRPC比较简单,它是一个简单的rpc结构,其是通过UDP传送消息的,报文是由bencode编码的字典。它包含3种消息类型,request、response和error。请求又分为四种:ping,find_node, get_peers, announce_peer。

ping 用来侦探对方是否在线

find_node 用来查找某一个节点ID为Key的具体信息,信息里包括ip,port,ID
get_peers 用来查找某一个资源ID为Key的具体信息,信息里包含可提供下载该资源的ip:port列表
announce_peer 用来告诉别人自己可提供某一个资源的下载,让别人把这个消息保存起来。还记得Angelababy那个例子吗?在我得到她的微信号后,我会通知所有我之前问过的人,他们就会把我有Angelababy微信号这个信息保存起来,以后如果有人再问他们有没有Angelababy微信号的话,他们就会告诉那个人我有。BT种子嗅探器就是根据这个来得到消息的,不过得到消息后我们还需要进一步下载。
跳出节点,整体看DHT这个哈希表,find_node和get_peers就是我们之前说的get(key),announce_peer就是set(ke, val)。

剩下的就是具体的消息格式,你可以在官方文档上看到,这里就不搬砖了。

实现KRPC时,需要注意的有以下几点:

每次收到请求或者回复你都需要根据情况更新你的Routing Table,或保存或丢掉。
你需要实现transaction,transaction里边要包含你的请求信息以及被请求的ip及端口,只有这样当你收到回复消息时,你才能根据消息的transaction id做出正确的处理。Mainline DHT对于如何实现transaction没有做具体规定。
一开始你是不在DHT网络中的,你需要别人把你介绍进去,任何一个在DHT中的人都可以。一般我们可以向 router.bittorrent.com:6881、 dht.transmissionbt.com:6881 等发送find_node请求,然后我们的DHT就可以开始工作了。
KRPC的实现你可以参考这里。

总结

DHT整体就是一张哈希表,首先我们本身是里边的一个节点,我们向别人发送krpc find_node或get_peers消息,就是在对这个哈希表执行get(key)操作。向别人发送announce_peer消息,就是在对这个哈希表执行set(key, val)操作。

NodeBB 基于 nodejs实现的社区论坛

Node.js based forum software built for the modern web http://www.nodebb.org

NodeBB Forum Software is powered by Node.js and built on either a Redis or MongoDB database. It utilizes web sockets for instant interactions and real-time notifications. NodeBB has many modern features out of the box such as social network integration and streaming discussions, while still making sure to be compatible with older browsers.

Additional functionality is enabled through the use of third-party plugins.

NodeBB Dockerfile

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# The base image is the latest 4.x node (LTS) on jessie (debian)
# -onbuild will install the node dependencies found in the project package.json
# and copy its content in /usr/src/app, its WORKDIR
FROM node:4-onbuild
ENV NODE_ENV=production \
daemon=false \
silent=false
# nodebb setup will ask you for connection information to a redis (default), mongodb then run the forum
# nodebb upgrade is not included and might be desired
CMD node app --setup && npm start
# the default port for NodeBB is exposed outside the container
EXPOSE 4567

Example Forum user nodebb

区块链开发者社区
nodebb

ONLYOFFICE 协同办公

onlyOffice

Collaborative system for managing documents, projects, customer relations and emails in one place

  • 在线编辑文档
  • 客户关系管理
  • 邮件服务
  • 文档管理
  • 项目管理
  • ONLYOFFICE Community Server is a free open source collaborative system developed to manage documents, projects, customer relationship and email correspondence, all in one place.

  • Cross platform solution: Linux, Windows

  • Document management
  • Integration with Google Drive, Box, Dropbox, OneDrive, OwnCloud
  • File sharing
  • Document embedding
  • Access rights management
  • Customizable CRM
  • Web-to-lead form
  • Invoicing system
  • Project Management
  • Gantt Chart
  • Milestones, task dependencies and subtasks
  • Time tracking
  • Automated reports
  • Blogs, forums, polls, wiki
  • Calendar
  • Email Aggregator
  • People module (employee database)
  • Instant Messenger
  • Support of more than 20 languages

Running Docker Image

sudo docker run -i -t -d -p 80:80 onlyoffice/communityserver

This command will install ONLYOFFICE Community Server and all the dependencies it needs.

Configuring Docker Image

###Auto-restart

To make Docker auto-restart containers on reboot, please use the –restart=always in the docker run command:

sudo docker run -i -t -d -p 80:80 --restart=always onlyoffice/communityserver

Storing Data

All the data are stored in the specially-designated directories, data volumes, at the following location:

  • /var/log/onlyoffice for ONLYOFFICE Community Server logs
  • /var/www/onlyoffice/Data for ONLYOFFICE Community Server data
  • /var/lib/mysql for MySQL database data

To get access to your data from outside the container, you need to mount the volumes. It can be done by specifying the ‘-v’ option in the docker run command.

sudo docker run -i -t -d -p 80:80 \
    -v /app/onlyoffice/CommunityServer/logs:/var/log/onlyoffice  \
    -v /app/onlyoffice/CommunityServer/data:/var/www/onlyoffice/Data  \
    -v /app/onlyoffice/CommunityServer/mysql:/var/lib/mysql  onlyoffice/communityserver

Storing the data on the host machine allows you to easily update ONLYOFFICE once the new version is released without losing your data.

Using MySQL

ONLYOFFICE uses MySQL 5.5 to store its data.

By default the MySQL server is started internally. But you can easily configure the image to use an external MySQL database.

If you have an external MySQL server installed on your machine, execute the following command:

1
2
3
4
5
6
7
sudo docker run -i -t -d -p 80:80 -p 5222:5222 -p 443:443 \
-e MYSQL_SERVER_HOST="127.0.0.1" \
-e MYSQL_SERVER_PORT="3306" \
-e MYSQL_SERVER_DB_NAME="onlyoffice" \
-e MYSQL_SERVER_USER="usr_onlyoffice" \
-e MYSQL_SERVER_PASS="onlyoffice123" \
onlyoffice/communityserver

Running ONLYOFFICE Community Server on Different Port

To change the port, use the -p command. E.g.: to make your portal accessible via port 8080 execute the following command:

sudo docker run -i -t -d -p 8080:80 onlyoffice/communityserver

Exposing Additional Ports

The container ports to be exposed for incoming connections are the folloing:

  • 80 for plain HTTP
  • 443 when HTTPS is enabled (see below)
  • 5222 for XMPP-compatible instant messaging client (for ONLYOFFICE Talk correct work)

You can expose ports by specifying the ‘-p’ option in the docker run command.

sudo docker run -i -t -d -p 80:80  -p 443:443  -p 5222:5222   onlyoffice/communityserver

For outgoing connections you need to expose the following ports:

  • 80 for HTTP
  • 443 for HTTPS

Additional ports to be exposed for the mail client correct work:

  • 25 for SMTP
  • 465 for SMTPS
  • 143 for IMAP
  • 993 for IMAPS
  • 110 for POP3
  • 995 for POP3S

Running ONLYOFFICE Community Server using HTTPS

sudo docker run -i -t -d -p 80:80  -p 443:443 \
-v /app/onlyoffice/CommunityServer/data:/var/www/onlyoffice/Data  onlyoffice/communityserver

Access to the onlyoffice application can be secured using SSL so as to prevent unauthorized access. While a CA certified SSL certificate allows for verification of trust via the CA, a self signed certificates can also provide an equal level of trust verification as long as each client takes some additional steps to verify the identity of your website. Below the instructions on achieving this are provided.

To secure the application via SSL basically two things are needed:

  • Private key (.key)
  • SSL certificate (.crt)

So you need to create and install the following files:

/app/onlyoffice/CommunityServer/data/certs/onlyoffice.key
/app/onlyoffice/CommunityServer/data/certs/onlyoffice.crt

When using CA certified certificates, these files are provided to you by the CA. When using self-signed certificates you need to generate these files yourself. Skip the following section if you are have CA certified SSL certificates.

Generation of Self Signed Certificates

Generation of self-signed SSL certificates involves a simple 3 step procedure.

STEP 1: Create the server private key

1
openssl genrsa -out onlyoffice.key 2048

STEP 2: Create the certificate signing request (CSR)

1
openssl req -new -key onlyoffice.key -out onlyoffice.csr

STEP 3: Sign the certificate using the private key and CSR

1
openssl x509 -req -days 365 -in onlyoffice.csr -signkey onlyoffice.key -out onlyoffice.crt

You have now generated an SSL certificate that’s valid for 365 days.

Strengthening the server security

This section provides you with instructions to strengthen your server security.
To achieve this you need to generate stronger DHE parameters.

1
openssl dhparam -out dhparam.pem 2048

Installation of the SSL Certificates

Out of the four files generated above, you need to install the onlyoffice.key, onlyoffice.crt and dhparam.pem files at the onlyoffice server. The CSR file is not needed, but do make sure you safely backup the file (in case you ever need it again).

The default path that the onlyoffice application is configured to look for the SSL certificates is at /var/www/onlyoffice/Data/certs, this can however be changed using the SSL_KEY_PATH, SSL_CERTIFICATE_PATH and SSL_DHPARAM_PATH configuration options.

The /var/www/onlyoffice/Data/ path is the path of the data store, which means that you have to create a folder named certs inside /app/onlyoffice/CommunityServer/data/ and copy the files into it and as a measure of security you will update the permission on the onlyoffice.key file to only be readable by the owner.

1
2
3
4
5
mkdir -p /app/onlyoffice/CommunityServer/data/certs
cp onlyoffice.key /app/onlyoffice/CommunityServer/data/certs/
cp onlyoffice.crt /app/onlyoffice/CommunityServer/data/certs/
cp dhparam.pem /app/onlyoffice/CommunityServer/data/certs/
chmod 400 /app/onlyoffice/CommunityServer/data/certs/onlyoffice.key

You are now just one step away from having our application secured.

Available Configuration Parameters

Please refer the docker run command options for the --env-file flag where you can specify all required environment variables in a single file. This will save you from writing a potentially long docker run command.

Below is the complete list of parameters that can be set using environment variables.

  • ONLYOFFICE_HTTPS_HSTS_ENABLED: Advanced configuration option for turning off the HSTS configuration. Applicable only when SSL is in use. Defaults to true.
  • ONLYOFFICE_HTTPS_HSTS_MAXAGE: Advanced configuration option for setting the HSTS max-age in the onlyoffice nginx vHost configuration. Applicable only when SSL is in use. Defaults to 31536000.
  • SSL_CERTIFICATE_PATH: The path to the SSL certificate to use. Defaults to /var/www/onlyoffice/Data/certs/onlyoffice.crt.
  • SSL_KEY_PATH: The path to the SSL certificate’s private key. Defaults to /var/www/onlyoffice/Data/certs/onlyoffice.key.
  • SSL_DHPARAM_PATH: The path to the Diffie-Hellman parameter. Defaults to /var/www/onlyoffice/Data/certs/dhparam.pem.
  • SSL_VERIFY_CLIENT: Enable verification of client certificates using the CA_CERTIFICATES_PATH file. Defaults to false
  • MYSQL_SERVER_HOST: The IP address or the name of the host where the server is running.
  • MYSQL_SERVER_PORT: The port number.
  • MYSQL_SERVER_DB_NAME: The name of a MySQL database to be created on image startup.
  • MYSQL_SERVER_USER: The new user name with superuser permissions for the MySQL account.
  • MYSQL_SERVER_PASS: The password set for the MySQL account.

Installing ONLYOFFICE Community Server integrated with Document and Mail Servers

ONLYOFFICE Community Server is a part of ONLYOFFICE Community Edition that comprises also Document Server and Mail Server. To install them, follow these easy steps:

STEP 1: Create the ‘onlyoffice’ network.

1
docker network create --driver bridge onlyoffice

Than launch containers on it using the ‘docker run –net onlyoffice’ option:

STEP 1: Install ONLYOFFICE Document Server.

1
2
3
4
sudo docker run --net onlyoffice -i -t -d --restart=always --name onlyoffice-document-server \
true-v /app/onlyoffice/DocumentServer/data:/var/www/onlyoffice/Data \
true-v /app/onlyoffice/DocumentServer/logs:/var/log/onlyoffice \
trueonlyoffice/documentserver

STEP 2: Install ONLYOFFICE Mail Server.

For the mail server correct work you need to specify its hostname ‘yourdomain.com’.
To learn more, refer to the ONLYOFFICE Mail Server documentation.

1
2
3
4
5
6
7
8
sudo docker run --net onlyoffice --privileged -i -t -d --restart=always --name onlyoffice-mail-server \
true-p 25:25 -p 143:143 -p 587:587 \
true-v /app/onlyoffice/MailServer/data:/var/vmail \
true-v /app/onlyoffice/MailServer/data/certs:/etc/pki/tls/mailserver \
true-v /app/onlyoffice/MailServer/logs:/var/log \
true-v /app/onlyoffice/MailServer/mysql:/var/lib/mysql \
true-h yourdomain.com \
trueonlyoffice/mailserver

STEP 3: Install ONLYOFFICE Community Server

1
2
3
4
5
6
7
8
9
sudo docker run --net onlyoffice -i -t -d --restart=always --name onlyoffice-community-server \
true-p 80:80 -p 5222:5222 -p 443:443 \
true-v /app/onlyoffice/CommunityServer/data:/var/www/onlyoffice/Data \
true-v /app/onlyoffice/CommunityServer/mysql:/var/lib/mysql \
true-v /app/onlyoffice/CommunityServer/logs:/var/log/onlyoffice \
true-v /app/onlyoffice/DocumentServer/data:/var/www/onlyoffice/DocumentServerData \
true-e DOCUMENT_SERVER_PORT_80_TCP_ADDR=onlyoffice-document-server \
true-e MAIL_SERVER_DB_HOST=onlyoffice-mail-server \
trueonlyoffice/communityserver

Alternatively, you can use an automatic installation script to install the whole ONLYOFFICE Community Edition at once. For the mail server correct work you need to specify its hostname ‘yourdomain.com’.

STEP 1: Download the Community Edition Docker script file

1
wget http://download.onlyoffice.com/install/opensource-install.sh

STEP 2: Install ONLYOFFICE Community Edition executing the following command:

1
bash opensource-install.sh -md yourdomain.com

Or, use docker-compose. For the mail server correct work you need to specify its hostname ‘yourdomain.com’. Assuming you have docker-compose installed, execute the following command:

1
2
wget https://raw.githubusercontent.com/ONLYOFFICE/Docker-CommunityServer/master/docker-compose.yml
docker-compose up -d

Upgrading ONLYOFFICE Community Server

To upgrade to a newer release, please follow there easy steps:

STEP 1: Make sure that all the container volumes are mounted following the Storing Data section instructions:

sudo docker inspect --format='{{range $p,$conf:=.HostConfig.Binds}}{{$conf}};{{end}}' {{COMMUNITY_SERVER_ID}} 

where
stands for a container name or ID

STEP 2 Remove the current container
sudo docker rm -f

STEP 3 Remove the current image
sudo docker rmi -f $(sudo docker images | grep onlyoffice/communityserver | awk ‘{ print $3 }’)

STEP 4 Run the new image with the same map paths

sudo docker run -i -t -d -p 80:80 \
-v /app/onlyoffice/CommunityServer/logs:/var/log/onlyoffice  \
-v /app/onlyoffice/CommunityServer/data:/var/www/onlyoffice/Data  \
-v /app/onlyoffice/CommunityServer/mysql:/var/lib/mysql  onlyoffice/communityserver

Project Information

Official website: http://www.onlyoffice.org

Code repository: https://github.com/ONLYOFFICE/CommunityServer

docker hub 国内加速

DaoCloud 加速器是广受欢迎的 Docker 工具,解决了国内用户访问 Docker Hub 缓慢的问题。DaoCloud 加速器结合国内的 CDN 服务与协议层优化,成倍的提升了下载速度。

配置加速器

请先确定您的 Docker 版本在 1.8 及以上。
登陆加速器页面可以获取 mirror 地址。
配置好后,您可以像往常一样使用docker pull命令,在拉取 Docker Hub 镜像时会自动采用加速器的镜像服务。

Linux

自动配置 Docker 加速器

适用于 Ubuntu14.04、Debian、CentOS6 、CentOS7

1
curl -sSL https://get.daocloud.io/daotools/set_mirror.sh | sh -s http://aa62783f.m.daocloud.io

该脚本可以将 –registry-mirror 加入到你的 Docker 配置文件 /etc/default/docker 中。适用于 Ubuntu14.04、Debian、CentOS6 、CentOS7,其他版本可能有细微不同。更多详情请访问文档。

登陆后参考配置命令
此命令会帮助您配置 registry-mirror 并重启 Docker Daemon。

手动配置 Docker 加速器

适用于各种 Linux 发行版

您可以找到 Docker 配置文件,一般配置文件在

,在配置文件中的```DOCKER_OPTS```加入
1
CentOS 7 在 /lib/systemd/system/docker.service 中

–registry-mirror=加速地址

1
2
重启Docker,一般可以用下面命令重启

service docker restart
```

Telegram 一款开源简洁的IM

Telegram 的诞生

Telegram 是俄罗斯兄弟帕维尔·杜罗夫(Pavel Durov)与尼古拉·杜罗夫(Nikolai Durov)于2013年创建的,他们也是俄罗斯最大社交网站VKontakte的创始人。当VKontakte引发俄罗斯政府关注后,帕维尔逃离俄罗斯。当他与正与圣彼得堡家中与特警队对峙的兄弟尼古拉通话时,他想到了创建Telegram的主意。他说 :“我意识到,我没有与兄弟通信的安全方式,这就是Telegram诞生的初衷。

可能是最注重隐私的通讯应用

都说在互联网上的东西就枉谈隐私了,大多数人对信息安全的概念是很弱的。Telegram 官方明确表示自己的态度:大型互联网公司总是想方设法让公众相信一种观点,保护隐私就是隐藏自己的线上信息不让身边的人知道,而实际上与此同时将大量的用户个人数据以某种形式变卖。而 Telegram 要做的是切实避免这样的情况,技术上的细则可以在网页上看到相关详尽的解说。

当然这些响亮的名号在日常使用中并不能轻易体验到,抛开技术层面的说明不谈,光是其悬赏 30 万美元给能够黑进应用的人,且至今无人能破这一点,也值得人对其报以关注。此外,用户还可以设置在一定时间内不登陆则自动销毁账号和一切信息,不费吹灰之力斩断后顾之忧;陌生人之间可以通过搜索 Username 进行临时会话,而不必暴露电话号码,只有主动共享手机号后才会添加进通讯录。

比起其他应用,Telegram 的会话选项多样,除正常会话和刚才提到的陌生人临时会话以外,还有私密会话。在此会话中可以对信息设置阅后即焚计时器,自定义多少时间后销毁信息,尤其是就算对方截屏了应用也会自动提醒这事,简直和微信「对方撤回一条信息」一样温暖人心。
telegram