2009年12月24日星期四

Writing is for Thinking Better (转)

GT的Google Reader shared items 中总有一些很好的博客、网站链接,今天又发现了一个——Mind hacks (http://mindhacks.cn/).该博客中有许多有关学习和思维方法的文章,读了几篇感觉很受益。

在《书写是为了更好的思考》一文中,作者阐述了书写对于思考的帮助。正如作者所说:“很多人不书写的原因是觉得没有什么可写的”,可是“你越是不开始书写,总是拿有限的思维缓存去默想一个问题,就越是没有内容可以写,如果你逼着自己将一些不成熟的想法写下来,看着自己写的内容,试着进一步拓展它们,就有可能在理性的道路上走得很远,很远”

书写是为了更好的思考

“我经常在走路和睡前总结所学过的内容,思考遗留的问题,一段时间的阅读和思考之后,一个总体的知识框架就会逐渐浮现在脑海中。然后我会将它书写下来,然而,我往往非常惊讶地发现,当我书写的时候,新的内容仍然源源不断的冒出来,就像我的键盘自己也会思考一样。

……
书写的好处有以下几点:

* 书写是对思维的备忘:……
* 书写是与自己的对话:……
* 书写是与别人的交流:……
* 有时候,语言自己也会思考:……


在开始书写你的想法之前,我知道很多人不书写的原因是因为觉得没有什么可写的,其实这是一个怪圈,你越是不开始书写,总是拿有限的思维缓存去默想一个问题,就越是没有内容可以写,如果你逼着自己将一些不成熟的想法写下来,看着自己写的内容,试着进一步拓展它们,就有可能在理性的道路上走得很远,很远。
……

2009年12月18日星期五

make again after modifying ns-lib.tcl

Using ns, you should make again after modifying "ns-lib.tcl";otherwise, your modification with ns-lib.tcl will not be effective.

2009年12月11日星期五

NS2 2.31(2) 重新编译问题 make error with “proxytrace2any.cc”(转)

NS2 2.32 make error with “proxytrace2any.cc”

Problem: NS2 2.32 make error with “proxytrace2any.cc”
proxytrace2any.cc: In function `int main(int, char**)':
proxytrace2any.cc:112: error: `IsLittleEndian' undeclared (first use this function)
proxytrace2any.cc:112: error: (Each undeclared identifier is reported only once for each function it appears in.)
proxytrace2any.cc:120: error: `ToOtherEndian' undeclared (first use this function)


Solution:
Modify file “ns-allinone-2.32/ns-2.32/indep-utils/webtrace-conv/dec/my-endian.h”

-#ifndef _ENDIAN_H_
-#define _ENDIAN_H_
+#ifndef _MY_ENDIAN_H_
+#define _MY_ENDIAN_H_

note:- remove
+ add

2009年12月9日星期三

一个NS2脚本的注释

一个NS2脚本的注释

NS2源码图示---数据链路层

NS2源码图示---数据链路层

NS2源码图示---物理层

NS2源码图示---物理层

NS2中数据包Packet的分析

NS2中数据包Packet的分析

注:从GTT的博客上发现该博客,几篇关于ns2的文章都不错,为方便查找把链接都贴在此处。遗憾的是该博客最近没有相关更新了

2009年12月4日星期五

What makes a good PhD student?--《Nature》

What makes a good PhD student?

Doing a PhD should be fun and rewarding, because you can spend all your working time discovering things and pursuing ideas — and getting paid for it, without any administrative responsibilities. Those who stick with a career in science do so because, despite the relatively poor pay, long hours and lack of security, it is all we want to do.
Unfortunately most new PhD students are ill-prepared, and as a consequence very few will fulfil their aspirations to be independent scientists. The main reasons for this are the ‘grade creep’ inherent at most universities, making it difficult to identify the really talented first-class graduates from the rest, and the
pressure on universities to graduate as many PhD students as possible. The consequence is that we enrol far too many of them without telling them clearly what doing a doctorate should entail. We therefore set ourselves, and the students, on a path of frustration and disappointment. So what should we be telling
prospective PhD students?
●Choose a supervisor whose work you admire and who is well supported by grants and departmental infrastructure.
●Take responsibility for your project.
●Work hard — long days all week and part of most weekends. If research is your passion this should be easy, and if it isn’t, you are probably in the wrong field. Note who goes home with a full briefcase to work on at the end of the day. This is a cause of success, not a consequence.
●Take some weekends off, and decent holidays, so you don’t burn out.
●Read the literature in your immediate area, both current and past, and around
it. You can’t possibly make an original contribution to the literature unless you
know what is already there.
●Plan your days and weeks carefully to dovetail experiments so that you have a
minimum amount of downtime.
●Keep a good lab book and write it up every day.
●Be creative. Think about what you are doing and why, and look for better ways to go. Don’t see your PhD as just a road map laid out by your supervisor.
●Develop good writing skills: they will make your scientific career immeasurably easier.
●To be successful you must be at least four of the following: smart, motivated,
creative, hard-working, skilful and lucky.
You can’t depend on luck, so you had better focus on the others!


Georgia Chenevix-Trench is principal research fellow at the Queensland
Institute of Medical Research, Royal Brisbane Hospital, Herston, Australia.
www.qimr.edu.au/research/labs/georgiat/Guideforphds.doc

2009年12月2日星期三

Ns Pkt 处理过程(

1. NS的整体的实现
固定网络的仿真是通过下面三层合作来实现的。

Application这个层是实现数据流的层次。Agent这个层是实现所有各层协议的的层次。Node这个部分由多个分类器(Classifier)实现了所有接收数据包进行判断是否进行转发或接收到Agent的部分。Link实现了队列、时延、Agent、记录Trace等一系列的仿真问题。

2. TclObject

Handler

ParentNode

Process

NsObject

Node

Application

Connector

Classifier

Delay

Queue

Agent

Trace

AddressClassifier

图表 2 NS内部类的继承关系图

NS内部类的继承关系

此图为NS内部类的继承关系,可以看出一些类是由那些类继承来的,这样相同的属性调用的函数就可以很方便的找到出处

3. NS中函数调用的分层

在用gdb跟踪NS发送一个cbr数据包的过程可以看到一下顺序:

CBR_Traffic::start

TrafficGenerator::timeout

Application::send

UdpAgent::sendmsg

Classifier::recv

Connect::recv

Connect::send

Trace::recv 写一条数据包加入队列的记录

Connector::send

Queue::recv

DropTail::enque

DequeTrace::recv 写一条数据包弹出队列的记录

Connector::send

LinkDelay::recv 插入事件到scheduler

Scheduler::dispatch

Scheduler::run

从上面的顺序可以看出,数据包在发送以后先通过应用层(Application::send)进行发送;然后通过Agent层(UdpAgent::sendmsg),UdpAgent是在初始化Agent的时候确定的。UdpAgent还有一个作用是生成相应的数据包;然后进入Node部分的分类器Classifier(Classifier::recv),通过find()函数返回下一跳地址。这个函数是通过读取 Packet的内容得到下一跳地址的,返回给recv函数后调用node->recv()进入connector;经过 connector::recv和connector::send后确定数据包可发,进入Trace::recv,记录这个数据包加入队列的记录;之后通过connector::send,进入Queue::recv函数,将数据包正式加入发送队列,再根据已经设定好的方法确定加入队列是否成功,是否要被丢弃;再调用DequeTrace::recv记录数据包弹出队列的记录;再通过connector::send进入LinkDelay::recv,先判断目的节点是否可达,根据不同的结果将事件写入scheduler,等待按序执行。

上述的过程只是一个数据包从生成到发送出去的过程,因为NS是一个根据一个一个离散事件调度执行的,后面的过程用gdb跟不进去。但可以看出,数据包是发送给下一跳节点,可知数据包是通过每个中间节点的。

4. NS中主要函数的分析

4.1. CBR数据源

开始从下面函数进入CBR数据源发送:

void CBR_Traffic::start()

{

init(); //初始化

running_ = 1;

timeout(); //进入发送数据的循环

}

void TrafficGenerator::timeout()

{

if (! running_) //判断是否要发送数据

return;

/* send a packet */

send(size_); //发送一个设定好大小的数据包

/* figure out when to send the next one */

nextPkttime_ = next_interval(size_);

/* schedule it */

if (nextPkttime_ > 0)

timer_.resched(nextPkttime_);

else

running_ = 0;

}

4.2. 中间几个函数只是体现分层

void Application::send(int nbytes)

{

agent_->sendmsg(nbytes);

}

void Agent::sendmsg(int /*sz*/, AppData* /*data*/, const char* /*flags*/)

{

fprintf(stderr,

"Agent::sendmsg(int, AppData*, const char*) not implemented\n");

abort();

}

上述两个函数其实并没有什么实质的操作,只是这样可以看出其经过了应用层和Agent层。

4.3. Classifier的函数

void Classifier::recv(Packet* p, Handler*h)

{

NsObject* node = find(p); //查找目的节点

if (node == NULL) { //只要返回了目的节点就调用节点的recv函数

/*

* 这个将被丢弃,不用记录在trace文件中

*/

Packet::free(p);

return;

}

node->recv(p,h);

}

NsObject* Classifier::find(Packet* p)

{

NsObject* node = NULL;

int cl = classify(p); //根据发送的packet的记录找到slot

if (cl < 0 || cl >= nslot_ || (node = slot_[cl]) == 0) { //根据slot得到下一跳node

if (default_target_)

return default_target_;

/*

* 不能将数据包发送出去,因为返回结果不是一个对象.

*/

Tcl::instance().evalf("%s no-slot %ld", name(), cl);

if (cl == TWICE) {

/*

* Try again. Maybe callback patched up the table.

*/

cl = classify(p);

if (cl < 0 || cl >= nslot_ || (node = slot_[cl]) == 0)

return (NULL);

}

}

return (node); //返回给classifier::recv得到的node的值

}

这个地址分类器就是根据数据包的内容,通过偏移查找接收的节点,然后调用接收节点的recv函数。而find函数是根据数据包的内容得到slot的值从而查询出谁是接收方的node。

4.4. Connector的函数

void Connector::recv(Packet* p, Handler* h)

{

send(p, h);

}

inline void send(Packet* p, Handler* h) { target_->recv(p, h); }

connector的recv和send函数是一个接口。这个函数中最重要的是target_这个值,这个值的不同会不同的调用Trace::recv、Queue::recv、LinkDelay::recv等等,但是这个值在那确定还没有看出来。

4.5. Queue的函数

void Queue::recv(Packet* p, Handler*)

{

double now = Scheduler::instance().clock();

enque(p); //根据规定的规则加入队列

if (!blocked_) {

/*

* 这里没有堵塞. 将一个数据包发送出去.

* 我们执行一个附加的检查,因为这个队列可能丢弃这个数据包

* 即使它前面是空的。 (例如, RED队列就可能发生.)

*/

p = deque();

if (p != 0) {

utilUpdate(last_change_, now, blocked_);

last_change_ = now;

blocked_ = 1;

target_->recv(p, &qh_); //调用dequetrace

}

}

}

Queue::recv这个函数调用DropTail规则将数据包加入队列,然后判断是否堵塞,如果没有则发送一个数据包,之前判断是认定这个包是否要被发送出去。这里也使用了target_->recv(),这里调用的是DequeTrace::recv函数,将记录一个数据包出队列的记录。

4.6. LinkDelay的函数

void LinkDelay::recv(Packet* p, Handler* h)

{

double txt = txtime(p);

Scheduler& s = Scheduler::instance();

if (dynamic_) { //这个是动态链路的标志,判断这个值确定链路是否为动态链

Event* e = (Event*)p;

e->time_= txt + delay_;

itq_->enque(p); // 用一个队列来储存数据包

s.schedule(this, p, txt + delay_);

} else if (avoidReordering_) {

// 预防重新安排带宽或时延改变

double now_ = Scheduler::instance().clock();

if (txt + delay_ < latest_time_ - now_ && latest_time_ > 0) {

latest_time_+=txt;

s.schedule(target_, p, latest_time_ - now_ );//在schedule里面加入事件

} else {

latest_time_ = now_ + txt + delay_;

s.schedule(target_, p, txt + delay_); //在schedule里面加入事件

}

} else {

s.schedule(target_, p, txt + delay_); //在schedule里面加入事件

}

s.schedule(h, &intr_, txt); //在schedule里面加入事件

}

这个函数非常重要,这个是数据包最后离开这个节点的出口,由这个函数写一个事件加入schedule,在一定的时间后调用。

s.schedule(target_, p, txt)这个的含义是在txt的时间以后调用target_的事件,处理p这个数据包。


你可以通过这个链接引用该篇文章:http://naonaoruby.bokee.com/tb.b?diaryId=11857286

http://naonaoruby.bokee.com/viewdiary.11857286.html

bzero & memset

bzero
--------------
NAME
bzero - memory operations (LEGACY)

SYNOPSIS
#include "<"strings.h">"
void bzero(void *s, size_t n);

DESCRIPTION
The bzero() function shall place n zero-valued bytes in the area pointed to by s.

RETURN VALUE
The bzero() function shall not return a value.

ERRORS
No errors are defined.
===============================================================

memset
-----------------------
NAME

memset - set bytes in memory

SYNOPSIS

#include "<"string.h">"

void *memset(void *s, int c, size_t n);

DESCRIPTION

The functionality described on this reference page is aligned with the ISO C standard. Any conflict between the requirements described here and the ISO C standard is unintentional. This volume of IEEE Std 1003.1-2001 defers to the ISO C standard.

The memset() function shall copy c (converted to an unsigned char) into each of the first n bytes of the object pointed to by s.

RETURN VALUE

The memset() function shall return s; no return value is reserved to indicate an error.

ERRORS

No errors are defined.
--------------------------------
memset

void * memset ( void * ptr, int value, size_t num );

Fill block of memory
Sets the first num bytes of the block of memory pointed by ptr to the specified value (interpreted as an unsigned char).

Parameters
ptr
Pointer to the block of memory to fill.
value
Value to be set. The value is passed as an int, but the function fills the block of memory using the unsigned char conversion of this value.
num
Number of bytes to be set to the value.



Return Value
ptr is returned.

Example

/* memset example */
#include "<"stdio.h">"
#include "<"string.h">"

int main ()
{
char str[] = "almost every programmer should know memset!";
memset (str,'-',6);
puts (str);
return 0;
}



Output:


------ every programmer should know memset!