JohnLyu的blog

橙汁事务所艾欧泽亚分部

0%

尝试做个包含matplotlib的docker image, 把 STKAITI.TTF 放到了 /usr/local/share/fonts, 然后运行 fc-cache -fv.

然而字体还是不能显示, 奇了个怪了, 做了如下测试, 首先是能检测到STKaiti的:

1
2
3
4
5
6
7
8
9
10
In [13]: matplotlib.font_manager.findSystemFonts(fontpaths=None, fontext='ttf')
Out[13]:
['/usr/share/fonts/truetype/dejavu/DejaVuSerif.ttf',
'/usr/local/share/fonts/STKAITI.TTF', # font is here
'/usr/share/fonts/truetype/dejavu/DejaVuSerif-Bold.ttf',
'/usr/local/share/fonts/NotoSansSC-Regular.otf',
'/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf',
'/usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf',
'/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf',
'/usr/share/fonts/truetype/dejavu/DejaVuSansMono-Bold.ttf']
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import matplotlib.pyplot as plt
In [6]: plt.rcParams["font.sans-serif"] ## this is definded in my '~/.config/matplotlib/matplotlibrc'
Out[6]:
['STKaiti', # is here
'DejaVu Sans',
'Bitstream Vera Sans',
'Computer Modern Sans Serif',
'Lucida Grande',
'Verdana',
'Geneva',
'Lucid',
'Arial',
'Helvetica',
'Avant Garde',
'sans-serif']

ok…testing

1
2
3
4
5
6
7
8
9
10
11
12
13
In [7]: matplotlib.font_manager.get_fontconfig_fonts()
<ipython-input-7-b1c4039c0e25>:1: MatplotlibDeprecationWarning:
The get_fontconfig_fonts function was deprecated in Matplotlib 3.5 and will be removed two minor releases later.
matplotlib.font_manager.get_fontconfig_fonts()
Out[7]:
['/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf',
'/usr/local/share/fonts/NotoSansSC-Regular.otf',
'/usr/local/share/fonts/STKAITI.TTF', # here
'/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf',
'/usr/share/fonts/truetype/dejavu/DejaVuSansMono-Bold.ttf',
'/usr/share/fonts/truetype/dejavu/DejaVuSerif-Bold.ttf',
'/usr/share/fonts/truetype/dejavu/DejaVuSerif.ttf',
'/usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf']

然而,还有不能检测到的:

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
In [8]: [f.name for f in matplotlib.font_manager.fontManager.ttflist]
Out[8]:
['cmb10',
'cmr10',
'STIXGeneral',
'STIXSizeOneSym',
'DejaVu Sans Mono',
'STIXSizeTwoSym',
'cmex10',
'DejaVu Serif',
'DejaVu Sans',
'cmss10',
'STIXGeneral',
'cmtt10',
'DejaVu Sans',
'cmmi10',
'STIXSizeThreeSym',
'STIXSizeTwoSym',
'STIXSizeFourSym',
'DejaVu Serif',
'STIXSizeFiveSym',
'DejaVu Sans Mono',
'DejaVu Sans Mono',
'STIXNonUnicode',
'STIXGeneral',
'cmsy10',
'DejaVu Sans',
'STIXSizeOneSym',
'STIXNonUnicode',
'STIXSizeFourSym',
'DejaVu Serif Display',
'STIXSizeThreeSym',
'DejaVu Sans Mono',
'STIXNonUnicode',
'STIXNonUnicode',
'STIXGeneral',
'DejaVu Sans',
'DejaVu Sans Display',
'DejaVu Serif',
'DejaVu Serif',
'DejaVu Sans Mono',
'DejaVu Sans',
'DejaVu Serif',
'DejaVu Serif',
'DejaVu Sans',
'DejaVu Sans Mono']

还有这

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
In [10]: matplotlib.font_manager.findfont("STKaiti", rebuild_if_missing=True)
findfont: Font family ['STKaiti'] not found. Falling back to DejaVu Sans.
Out[10]: '/usr/local/lib/python3.8/site-packages/matplotlib/mpl-data/fonts/ttf/DejaVuSans.ttf'

In [14]: matplotlib.font_manager.findfont("STIXSizeTwoSym", rebuild_if_missing=True)
Out[14]: '/usr/local/lib/python3.8/site-packages/matplotlib/mpl-data/fonts/ttf/STIXSizTwoSymReg.ttf'

In [19]: matplotlib.font_manager.findfont("STKaiti", directory="/usr/local/share/fonts/",rebuild_if_missing=True)
findfont: Font family ['STKaiti'] not found. Falling back to DejaVu Sans.
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
Input In [19], in <cell line: 1>()
----> 1 matplotlib.font_manager.findfont("STKaiti", directory="/usr/local/share/fonts/",rebuild_if_missing=True)

File /usr/local/lib/python3.8/site-packages/matplotlib/font_manager.py:1307, in FontManager.findfont(self, prop, fontext, directory, fallback_to_default, rebuild_if_missing)
1301 # Pass the relevant rcParams (and the font manager, as `self`) to
1302 # _findfont_cached so to prevent using a stale cache entry after an
1303 # rcParam was changed.
1304 rc_params = tuple(tuple(rcParams[key]) for key in [
1305 "font.serif", "font.sans-serif", "font.cursive", "font.fantasy",
1306 "font.monospace"])
-> 1307 return self._findfont_cached(
1308 prop, fontext, directory, fallback_to_default, rebuild_if_missing,
1309 rc_params)

