Browsed by
分类:编程语言

Unix考古记:一个“遗失”的shell

Unix考古记:一个“遗失”的shell

(感谢网友Leo投递此文)

谨以此文纪念伟大的计算机科学巨匠Ken ThompsonDennis Ritchie,并同时向其他所有为Unix发展做出贡献的黑客致敬。

历史的尘埃

Unix作为一个举世闻名的操作系统已有40余年的历史,围绕着这个古老的操作系统的发展又衍生出了一系列外围软件生态群,其中一个非常重要的组件就是shell。它是操作系统最外层的接口,负责直接面向用户交互并提供内核服务,包括命令行接口(CLI)或图形界面接口(GUI)两种形式。以CLI为例,它提供一套命令规范,是一种解释性语言,将用户输入经过解释器(interpreter)输出使其转化成真正的系统调用,实现人机交互的功能。

和操作系统一样,shell也经历了一个漫长的演变史。如今大部分资料讲述最古老的shell都是从1977年的Bourne Shell说起的,它最初移植到Unix V7上,被追认整个shell家族成员的鼻祖,后来的种群都是从其身上分支出来的。

Linux shells since 1977

对于1977年之前的历史很多资料大多一笔带过或略过不提。事实上,第一个移植到Unix上的shell却不是Steve Bourne写的,早在1975年5月,贝尔实验室就对外发布了第一个广泛传播的Unix版本——Unix V6(之前开发的版本只供内部研究之用),其根目录下的/bin/sh是第一个Unix自带的shell,由Ken Thompson写的,因此也被称为Thompson Shell。甚至,更早可以追溯到1971年的时候,Thompson Shell就作为一个独立于内核的应用程序而实现了,只不过从1975年正式问世到1977年被取代,短短两年的寿命使得它很少为大多数人所认识。

阅读全文 Read More

好烂啊有点差凑合看看还不错很精彩 (33 人打了分,平均分: 4.61 )
Loading...
实例分析Java Class的文件结构

实例分析Java Class的文件结构

【感谢网友 @Krq_Tiger 投稿】

今天把之前在Evernote中的笔记重新整理了一下,发上来供对java class 文件结构的有兴趣的同学参考一下。

学习Java的朋友应该都知道Java从刚开始的时候就打着平台无关性的旗号,说“一次编写,到处运行”,其实说到无关性,Java平台还有另外一个无关 性那就是语言无关性,要实现语言无关性,那么Java体系中的class的文件结构或者说是字节码就显得相当重要了,其实Java从刚开始的时候就有两套 规范,一个是Java语言规范,另外一个是Java虚拟机规范,Java语言规范只是规定了Java语言相关的约束以及规则,而虚拟机规范则才是真正从跨 平台的角度去设计的。今天我们就以一个实际的例子来看看,到底Java中一个Class文件对应的字节码应该是什么样子。 这篇文章将首先总体上阐述一下Class到底由哪些内容构成,然后再用一个实际的Java类入手去分析class的文件结构。

在继续之前,我们首先需要明确如下几点:

1)Class文件是有8个字节为基础的字节流构成的,这些字节流之间都严格按照规定的顺序排列,并且字节之间不存在任何空隙,对于超过8个字节的数据,将按 照Big-Endian的顺序存储的,也就是说高位字节存储在低的地址上面,而低位字节存储到高地址上面,其实这也是class文件要跨平台的关键,因为 PowerPC架构的处理采用Big-Endian的存储顺序,而x86系列的处理器则采用Little-Endian的存储顺序,因此为了Class文 件在各中处理器架构下保持统一的存储顺序,虚拟机规范必须对起进行统一。

2) Class文件结构采用类似C语言的结构体来存储数据的,主要有两类数据项,无符号数和表,无符号数用来表述数字,索引引用以及字符串等,比如 u1,u2,u4,u8分别代表1个字节,2个字节,4个字节,8个字节的无符号数,而表是有多个无符号数以及其它的表组成的复合结构。可能大家看到这里 对无符号数和表到底是上面也不是很清楚,不过不要紧,等下面实例的时候,我会再以实例来解释。

明确了上面的两点以后,我们接下来后来看看Class文件中按照严格的顺序排列的字节流都具体包含些什么数据:

阅读全文 Read More

好烂啊有点差凑合看看还不错很精彩 (28 人打了分,平均分: 4.29 )
Loading...
并发框架Disruptor译文

并发框架Disruptor译文

(感谢同事方腾飞投递本文)

Martin Fowler在自己网站上写了一篇LMAX架构的文章,在文章中他介绍了LMAX是一种新型零售金融交易平台,它能够以很低的延迟产生大量交易。这个系统是建立在JVM平台上,其核心是一个业务逻辑处理器,它能够在一个线程里每秒处理6百万订单。业务逻辑处理器完全是运行在内存中,使用事件源驱动方式。业务逻辑处理器的核心是Disruptor。

