一、英语学习
1、【每日一句英语】
If you look the right way, you can see that the whole world is a garden.
如果欣赏的角度对了,整个世界都是花园。
2、阅读BBC新闻
词汇积累
a sore throat | 嗓子疼 |
blocked nose | 鼻塞 |
soldier on | 坚持干活 |
perk somebody up | 使某人精神振作 |
duvet day | 休假日 |
sniffle | 流鼻涕,吸鼻子 |
at death’s door | 病入膏肓 |
sickie | 假病假,称病缺勤 |
migraine | 偏头疼 |
common cold | 感冒 |
symptom | 症状 |
germ | 病菌 |
catch a cold | 患感冒 |
recuperate | 恢复,康复 |
under the weather | 生病 |
cure | 治疗方法 |
lurgy | 小病 |
not to be sneezed at | 不可轻视的 |
二、ONE仿真平台学习
今天主要学习了DirectDelivery路由,首先,该路由继承了父类ActiveRouter,所以顺带了解了ActiveRouter类的代码结构,以下是今天学习的总结:
2.1 DirectDeliveryRouter代码:
package routing;
import core.Settings;
/**
* Router that will deliver messages only to the final recipient.
*/
public class DirectDeliveryRouter extends ActiveRouter {
public DirectDeliveryRouter(Settings s) {
super(s);
}
protected DirectDeliveryRouter(DirectDeliveryRouter r) {
super(r);
}
@Override
public void update() {
super.update();
//判断能否进行传输
if (isTransferring() || !canStartTransfer()) {
return; // can't start a new transfer
}
// Try only the messages that can be delivered to final recipient
//只尝试可以传递给最终目的节点
//若有目的节点就在本节点或者邻居节点的消息
if (exchangeDeliverableMessages() != null) {
return; // started a transfer
}
}
@Override
public DirectDeliveryRouter replicate() {
return new DirectDeliveryRouter(this);
}
}
DirectDelivery
路由策略很简单,每个节点携带自创建的消息,不断移动,直到遇到目的节点,才把消息传递出去,整个通信过程从不借助其他节点。这点方法优点很明显,开销是最低的,但缺点也很明显,效率是最低的。这里要学习三个函数,分别是:isTransferring()
、canStartTransfer()
、exchangeDeliverableMessages()
。
2.2 ActiveRouter主要做5件事,其源码如下:
@Override
public void update() {
//调用MessageRouter的update()
super.update();
/* in theory we can have multiple sending connections even though
currently all routers allow only one concurrent sending connection
理论上,我们可以有多个发送连接,尽管目前所有路由器都只允许一个并发发送连接
*/
for (int i=0; i<this.sendingConnections.size(); ) {
boolean removeCurrent = false;
Connection con = sendingConnections.get(i);
/* finalize ready transfers 1. 处理已完成传输的数据包 */
if (con.isMessageTransferred()) {
if (con.getMessage() != null) {
transferDone(con);
con.finalizeTransfer();
} /* else: some other entity aborted transfer */
removeCurrent = true;
}
/* remove connections that have gone down 2. 中止那些断开链路上的数据包 */
else if (!con.isUp()) {
if (con.getMessage() != null) {
transferAborted(con);
con.abortTransfer();
}
removeCurrent = true;
}
// 3. 必要时,删除那些最早接收到且不正在传输的消息
if (removeCurrent) {
// if the message being sent was holding excess buffer, free it
if (this.getFreeBufferSize() < 0) {
this.makeRoomForMessage(0);
}
sendingConnections.remove(i);
}
else {
/* index increase needed only if nothing was removed */
i++;
}
}
/* time to do a TTL check and drop old messages? Only if not sending 4. 丢弃那些TTL到期的数据包(只在没有消息发送的情况) */
if (SimClock.getTime() - lastTtlCheck >= TTL_CHECK_INTERVAL &&
sendingConnections.size() == 0) {
dropExpiredMessages();
lastTtlCheck = SimClock.getTime();
}
/* 5. 更新能量模板 */
if (energy != null) {
/* TODO: add support for other interfaces */
NetworkInterface iface = getHost().getInterface(1);
energy.update(iface, getHost().getComBus());
}
}
由上可见,ActiveRouter.update
主要做以下5件事:
- 处理已完成传输的数据包
- 中止那些断开链路上的数据包
- 必要时,删除那些最早接收到且不正在传输的消息
- 丢弃那些TTL到期的数据包(只在没有消息发送的情况)
- 更新能量模板
2.3 isTransferring()和canStartTransfer()
判断该节点能否进行传输消息,存在以下情况一种以上的,直接返回,不更新:
- 本节点正在传输,
sendingConnections.size() > 0
- 没有邻居节点,即没有节点与之建立连接,
connections.size() == 0
- 有邻居节点,但有链路正在传输(想想无线信道),
!con.isReadyForTransfer()
- 缓冲区没有消息,
this.getNrofMessages() == 0
2.3.1
isTransferring()
isTransferring()函数覆盖了以上前三种情况,其源代码如下:
/**
* Returns true if this router is transferring something at the moment or
* some transfer has not been finalized.
* @return true if this router is transferring something
* 判断该节点能否进行传输消息
*
*/
public boolean isTransferring() {
//情形1:本节点正在传输
if (this.sendingConnections.size() > 0) {
return true; // sending something
}
List<Connection> connections = getConnections();
//情型2:没有邻居节点
if (connections.size() == 0) {
return false; // not connected
}
//情型3:有邻居节点,但有链路正在传输
// 只有当与邻居相连的所有链路都是空闲的,才能传输
for (int i=0, n=connections.size(); i<n; i++) {
Connection con = connections.get(i);
if (!con.isReadyForTransfer()) {
// 一条链路能用于传输需要同时满足两个条件:其一,该链路是建立的;其二,该链路是空闲的。
return true; // a connection isn't ready for new transfer
}
}
return false;
}
值得注意的是,只有当与邻居相连的所有链路都是空闲的,才能传输,这是因为无线的传输介质是广播的。而且每次传输只能有一个
connection
进行传输,可见The ONE仿真了无线信道,但其他没法收到这个广播包。判断链路是否空闲
The ONE的链路用
Connection
类表示,一条链路能用于传输需要同时满足两个条件:其一,该链路是建立的;其二,该链路是空闲的。相关成员变量如下:
//Connection.java
private boolean isUp; //连接是否建立
protected Message msgOnFly; //连接是否被占用
public boolean isReadyForTransfer() {
return this.isUp && this.msgOnFly == null;
}
2.3.2 canStartTransfer()
canStartTransfer
判断该节点能否开始传输,缓冲区有消息,并且有邻居节点,才返回真。源代码如下:
/**
* Makes rudimentary checks (that we have at least one message and one
* connection) about can this router start transfer.
* @return True if router can start transfer, false if not
* 判断该节点能否开始传输,缓冲区有消息,并且有邻居节点,才返回真。
*/
protected boolean canStartTransfer() {
if (this.getNrofMessages() == 0) {//缓冲区空
return false;
}
if (this.getConnections().size() == 0) {//没有连接建立,即没有邻居节点
return false;
}
//不符合上述两个情况 返回真 即可以开始传输
return true;
}
2.4 exchangeDeliverableMessages()
exchangeDeliverableMessages
用于交换该节点与邻居节点间的消息,这些消息的目的节点是该节点或者其邻居节点。值得注意的是:该节点可能会有多个邻居节点(The ONE表示为多个connection
),但只能让一个connection
传输数据,想想无线信道。所以,只有有一个消息能传输到目的节点,就返回。exchangeDeliverableMessages
先看本节点是否有消息的某个邻居节点,如果没有,再查看邻居节点是否有消息的目的节点是本节点。其源代码如下:
/**
* Exchanges deliverable (to final recipient) messages between this host
* and all hosts this host is currently connected to. First all messages
* from this host are checked and then all other hosts are asked for
* messages to this host. If a transfer is started, the search ends.
* @return A connection that started a transfer or null if no transfer
* was started
* 用于交换该节点与邻居节点间的消息,这些消息的目的节点是该节点或者其邻居节点。
* 值得注意的是:该节点可能会有多个邻居节点(The ONE表示为多个connection),
* 但只能让一个connection传输数据,想想无线信道。所以,只有有一个消息能传输到目的节点,就返回。
*
* exchangeDeliverableMessages先看本节点是否有消息的某个邻居节点,如果没有,再查看邻居节点是否有消息的目的节点是本节点。
*/
protected Connection exchangeDeliverableMessages() {
List<Connection> connections = getConnections();
if (connections.size() == 0) {
return null;
}
//getMessagesForConnected()返回那些目的节点就是邻居节点的消息
//tryMessagesForConnected,尝试将上述返回的消息发送到目的节点(值得注意的是:只能发一个)
@SuppressWarnings(value = "unchecked")
Tuple<Message, Connection> t =
tryMessagesForConnected(sortByQueueMode(getMessagesForConnected()));
if (t != null) {
return t.getValue(); // started transfer
}
// didn't start transfer to any node -> ask messages from connected
// 如果没发送成功,看邻居节点的缓冲区是否有消息的目的节点是该节点,若是,尝试传输
for (Connection con : connections) {
if (con.getOtherNode(getHost()).requestDeliverableMessages(con)) {
return con;
}
}
return null;
}
2.4.1 getMessagesForConnected()
getMessagesForConnected
返回本节点缓冲区的那些目的节点在其邻居节点的消息,这些消息只要投递成功,就成功达到目的节点。源代码如下:
//返回那些消息的目的节点是某个邻居节点
protected List<Tuple<Message, Connection>> getMessagesForConnected() {
if (getNrofMessages() == 0 || getConnections().size() == 0) {
/* no messages -> empty list */
return new ArrayList<Tuple<Message, Connection>>(0);
}
List<Tuple<Message, Connection>> forTuples =
new ArrayList<Tuple<Message, Connection>>();
for (Message m : getMessageCollection()) { //遍历缓冲区每个消息
for (Connection con : getConnections()) { //遍历每个邻居节点
DTNHost to = con.getOtherNode(getHost());
if (m.getTo() == to) { //消息的目的节点是邻居节点
forTuples.add(new Tuple<Message, Connection>(m,con));
}
}
}
return forTuples;
}
2.4.2 tryMessagesForConnected()
tryMessagesForConnected
尝试着将消息传输出去,只要有一个成功(意味着该信道被占用),就返回。
2.4.3 requestDeliverableMessages()
requestDeliverableMessages
如果本节点没有消息的目的节点是邻居节点,那么看看邻居节点是否有消息的目的节点在本节点。DTNHost
的requestDeliverableMessages
调用ActiveRouter
的requestDeliverableMessages
。源代码如下:
// requestDeliverableMessages如果本节点没有消息的目的节点是邻居节点,
// 那么看看邻居节点是否有消息的目的节点在本节点。
@Override
public boolean requestDeliverableMessages(Connection con) {
if (isTransferring()) {
return false;
}
DTNHost other = con.getOtherNode(getHost()); //即得到本节点
/* do a copy to avoid concurrent modification exceptions 进行复制以避免并发修改异常
* (startTransfer may remove messages) */
ArrayList<Message> temp =
new ArrayList<Message>(this.getMessageCollection());
for (Message m : temp) {
if (other == m.getTo()) {
if (startTransfer(m, con) == RCV_OK) {
return true;
}
}
}
return false;
}