File /usr/local/lib/python3.8/site-packages/matplotlib/font_manager.py:1361, in FontManager._findfont_cached(self, prop, fontext, directory, fallback_to_default, rebuild_if_missing, rc_params)
1359 default_prop = prop.copy()
1360 default_prop.set_family(self.defaultFamily[fontext])
-> 1361 return self.findfont(default_prop, fontext, directory,
1362 fallback_to_default=False)
1363 else:
1364 raise ValueError(f"Failed to find font {prop}, and fallback "
1365 f"to the default font was disabled")

File /usr/local/lib/python3.8/site-packages/matplotlib/font_manager.py:1307, in FontManager.findfont(self, prop, fontext, directory, fallback_to_default, rebuild_if_missing)
1301 # Pass the relevant rcParams (and the font manager, as `self`) to
1302 # _findfont_cached so to prevent using a stale cache entry after an
1303 # rcParam was changed.
1304 rc_params = tuple(tuple(rcParams[key]) for key in [
1305 "font.serif", "font.sans-serif", "font.cursive", "font.fantasy",
1306 "font.monospace"])
-> 1307 return self._findfont_cached(
1308 prop, fontext, directory, fallback_to_default, rebuild_if_missing,
1309 rc_params)

File /usr/local/lib/python3.8/site-packages/matplotlib/font_manager.py:1364, in FontManager._findfont_cached(self, prop, fontext, directory, fallback_to_default, rebuild_if_missing, rc_params)
1361 return self.findfont(default_prop, fontext, directory,
1362 fallback_to_default=False)
1363 else:
-> 1364 raise ValueError(f"Failed to find font {prop}, and fallback "
1365 f"to the default font was disabled")
1366 else:
1367 _log.debug('findfont: Matching %s to %s (%r) with score of %f.',
1368 prop, best_font.name, best_font.fname, best_score)

ValueError: Failed to find font DejaVu Sans:style=normal:variant=normal:weight=normal:stretch=normal:size=16.0, and fallback to the default font was disabled

反正matplotlib提供的方法众多,我也不知道以哪个为准, 再加上matplotlibttc字体文件对处理是仅仅支持collection里的第一个文件,导致众多现代字体包没有意义,例如fonts-wqy-zenheifonts-noto-cjk.

大概和$\LaTeX$一样,差不多成为屎山了吧.

最终解决方案是把.cahce/matplotlib/下的缓存手动删除完事儿。

PS: 不知道是哪个大聪明,把matplotlib.font_manager._rebuild()方法给删了,我愿称之为把茅坑里的手纸给移除了。

attr就是从Model访问的名称, name是数据库中的列名, key是从Table对象访问的名称

从table说起

一般来说我们会这样定义一个Model:

1
2
3
4
5
6
7
8
Base = declarative_base()

class Customer(Base):
__tablename__ = 'Customers'

Id = Column("id_col", Integer, primary_key=True, key="abcde")
Name = Column(String(255))

注意,当我们定义一个Customer,然后有一个列叫Id, name叫id_col, key叫"abcde"的时候,这堆东西都意味着什么呢?

首先,declarative_base的作用本质是语法糖,它等价于:

1
2
3
4
5
6
7
8
9
10
11
metadata = MetaData()

customer = Table('Customers', metadata,
Column("id_col", Integer, primary_key=True, key="abcde"),
Column("Name", String(255))
)

class Customer(object):
pass

mapper(Customer, customer) # this will modify the Customer class!

实际上,sqlalchemy中使用的都是Table类.

例如上述代码创建的model:

1
2
>>> Customer.__table__
Table('Customers', MetaData(), Column('id_col', Integer(), table=<Customers>, key='abcde', primary_key=True, nullable=False), Column('Name', String(length=255), table=<Customers>), schema=None)

attr 与 name 与 key

attr就是从Model访问的名称, name是数据库中的列名, key是从Table对象访问的名称:

测试name是列名:

1
2
stmt = select(Customer)
print(str(stmt.compile(engine)))
1
2
3
SELECT "Customers".id_col,
"Customers"."Name"
FROM "Customers"

测试key是从Table对象访问的名称:

1
2
>>> Customer.__table__.c.abcde
Column('id_col', Integer(), table=<Customers>, key='abcde', primary_key=True, nullable=False)

公司的数据库是Oracle的,并且提供的数据字典是大小写混合表名,纯大写列名。

但是实际上,在公司数据库中,无论是表名还是列名都是大小写不敏感的,因此,sqlalchemy进行reflect的时候,
会将全部的表名和列名都转换为小写。这就导致从网页的数据字典复制到python代码中需要额外的将列名转换为小写,很不方便。

In Oracle, the data dictionary represents all case insensitive identifier names using UPPERCASE text. SQLAlchemy on the other hand considers an all-lower case identifier name to be case insensitive. The Oracle dialect converts all case insensitive identifiers to and from those two formats during schema level communication, such as reflection of tables and indexes. Using an UPPERCASE name on the SQLAlchemy side indicates a case sensitive identifier, and SQLAlchemy will quote the name - this will cause mismatches against data dictionary data received from Oracle, so unless identifier names have been truly created as case sensitive (i.e. using quoted names), all lowercase names should be used on the SQLAlchemy side.

solution 1

首先考虑将生成的Model的属性名改为大写,这样就不需要对sqlalchemy动刀,生成的model大概是这样:

1
2
3
4
5
6
7
class Mytablemodel(Base):
__tablename__ = 'mytablemodel'
__table_args__ = (
PrimaryKeyConstraint('object_id', name='sys_c00200245'),
)
OBJECT_ID = Column('object_id', VARCHAR(100), comment='对象ID')
...

既能够在代码里列名和数据字典保持一致,又不需要大动干戈,何乐不为呢?

因此重写了sqlacodegengenerator:

1
2
3
4
5
class MyModelGenerator(DeclarativeGenerator):
"""将列名全部替换为大写"""
def render_column_attribute(self, column_attr: ColumnAttribute) -> str:
column_attr.name = column_attr.name.uppper()
return super().render_column_attribute(column_attr)