Disruptor它是一个开源的并发框架,并获得2011 Duke’s 程序框架创新奖,能够在无锁的情况下实现网络的Queue并发操作。本文是Disruptor官网中发布的文章的译文(现在被移到了GitHub)。

剖析Disruptor:为什么会这么快

Disruptor如何工作和使用

阅读全文 Read More

好烂啊有点差凑合看看还不错很精彩 (21 人打了分,平均分: 4.48 )
Loading...
Linus:利用二级指针删除单向链表

Linus:利用二级指针删除单向链表

感谢网友full_of_bull投递此文(注:此文最初发表在这个这里,我对原文后半段修改了许多,并加入了插图)

Linus大婶在slashdot上回答一些编程爱好者的提问,其中一个人问他什么样的代码是他所喜好的,大婶表述了自己一些观点之后,举了一个指针的例子,解释了什么才是core low-level coding

下面是Linus的教学原文及翻译——

“At the opposite end of the spectrum, I actually wish more people understood the really core low-level kind of coding. Not big, complex stuff like the lockless name lookup, but simply good use of pointers-to-pointers etc. For example, I’ve seen too many people who delete a singly-linked list entry by keeping track of the “prev” entry, and then to delete the entry, doing something like。(在这段话的最后,我实际上希望更多的人了解什么是真正的核心底层代码。这并不像无锁文件名查询(注:可能是git源码里的设计)那样庞大、复杂,只是仅仅像诸如使用二级指针那样简单的技术。例如,我见过很多人在删除一个单项链表的时候,维护了一个”prev”表项指针,然后删除当前表项,就像这样)”

if (prev)
    prev->next = entry->next;
else
    list_head = entry->next;

and whenever I see code like that, I just go “This person doesn’t understand pointers”. And it’s sadly quite common.(当我看到这样的代码时,我就会想“这个人不了解指针”。令人难过的是这太常见了。)

阅读全文 Read More

好烂啊有点差凑合看看还不错很精彩 (47 人打了分,平均分: 4.55 )
Loading...
Web工程师的工具箱

Web工程师的工具箱

Web Toolbox本文出自Ivan Zuzak 的《The Web engineer’s online toolbox》,作者给了一个各种可以用来进行开发、测试、调试以及文档编排的在线工具集。(注:我发现CSDN上已经有了这篇文章《Web工程师必备的18款工具》,但可惜的是这篇文章并不全(原文后来被更新到了33个工具),而且其中并没有包括原文评论中出现的所有工具,所以,我一并补全了更出来,一共40多个工具)

Web工程师在线工具箱

  • RequestBin允许你创建一个URL,利用这款工具进行收集请求,然后通过个性化方式进行检查。
  • HttpbinHTTP请求&响应服务,涵盖所有的HTTP方案(例如不同的HTTP verbs、状态代码和重定向)。类似工具:UrlEcho
  • REDbot这是一个机器人工具,帮助用户检查HTTP资源,可查看它的操作情况,指出常见的问题并提出改进。类似工具:HTTP lint
  • WebGun用于创建webhooks模板的API。类似工具:UrlReq
  • Webscript  自选一个url,填一段Lua代码,就能对访问做各种respond,还可以主动运行任务,cron job等等…

阅读全文 Read More

好烂啊有点差凑合看看还不错很精彩 (20 人打了分,平均分: 4.40 )
Loading...
如此理解面向对象编程

如此理解面向对象编程

从Rob Pike 的 Google+上的一个推看到了一篇叫《Understanding Object Oriented Programming》的文章,我先把这篇文章简述一下,然后再说说老牌黑客Rob Pike的评论。

先看这篇教程是怎么来讲述OOP的。它先给了下面这个问题,这个问题需要输出一段关于操作系统的文字:假设Unix很不错,Windows很差。

这个把下面这段代码描述成是Hacker Solution。(这帮人觉得下面这叫黑客?我估计这帮人真是没看过C语言的代码)

public class PrintOS
{
	public static void main(final String[] args)
	{
		String osName = System.getProperty("os.name") ;
		if (osName.equals("SunOS") || osName.equals("Linux"))
		{
			System.out.println("This is a UNIX box and therefore good.") ;
		}
		else if (osName.equals("Windows NT") || osName.equals("Windows 95"))
		{
			System.out.println("This is a Windows box and therefore bad.") ;
		}
		else
		{
			System.out.println("This is not a box.") ;
		}
	}
}

然后开始用面向对象的编程方式一步一步地进化这个代码。

先是以过程化的思路来重构之。

阅读全文 Read More

好烂啊有点差凑合看看还不错很精彩 (47 人打了分,平均分: 4.62 )
Loading...
程序员疫苗:代码注入

程序员疫苗:代码注入