但是,测试中发现了尴尬的情况:

1
2
3
4
5
stmt = select(Mytablemodel)
with engine.connect() as conn:
with conn.begin(): # Optional: start a transaction
q = conn.execute(stmt)
print(q.keys())

哦豁,露馅了,keys跟着实际数据库表的列名走, 与model中定义的attribute无关,还是个小写。
要说不能用吧,也不至于,但是总觉得不够完美。解决的思路大概有两种,一种是将实际sqlalchemy reflect
出来的列名设置为大写,另一种就是将engine.execute返回的对象修改。

solution 2

重新回去分析sqlalchemy的源码,仔细研究后发现,这个大小写转换主要存在于以下两个函数

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
def normalize_name(self, name):
if name is None:
return None

name_lower = name.lower()
name_upper = name.upper()

if name_upper == name_lower:
# name has no upper/lower conversion, e.g. non-european characters.
# return unchanged
return name
elif name_upper == name and not (
self.identifier_preparer._requires_quotes
)(name_lower):
# name is all uppercase and doesn't require quoting; normalize
# to all lower case
return name_lower
elif name_lower == name:
# name is all lower case, which if denormalized means we need to
# force quoting on it
return quoted_name(name, quote=True)
else:
# name is mixed case, means it will be quoted in SQL when used
# later, no normalizes
return name

def denormalize_name(self, name):
if name is None:
return None

name_lower = name.lower()
name_upper = name.upper()

if name_upper == name_lower:
# name has no upper/lower conversion, e.g. non-european characters.
# return unchanged
return name
elif name_lower == name and not (
self.identifier_preparer._requires_quotes
)(name_lower):
name = name_upper
return name

那么,第一反应肯定是将这个步骤给屏蔽掉,而且Sqlalchemy贴心在OracleDialect提供了这个选项:requires_name_normalize = True,改为False不就完事大吉了? 但是实际操作之后发现, 对于Oracle
的dialect而言,这个设置无效. 只能重写函数.

当然,重写函数并不困难, 甚至不需要重写, 可以考虑用event的方法

1
2
3
4
5
6
7
from sqlalchemy import event

@event.listens_for(metadata, 'column_reflect')
def receive_column_reflect(inspector, table, column_info):
"listen for the 'column_reflect' event"

# ... (event handling logic) ...

得到的model变成了这样:

1
2
3
4
5
6
class Mytablemodel(Base):
__tablename__ = 'mytablemodel'
__table_args__ = (
PrimaryKeyConstraint('OBJECT_ID', name='sys_c00200245'),
)
OBJECT_ID = Column(VARCHAR(100), comment='对象ID')

似乎就快成功了, 跑个测试之后发现, compile出来的SQL中, 列名都带了引号, 因为sqlalchemy默认纯小写是
大小写不敏感的, 纯大写需要被quote来表名这是个大小写敏感的列名,但是实际上在数据库中这是大小写不敏感的
因此SQL会出错.

重新分析compile的代码, 发现可以在dialect中进行修改:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

class MyOracleIdentifierPreparer(OracleIdentifierPreparer):

def _requires_quotes(self, value):
"""Return True if the given identifier requires quoting."""
lc_value = value.lower()
uc_value = value.upper()
return (
lc_value in self.reserved_words
or value[0] in self.illegal_initial_characters
or not self.legal_characters.match(util.text_type(value))
or ((lc_value != value) and (uc_value != value)) # change here, allow all uppercaes
)

class MyDialect(oracle.dialect):
preparer = MyOracleIdentifierPreparer

目前运行良好.

启动steam的串流,出现如下提示:

1
Would you like to accept secure desktop input from Steam?.

Solved. The methods are as follows.

Suppose that you have PC A and B, your game is installed on A, and you wanna play on B. May be B is in your office and A is at your home.

  1. On B, RDP into A.

  2. Launch steam on both A and B. (In B, you should see "Stream" button on the game you are to play)

  3. Click "stream" button on B. (It will fail because you will see the boring dialog box)

  4. Press "Tab" key and choose the window of your RDP, so now you can see that on A, your game has been launched.

  5. On A, launch cmd.exe as administrator.

  6. type "qwinsta" and press enter, no quotes are required.

  7. You should see the active sessions list on your A. One of them is your RDP session, with your username followed. One of them named "concole" is what your steam on B attempted to login but failed. Please remember the session ID of the former. (The ID should be an integer.)

  8. Type "tscon SESSIONID /password:PWD /dest:console" in the cmd on A. Change SESSIONID to the number you remembered, and PWD to your normal windows user password, leave the rest intact. Press enter. (This command will attach the RDP session to the console session)

  9. Once you pressed enter, your RDP to A will immediately disconnect. Now, back to B, on your steam game page, click "Stop" button, then click "connect" button, you are ready to remote play :)

wakeonlan 配置

windows上的配置没有什么多说的, 设备管理器, 找到需要唤醒的网卡, 在power部分设置可以唤醒,在detail部分确认即可.

Go to Device Manager( in System) -> Select your network adapter and click right button -> Select Properties -> >Click Allow this device to wake the computer and Only allow a magic packet to wake the computer.

防火墙无需额外配置.

BIOS记得在power部分确认允许唤醒.

核心tricky的地方在于,就算设置了这么多, 依旧只能在Windows选择sleep的时候唤醒, shutdown之后是不行的.

原因在于fastboot, 关掉之后就可以了.

参考:

What I've checked was these: -Windows LAN adapters settings: All OK with all Magic Packets checked, and power saving unchecked. -Windows Power Saving settings: Full Performance (LAN/PCI/Related goes to standby) -BIOS settings: EuP Disabled, PCIE Wake Enabled

What I've found: -Normal Windows Shutdown: When performing a normal windows shutdown from "Shutdown" button, LAN card turns >completely off (stops blinking/reporting to router) -PC Monitor App: When sending from my phone the shutdown command from this app. the PC turns off the same way than >pressing the button BUT LAN card keeps alive (blinking and reporting to router), allowing me to wake up from my >network or through internet.

So it seems the shutdown button has some different command that kills my card when I press it to turn of my PC.

UPDATE: Think I've found it... is because Windows "Fast Boot" - http://support.microsoft.com/kb/2776718/en-us

Java连接hive例子

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
import java.sql.SQLException;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.sql.DriverManager;

public class HiveJdbcClient {
private static String driverName = "org.apache.hadoop.hive.jdbc.HiveDriver";

/**
* @param args
* @throws SQLException
*/
public static void main(String[] args) throws SQLException {
try {
Class.forName(driverName);
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.exit(1);
}
//replace "hive" here with the name of the user the queries should run as
Connection con = DriverManager.getConnection("jdbc:hive2://localhost:10000/default", "hive", "");
Statement stmt = con.createStatement();
String tableName = "testHiveDriverTable";
stmt.execute("drop table if exists " + tableName);
stmt.execute("create table " + tableName + " (key int, value string)");
// show tables
String sql = "show tables '" + tableName + "'";
System.out.println("Running: " + sql);
ResultSet res = stmt.executeQuery(sql);
if (res.next()) {
System.out.println(res.getString(1));
}
// describe table
sql = "describe " + tableName;
System.out.println("Running: " + sql);
res = stmt.executeQuery(sql);
while (res.next()) {
System.out.println(res.getString(1) + "\t" + res.getString(2));
}


// load data into table
// NOTE: filepath has to be local to the hive server
// NOTE: /tmp/a.txt is a ctrl-A separated file with two fields per line
String filepath = "/tmp/a.txt";
sql = "load data local inpath '" + filepath + "' into table " + tableName;
System.out.println("Running: " + sql);
stmt.execute(sql);

// select * query
sql = "select * from " + tableName;
System.out.println("Running: " + sql);
res = stmt.executeQuery(sql);
while (res.next()) {
System.out.println(String.valueOf(res.getInt(1)) + "\t" + res.getString(2));
}

// regular hive query
sql = "select count(1) from " + tableName;
System.out.println("Running: " + sql);
res = stmt.executeQuery(sql);
while (res.next()) {
System.out.println(res.getString(1));
}

Microsoft在2015版本之后的visual studio不再提供官方的offline installer.

解决方案有两个, 一个是使用2015版本的Microsoft Build Tools 2015

另一个是自己找一台有网络的电脑, 手动制作一个安装包.

首先去visual studio 官网 下载最新的vs_BuildTools, 然后使用命令行:

1
vs_buildtools_xxxxx.exe --add Microsoft.VisualStudio.Workload.MSBuildTools --layout c:\offlineBuildTool --lang en-us

refer: https://stackoverflow.com/questions/59868753/offline-build-tools-for-visual-studio-2019

官网教程

但是国内只能使用阿里云镜像

1
2
3
4
5
6
wget https://mirrors.aliyun.com/nvidia-cuda/ubuntu1804/x86_64/cuda-ubuntu1804.pin
sudo mv cuda-ubuntu1804.pin /etc/apt/preferences.d/cuda-repository-pin-600
sudo apt-key adv --fetch-keys https://mirrors.aliyun.com/nvidia-cuda/ubuntu1804/x86_64/7fa2af80.pub
sudo add-apt-repository "deb https://mirrors.aliyun.com/nvidia-cuda/ubuntu1804/x86_64/ /"
sudo apt-get update
sudo apt-get -y install cuda

请阐明因特网中数据链路层和传输层的可靠传输服务实现的异同点。

相同点:

  1. 数据链路层和传输层都需要提供可靠服务。
  2. 用面向连接的方式工作。
  3. 都包含了差错控制和流量控制。
  4. 差错控制机制都采用了校验和重发机制来实现,确认都采用稍带确认。
  5. 流量控制都是采用窗口机制来实现。

差别:数据链路层的传输基础是一条传输媒体,而传输层的传输基础是一个互联网,这导致了数据链路层和传输层实现时有如下几个区别:

  1. 重发机制中的定时器值的设定
  2. 连接建立和连接释放过程
  3. 传输层还需要考虑拥塞控制

分别画出面向连接面向无连接的客户/服务器时序图

面向连接的客户/服务器时序图

无连接的套接字调用时序图:

请比较两层交换机、三层交换机和路由器的功能以及区别。

二层交换机工作在数据链路层, 当收到数据包时, 根据目标MAC, 查找端口-MAC地址转发表进行转发.

路由器工作在网络层, 收到数据包时, 根据目标IP, 查找内部的路由表进行转发.

三层交换机也工作在网络层, 相对于路由器, 三层交换机在完成一次路由表查找之后, 会将下一跳的MAC地址记录在转发表中. 当下一次收到目的地是这个IP的请求时, 不再拆包到网络层并查找路由表, 而是直接根据转发表进行转发. 这就是一次路由多次转发.

DV和LSR

试简述距离矢量法(DV)和链路状态法(LSR)的工作过程。分别适用于什么场合?因特网中的RIP协议和OSPF协议分别采用哪个算法?

答:1)距离矢量法定期与邻居交换自己的距离矢量。根据邻居的距离矢量及自己到邻居的距离计算到其他节点的最近距离

2)链路状态法收集邻居信息,组装成一个路由分组,广播给网上的所有节点。每个节点根据收集到的路由分组总结出整个网络的拓扑结构,用单源最短路径的算法计算到每个节点的最短路径。