几个月在我的微博上说过要建一个程序员疫苗网站,希望大家一起来提交一些错误示例的代码,来帮助我们新入行的程序员,不要让我们的程序员一代又一代的再重复地犯一些错误。很多程序上错误就像人类世界的病毒一样,我们应该给我们的新入行的程序员注射一些疫苗,就像给新生儿打疫苗一样,希望程序员从入行时就对这些错误有抵抗力。

我的那个疫苗网站正在建议中(不好意思拖了很久),不过,我可以先写一些关于程序员疫苗性质的文章,也算是热热身。希望大家喜欢,先向大家介绍第一注疫苗——代码注入。

Shell注入

我们先来看一段perl的代码:

use CGI qw(:standard);
$name = param('name');
$nslookup = "/path/to/nslookup";
print header;
if (open($fh, "$nslookup $name|")) {
    while (<$fh>) {
        print escapeHTML($_);
        print "<br>\n";
    }
    close($fh);
}

如果用户输入的参数是:

coolshell.cn%20%3B%20/bin/ls%20-l

那么,这段perl的程序就成了:

阅读全文 Read More

好烂啊有点差凑合看看还不错很精彩 (34 人打了分,平均分: 4.71 )
Loading...
如何测试洗牌程序

如何测试洗牌程序

我希望本文有助于你了解测试软件是一件很重要也是一件不简单的事。

我们有一个程序,叫ShuffleArray(),是用来洗牌的,我见过N多千变万化的ShuffleArray(),但是似乎从来没人去想过怎么去测试这个算法。所以,我在面试中我经常会问应聘者如何测试ShuffleArray(),没想到这个问题居然难倒了很多有多年编程经验的人。对于这类的问题,其实,测试程序可能比算法更难写,代码更多。而这个问题正好可以加强一下我在《我们需要专职的QA吗?》中我所推崇的——开发人员更适合做测试的观点。

我们先来看几个算法(第一个用递归二分随机抽牌,第二个比较偷机取巧,第三个比较通俗易懂

递归二分随机抽牌

有一次是有一个朋友做了一个网页版的扑克游戏,他用到的算法就是想模拟平时我们玩牌时用手洗牌的方式,是用递归+二分法,我说这个程序恐怕不对吧。他觉得挺对的,说测试了没有问题。他的程序大致如下(原来的是用Javascript写的,我在这里凭记忆用C复现一下):

//递归二分方法
const size_t MAXLEN = 10;
const char TestArr[MAXLEN] = {'A','B','C','D','E','F','G','H','I','J'};

static char RecurArr[MAXLEN]={0};
static int cnt = 0;
void ShuffleArray_Recursive_Tmp(char* arr, int len)
{
    if(cnt > MAXLEN || len <=0){
        return;
    }

    int pos = rand() % len;
    RecurArr[cnt++] = arr[pos];
    if (len==1) return;
    ShuffleArray_Recursive_Tmp(arr, pos);
    ShuffleArray_Recursive_Tmp(arr+pos+1, len-pos-1);
}

void ShuffleArray_Recursive(char* arr, int len)
{
    memset(RecurArr, 0, sizeof(RecurArr));
    cnt=0;
    ShuffleArray_Recursive_Tmp(arr, len);
    memcpy(arr, RecurArr, len);
}

void main()
{
    char temp[MAXLEN]={0};
    for(int i=0; i<5; i++) {
        strncpy(temp, TestArr, MAXLEN);
        ShuffleArray_Recursive((char*)temp, MAXLEN);
    }
}

阅读全文 Read More

好烂啊有点差凑合看看还不错很精彩 (24 人打了分,平均分: 4.71 )
Loading...
Go 语言简介(下)— 特性

Go 语言简介(下)— 特性

希望你看到这篇文章的时候还是在公交车和地铁上正在上下班的时间,我希望我的这篇文章可以让你利用这段时间了解一门语言。当然,希望你不会因为看我的文章而错过站。呵呵。

如果你还不了解Go语言的语法,还请你移步先看一下上篇——《Go语言简介(上):语法

goroutine

GoRoutine主要是使用go关键字来调用函数,你还可以使用匿名函数,如下所示:

阅读全文 Read More

好烂啊有点差凑合看看还不错很精彩 (23 人打了分,平均分: 4.61 )
Loading...
Go 语言简介(上)— 语法

Go 语言简介(上)— 语法

周末天气不好,只能宅在家里,于是就顺便看了一下Go语言,觉得比较有意思,所以写篇文章介绍一下。我想写一篇你可以在乘坐地铁或公交车上下班时就可以初步了解一门语言的文章。所以,下面的文章主要是以代码和注释为主。只需要你对C语言,Unix,Python有一点基础,我相信你会在30分钟左右读完并对Go语言有一些初步了解的。

Hello World

package main //声明本文件的package名

import "fmt" //import语言的fmt库——用于输出

func main() {
    fmt.Println("hello world")
}

阅读全文 Read More

好烂啊有点差凑合看看还不错很精彩 (22 人打了分,平均分: 4.77 )
Loading...