3)距离矢量法适合小型网络,链路状态法适合较大型网络

4)RIP用DV,OSPF用LSR

RTT计算

假设主机A需要通过TCP将一个很大的文件发送给主机B。A和B之间由一台路由器相联,相距5000 km,信号的传播速率为200m/μs,数据传输率为10Mbps,TCP的数据报长度为1KB。

  1. 求A和B之间发送一个数据报的往返延迟RTT。路由器的排队及转发延迟为1ms、忽略主机的处理延迟以及数据包和ACK包的传输延迟。
  2. TCP使用慢启动来进行端对端的拥塞控制。初始临界值取8KB。请问6次成功发送之后,A和B之间的平均吞吐量是多少?线路的效率是多少?

解答:

  1. RTT的含义是Round-trip time, 因此需要计算往返的时间, 计算方法为:
1
2
3
RTT = 2(distance / speed + delay)
= 2(5000e3 / 200e3 + 1)
= 52

因此RTT为52毫秒.

  1. 慢启动分两种增长模式, 在达到阈值之前, 每次发送的数据包cwnd=cwnd+ack_num, 也就是指数增长。而到达阈值之后cwnd=cwnd+1, 也就是随着RTT线性增长. 这意味着单次发送在达到8KB之前, 都是指数增长的, 增长模式是1, 2, 4, 8, 在8KB之后是线性增长的, 增长模式为8, 9, 10.
    具体到题目中
    6次成功发送的总数据量为(1 + 2 + 4 + 8 + 9 + 10)* 1kB=34kB=272k bit
    总时长为52 * 6 = 312 ms
    平均速度为272/312e-3 = 871.79 kbps
    线路效率为871.79e3 / 10e6 = 0.087179

如图所示,数据报从A经过R到达B,数据报如何从源主机到达目的主机,简述下整个工作原理和过程。

image-20201206134438141

答:

  1. A将B的IP地址和自己的IP地址与掩码分别计算后进行比较, 发现不在同一个子网中, 因此, A决定将数据包发给网关.

  2. A封装一个目标IP为222.222.222.222, 目标MAC为E6-E9-00-17-BB-4B的数据包, 发送给R.

  3. R拆封数据包, 根据IP查找路由表, 发现222.222.222.222可以转发到端口222.222.222.220,

  4. 端口 222.222.222.220 通过子网掩码判断目的地222.222.222.222 和自己属于同一子网, 查找本地ARP表格, 发现记录中存在222.222.222.222的记录, 因此将数据包的目的MAC地址设置为49-BD-D2-C7-56-2A目的IP地址为222.222.222.222发送给B.

WiFi的分布式媒体访问控制方法

下图WiFi网络中,D在t0时刻给C发送了RTS,C回答了CTS。D在收到CTS之后在t2时刻开始发送数据,同时A在t1时刻给B发送了RTS并在t3时刻到达B。

image-20201206151958418

  1. 请简单阐述WiFi的分布式媒体访问控制方法。
  2. 如果A在t3时刻以后给B发送数据,B 能正确接收吗?这会干扰正在进行的C和D之间的通信吗?
  3. 在t3时刻, B可以给A回答CTS吗? 为什么?

答:

  • RTS:Request To Send,即请求发送。RTS帧是一个单播帧,没有加密,其duration字段中填充包含后续发送过程中总体所需要时间。
  • CTS:Clear To Send,即信道清除帧。节点在收到CTS后,确认信道是空闲的,可以发送。CTS也是一个单播帧,没有加密,其duration字段包含除去RTS以及一个SIFS后,发送过程总体所需要时间。其RA(receiver address)表明了该CTS是发送给哪个客户端的.
  1. WiFi采用CSMA/CA的方法进行媒体访问控制。在发送数据前,源端首先侦听信道,如果信道空闲,则通过发送RTS/CTS短帧以防止冲突,然后再发送数据;如果信道忙,则通过二进制指数后退法等待一段时间以后再重新尝试。
  2. 不能正确接收, 因为B还没有给A回复CTS信号.
    不会干扰. 因为C在A的发射半径之外,所以A可以给B发送数据,不会干扰C接收数据
  3. B不可以回复CTS, 因为B可以从CTS中获知其RA不是指向自己. 另一方面, B在此之前也没有发送过RTS. 实际上T3时刻, B在收到不属于自己的CTS信号时已经进入了NAV(Network Allocation Vector)倒数状态.
    另一方面, 如果B在T3时刻发起对C的通信, 会导致和D发送的信号冲突.

子网划分

某网络拓扑如下图所示,路由器R1通过接口EE2分别连接局域网局域网2,通过接口L0连接路由器R2,并通过路由器R2连接域名服务器与互联网。R1的L0接口的IP地址是202.118.2.1;R2的L0接口的IP地址是202.118.2.2,L1接口的IP地址是130.11.120.1,E0接口的IP地址是202.118.3.1;域名服务器的IP地址是202.118.3.2。

img

R1和R2的路由表结构为:

目的网络IP地址 子网掩码 下一跳IP地址 接口
  1. 将IP地址空间202.118.1.0/24划分为2个子网,分别分配给局域网局域网2,每个局域网需分配的IP地址数不少于120个。请给出子网划分结果,说明理由或给出必要的计算过程。
  2. 请给出R1的路由表,使其明确包括到局域网1的路由、局域网2的路由、域名服务器的主机路由和互联网的路由。(路由表格式参照路由表结构)
  3. 请采用路由聚合技术,给出R2到局域网1和局域网2的路由。(路由表格式参照路由表结构)

答:

  1. 可使用的地址空间为后八位, 其中第一位用来划分成两个子网, 后七位用来每个子网内分配. 7位的可分配地址为2^7-1=127在减去全0, 全1, 网关三个地址, 剩下124个可分配地址, 符合题目要求. 因此, E1为202.118.1.0/25, E2为202.118.1.128/25.

  2. 目的网络IP地址 子网掩码 下一跳IP地址 接口
    130.11.120.1 255.255.255.0 202.118.2.2 L0
    202.118.3.1 255.255.255.0 202.118.2.2 L0
    202.118.2.2 255.255.255.0 Direct L0
    202.118.1.0 255.255.255.128 Direct E1
    202.118.1.128 255.255.255.128 Direct E2
  3. 目的网络IP地址 子网掩码 下一跳IP地址 接口
    202.118.1.0 255.255.255.0 202.118.2.1 L0

下图所表示的网络中,子网A~D 最多有30 台主机。现有一个C 类地址202.120.36.0可以用来为该网络分配IP地址。

image-20201206171408720

  1. 为子网A~E分配子网号和子网掩码,并为子网E中的两台路由器的接口分别分配其IP地址。
    题中有5个子网, 因此至少需要2^3=8 > 5位作为子网掩码, 每个子网中剩下2^5-1=31个地址空间.子网号和掩码分别是:

    1. 202.120.36.128/27 (1000 0000)
    2. 202.120.36.64/27 (0100 0000)
    3. 202.120.36.192/27 (1100 0000)
    4. 202.120.36.32/27 (0010 0000)
    5. 202.120.36.160/27 (1010 0000)

    路由器接口IP从左到右依次可以分配202.120.36.129, 202.120.36.65, 202.120.36.66, 202.120.36.193, 202.120.36.33, 202.120.36.161

  2. 路由器R1向外广播的子网号和子网掩码分别是多少?

    202.120.36.0, 255.255.255.0

  3. 如果子网A中的主机要给子网D中的主机发送分组,他们需要知道R1连接在子网E中的MAC地址吗?请解释原因。

    不需要, 同一子网之间才需要知道MAC地址, A只需要知道它的网关R2的MAC地址. 数据包经过R2时, 会在路由后修改目的MAC地址为R1.

  4. 如果路由器R2替换成交换机S2. 请指出各自的冲突域和广播域。

    A, B, E各自形成一个冲突域, A, B, E共同形成一个广播域.

  5. 如果路由器R2替换成交换机S2,子网A中的主机要给子网D中的主机发送分组,他们需要知道R1连接在子网E中的MAC地址吗?如果需要,他们如何得到其MAC地址?

    需要, 由主机发送查询R1的IP的ARP请求, R2会洪泛给子网中的全部其他主机, R1收到ARP请求之后应答, 主机就得到了R1的MAC地址.

以太网帧和IP包

在图(a)的网络结构图中,主机A要发送一个数据包给主机B,已知主机B的域名为www.xxx.com。主机A向主机B发送了一个IP数据包,该数据包被封装在一个以太网帧里边。帧的内容如图(b)所示。IP包格式和以太网的帧格式如图(c)所示。

image-20201206183622377

1
00 21 27 21 51 ee 00 15 c5 c1 5e 28 08 00 45 00 01 ef 11 3b 40 00 80 06 ba 9d ca 78 02 14 40 aa 62 20 04 ff 00 50
6 6 2 0~1500 46~0 4
目的地址 源地址 类型 数据 填充字符 检验和

image-20201206185146487

不得不说这题真烂, 以太网帧格式给的是以byte为单位, IP包格式给的是以bit为单位.

  1. 主机A如何获得主机B的IP地址?
    通过DNS查找
  2. 主机A所在的网络是A、B、C类中的哪一类网络?
    C类
  3. 主机A的缺省网关的IP地址是多少?
    201.120.2.1
  4. 主机A的MAC地址是多少?
    00 15 c5 c1 5e 28
  5. 缺省网关的MAC地址是多少?
    00 21 27 21 51 ee
  6. 主机B的IP地址是多少(用点分十进制表示)?
    不会吧不会吧, 这破题不会有人能做出来吧, 主机A的ip的第一段换算成16进制是c9整段报文里都找不到c9, 真有你的啊, 编个数也不走心的吗.
    强行数数, 第(6 + 6 + 2 + 4 * 4) 个字节后就是目标IP地址, 40aa6220, 换算成点分十进制是64.170.98.32

通信原理

一个TDM系统容量为480kbps, 为10路语音线路共享,语音信号的带宽为3000 Hz. 请问模数转换的采样频率为多少?每个样本/信元携带多少比特的信息?假设该系统无噪声,并且采用二元信号进行传输,则信道的总带宽最小为多少Hz?如果采用曼切斯特编码,则信道的总带宽最小为多少Hz?

答:

  1. 采样频率为两倍信号带宽 3000 * 2 = 6000Hz
  2. 每一路语音容量为48kbps, 每个样本携带 48 / 6=8bit信息.
  3. 我不想写了…通信原理的题为什么会出现在计网里…抄百度文库也有点限度吧

一台机器是否允许有多个IP地址,是否允许有多个域名?在什么情况下将出现此类情况?

当然允许啊, 每一个interface都有一个IP, 每个IP可以对应多个域名. 绝大部分情况都是这样, 机器除了真实网卡总有一个loopback interface吧, 这就俩了.

简述ARP欺骗的实现原理及主要防范方法。

1.arp欺骗的原理 

以太网设备(比如网卡)都有自己全球唯一的MAC地址,它们是以MAC地址来传输以太网数据包的,但是以太网设备却识别不了IP数据包中的IP地址,所以要在以太网中进行IP通信,就需要一个协议来建立IP地址与MAC地址的对应关系,使IP数据包能够发送到一个确定的主机上。这种功能是由arp(AddressResolution Protocol)来完成的。arp协议不管是否发送了arp请求,都会根据收到的任何arp应答数据包对本地的arp高速缓存进行更新,将应答数据包中的IP地址和MAC地址存储在arp高速缓存中。这正是实现arp欺骗的关键。可以通过编程的方式构建arp应答数据包,然后发送给被欺骗者,用假的IP地址与MAC地址的映射来更新被欺骗者的arp高速缓存,实现对被欺骗者的arp欺骗。

有两种arp欺骗:一种是对路由器arp高速缓存的欺骗;另一种是对内网电脑arp高速缓存的欺骗。

2.arp欺骗攻击的防范 

  1. 在客户端使用arp命令绑定网关的IP/MAC(例如arp -s192.168.1.1 00-e0-eb-81-81-85)
  2. 在交换机上做端口与MAC地址的静态绑定。
  3. 在路由器上做IP/MAC地址的静态绑定。 
  4. 使用arp服务器定时广播网段内所有主机的正确IP/MAC映射表。
  5. 及时升级客户端的操作系统和应用程序补丁。
  6. 升级杀毒软件及其病毒库。

密码学

用户A要通过网络向用户B发送报文M,假设A的公开密钥和秘密密钥分别为EA和DA,B的公开密钥和秘密密钥分别为EB和DB。如果希望A发送的报文带数字签名,且A和B之间进行加密通信,请问A在发送报文M前应对其如何处理?而B在接收到报文后又如何处理?

…所以说为什么又混入了密码学的题啊, 绝了嘿.

发送报文时,用户A用一个哈希函数从报文文本中生成报文摘要,然后用对方的自己的私钥对这个摘要进行加密,这个加密后的摘要将作为报文的数字签名,然后再使用用户B的公钥对报文消息进行加密,并把加密后的密文附到数字签名后一起发送给接收方用户B,用户B首先使用自己的私钥对加密后的密文报文进行解密,获得消息明文,并利用用户A的公钥对数字签名解密获得报文摘要,然后与利用与用户A相同的hash函数对解密后的明文求得的hash值进行比较,验证是否是用户A发送的。

IEEE802.11协议

在下图所示的网络中,若主机H 发送一个封装访问Internet 的IP 分组的IEEE802.11数据帧F,则帧F的地址地址2 和地址3 分别是什么?试分析原因。

三个地址的含义分别是:

  1. Address 1 is the receiver
  2. Address 2 is the transmitter
  3. Address 3 is used for filtering purposes by the receiver

地址1为AP, 地址2为发送方, 地址3为R的MAC.

TCP协议中的后退N帧协议

甲乙双方均采用后退N帧协议(GBN)进行持续的双向数据传输,且双方始终采用捎带确认,帧长均为1000B。Sx,y 和Rx,y 分别表示甲方和乙方发送的数据帧,其中:x是发送序号;y 是确认序号(表示希望接收对方的下一帧序号);数据帧的发送序号和确认序号字段均为3比特。信道传输速率为100Mbps,RTT=0.96ms。下图给出了甲方发送数据帧和接收数据帧的两种场景,其中t0 为初始时刻,此时甲方的发送和确认序号均为0,t1 时刻甲方有足够多的数据待发送。

请回答下列问题。

  1. 对于图(a),t=0时刻到t1时刻期间,甲方可以断定乙方已正确接收的数据帧数是多少?正确接收的是哪几个帧(请用Sx,y形式给出)?

    由图可知, 最后返回的是R3,3, 代表接收方期待的下一个seq是3, 也就是seq从0到2已经确认接收了.
    答案是S0,0, S1,0, S2,0

  2. 对于图(a),从t1 时刻起,甲方在不出现超时且未收到乙方新的数据帧之前,最多还可以发送多少个数据帧?其中第一个帧和最后一个帧分别是哪个(请用Sx,y形式给出)?

    根据发送序号和确认序号字段均为3比特, 可以计算出发送窗口大小为2^3 - 1 = 7.
    当前窗口起始位置为第一个已发送未接收的包, 也就是S3,0. 按照窗口大小为7(最大), 图中看到已经发送了S4,0, 那么按照sequence number递增剩下的五个应该分别是5, 6, 7, 0, 1.
    再考虑acknowledge number, 截止到t1时刻, 甲方总共收到可确认的R0,1R1,3, R3,3因为R2,3并未收到并不记入acknowledge number中, 因此t1之后的acknowledge number全都是2.
    故而第一个包是S5,2而最后一个是S1,2.

  3. 对于图(b),从t1 时刻起,甲方在不出现新的超时且未收到乙方新的数据帧之前,需要重发多少个数据帧?重发的第一个帧是哪个(请用Sx,y 形式给出)?

    需要重发S2以及之后的全部数据帧. 但是需要注意的是acknowledge number已经累加了, 此时的acknowledge number是3.
    所以需要重发3个数据帧, 第一个是S2,3.

  4. 甲方可以达到的最大信道利用率是多少?

    单个包的发送时延为: $t1 = \frac{8*1000}{100e6}$
    整体信道利用率为 $\frac{7 * t1}{0.96e-3 + 2 * t1} = 50%$

公司子网划分

某公司网络如题图所示。IP地址空间192.168.1.0/24被均分给销售部和技术部两个子网,并已分别为部分主机和路由器接口分配了IP地址,销售部子网的MTU=1500 B,技术部子网的MTU=800 B

image-20201209201952850

请回答下列问题。

  1. 销售部子网的广播地址是什么?技术部子网的子网地址是什么?若每个主机仅分配一个IP地址,则技术部子网还可以连接多少台主机?

    先分析两个网络, 已知F0和F1的地址分别是192.168.1.126192.168.1.254. 分析其最后一段, 二进制分别为0111111011111110, 可见唯一的区别是第一位, 也就是子网掩码是第一位.

    进而推测出两个子网分别是192.168.1.0/25192.168.1.128/25.

    技术部的容量为2^7 - 2 = 126 还可以连接126 - (208 - 79 + 1) - 1 = 45台.

  2. 假设主机192.168.1.1向主机192.168.1.208发送一个总长度为1500 B的IP分组,IP分组的头部长度为20 B,路由器在通过接口F1转发该IP分组时进行了分配。若分片时尽可能分为最大片,则一个最大IP分片封装数据的字节数是多少?至少需要分为几个分片?每个分片的片偏移量是多少?

答案及知识点解析:考察局域网和ip协议

1)广播地址是网络地址中主机号全 1 的地址(主机号全 0 的地址,代表网络本身)。销售部和技术部均分配了 192.168.1.0/24 的 IP 地址空间,IP 地址的前 24 位为子网的网络号。于是在后 8位中划分部门的子网,选择前 1 位作为部门子网的网络号。令销售部子网的网络号为 0,技术部子网的网络号为 1,则技术部子网的完整地址为 192.168.1.128;令销售部子网的主机号全 1,可以得到该部门的广播地址为 192.168.1.127。每个主机仅分配一个 IP 地址,计算目前还可以分配的主机数,用技术部可以分配的主机数,减去已分配的主机数,技术部总共可以分配计算机主机数为27 -2=126(减去全 0 和全 1 的主机号)。已经分配了 208-129+1=80 个,此外还有 1 个 IP 地址分配给了路由器的端口(192.168.1.254),因此还可以分配 126-80-1=45 台。2)判断分片的大小,需要考虑各个网段的 MTU,而且注意分片的数据长度必须是 8B 的整数倍。由题可知,在技术部子网内,MTU=800B,IP 分组头部长 20B,最大 IP 分片封装数据的节数为ë(800-20)/8û×8=776。至少需要的分片数为é(1500-20)/776ù =2。第 1 个分片的偏移量为 0;第 2 个分片的偏移量为 776/8=97。

假设Internet的两个自治系统构成网络如题图所示,自治系统ASI由路由器R1连接两个子网构成;自治系统AS2由路由器RR3互联并连接3个子网构成。各子网地址、R2的接口名、R1与R3的部分接口IP地址如题图所示。

img

题 图网络拓扑结构

请回答下列问题。

(1) 假设路由表结构如下所示。请利用路由聚合技术,给出R2的路由表,要求包括到达题图中所有子网的路由,且路由表中的路由项尽可能少。

img

(2) 若R2收到一个目的IP地址为194.17.20.200的IP分组,R2会通过哪个接口转发该IP分组?

(3) R1与R2之间利用哪个路由协议交换信息?该路由协议的报文被封装到哪个议的分组中进行传输?

解析:

\1. 在AS1中,子网153.14.5.0/25 和子网 153.14.5.128/25可以聚合为子网 153.14.5.0/24;在 AS2 中,子网 194.17.20.0/25 和子网 194.17.21.0/24 可以聚合为子网 194.17.20.0/23,但缺少 194.17.20.128/25;子网194.17.20.128/25 单独连接到 R2 的接口 E0;

R2的路由表:

目的网络 下一跳 接口
153.14.5.0/24 153.14.3.2 S0
194.17.20.0/23 194.17.24.2 S1
194.17.20.128/25 / E0

\2. 该IP分组的目的IP地址是 194.17.20.200 与 路由表中的 194.17.20.0/23 和 194.17.20.128/25 这2个路由表都匹配,根据最长匹配原则,R2 将通过 E0 接口转发该IP分组。

\3. R1 与 R2 之间利用 BGP 协议交换路由信息,该路由协议的报文被封装到TCP 协议段中进行传输。

某网络中的路由器运行OSPF路由协议,题表是路由器R1维护的主要链路状态信息(LSI),题42图是根据题42表及R1的接口名构造出来的网络拓扑。

img

表1:表 R1所维护的LSI

img

图1:R1构造的网络拓扑

请回答下列问题。

(1)本题中的网络可抽象为数据结构中的哪种逻辑结构?

(2)针对表1中的内容,设计合理的链式存储结构,以保存表1表中的链路状态信息(LSI)。要求给出链式存储结构的数据类型定义,并画出对应题1表的链式存储结构示意图(示意图中可仅以ID标识结点)。

(3)按照迪杰斯特拉(Dijkstra)算法的策略,依次给出R1到达题图1中子网192.1.x.x的最短路径及费用。

(4)假设路由表结构如下表所示,请给出图1中R1的路由表,要求包括到达图1中子网192.1.x.x的路由,且路由表中的路由项尽可能少。

img

(5)当主机192.1.1.130向主机192.1.7.211发送一个TTL=64的IP分组时,R1通过哪个接口转发该IP分组?主机192.1.7.211收到的IP分组TTL是多少?

(6)若R1增加一条Metric为10的链路连接Internet,则题42表中R1的LSI需要增加哪些信息?

解析:

img

img

img

img

3,4,5问:

img

赛制

手册有好几页, 名词记不住, 但是实际上和参赛前想象的AWD还是不一样, 更偏向于传统的CTF.

采用累积记分制度, 每10分钟结算一次, 拿到flag/加固好的题目可以得分, 每道题的分值是浮动的. 因此, 手速变的非常重要, 也不存在憋flag的可能.

和传统的CTF有所不同的是, 每道题分为两个部分, 一个是传统的攻击目标机器拿到flag, 另一个是上传一个压缩包以及对应的部署脚本去加固这个应用, 系统判定加固成功即可每轮得分.

经验

最大的敌人是完全断网, 熟练度非常非常重要,