目录
[1. 发邮件](#1. 发邮件)
[2. 最长上升子序列](#2. 最长上升子序列)
选择题
1.
DNS 劫持又称域名劫持,是指在劫持的网络范围内拦截域名解析的请求,分析请求的域名,把审查范围以外的请求放行,否则返回假的 IP 地址或者什么都不做使请求失去响应,其效果就是对特定的网络,不能反应或访问的是假网站。
DDos 攻击:分布式拒绝服务攻击指借助于客户/服务器技术,将多个计算机联合起来作为攻击平台,对一个或多个目标发动 DDos 攻击,从而成倍的提高拒绝服务攻击的威力。
MAC 地址欺骗:利用 mac 欺骗阻止局域网内任意电脑使用网络。
伪造 DHCP 服务器:本质上是 DHCP 欺骗攻击,将真的 DHCP 服务器的 ip 资源耗尽,然后部署假的 DHCP 服务器,让主机向假的 DHCP 服务器请求。
2.
三次握手 :
四次挥手:
3.
TCP 本身是可靠传输的协议,支持重传,纠错,网络拥塞处理等等。
TCP 本身是面向字节流的协议,对于发送的有效载荷的格式并不是很关心,由应用层协议来处理发送数据的格式,应用层协议由程序员来考虑和处理(TCP 粘包的问题也是如此)。
4.
HTTPS 在 HTTP 的基础上加入 SSL,HTTPS 的安全基础是 SSL,因此加密的详细内容就需要 SSL。
对使用 HTTP 传输的数据使用 SSL 进行加密传输,第三者即使从网络当中获取数据包内容,也会由于没有加密的密钥而导致无法解析传输的内容,从而达到加密的效果。
5.
四次挥手:
6.
host 表示访问的 IP 地址,connection 的值是 close,所以应该是连接会在请求处理完毕后断开。
Cookie 是浏览器存储数据的方式,浏览器会将 Cookie 的 key/value 保存到某个目录下的文本文件内,下次请求同一网站时,就发送该 Cookie 给服务器。
7.
甲方的发送窗口 = min(接收窗口,拥塞窗口)
拥塞窗口以指数形式增长,后一次是前一次的两倍。
甲方发送的数据大小取决于接收窗口和拥塞窗口的较小值,
如上图,当经过四个往返时间后 接收窗口值变为 1.
8.
POP3 邮件协议版本3,是 TCP/IP 协议族中的一员。
该协议主要作用于支持使用客户端远程管理在服务器上的电子邮件。提供了 SSL 加密的 POP3 协议被称为 POP3S。
属于应用层协议,传输层协议使用 TCP 协议。
9.
UDP 是无连接,不可靠,面向数据报的协议,在协议头部当中有 16 字节的校验和,可以校验数据在传输过程当中是否失真,但是并不保证可靠。
传输层分用和复用就是把网络层提供的 host-to-host (主机对主机)传输服务扩展到运行于计算机上的应用进程间的传输服务,也就是点对点的传输,这里的点可以理解为端口。
分用是把传输层报文段当中的信息发送给正确的 socket 的服务(分用就是把传输层的数据给应用层)。
复用是把所有 socket 中的数据集中并加头信息封装,然后发送到网络层的服务(复用就是把传输层的数据给网络层)。
10.
编程题
1. 发邮件
根据以上思路,就很好写代码了。
代码实现:
java
import java.util.Scanner;
// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
public static void main(String[] args) {
// 可以先算出所有的错排可能性,然后再根据 n 直接从数组取即可
long[] arr = new long[21];
arr[0] = 0;
arr[1] = 0;
arr[2] = 1;
for (int i = 3; i < arr.length; i++) {
arr[i] = (i - 1) * (arr[i - 1] + arr[i - 2]);
}
Scanner in = new Scanner(System.in);
// 注意 hasNext 和 hasNextLine 的区别
while (in.hasNextInt()) { // 注意 while 处理多个 case
int n = in.nextInt();
System.out.println(arr[n]);
}
}
}
2. 最长上升子序列
这一道题也是非常经典的动态规划题目。
还是从 1. 定义状态 2. 状态转移方程 3. 初始化 4. 返回值 入手。
代码实现:
java
import java.util.*;
// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
// 注意 hasNext 和 hasNextLine 的区别
while (in.hasNextInt()) { // 注意 while 处理多个 case
int n = in.nextInt();
int[] arr = new int[n];
for (int i = 0; i < arr.length; i++) {
arr[i] = in.nextInt();
}
print(n, arr);
}
}
public static void print(int n, int[] arr) {
// dp[i] 就是数组 arr 中以 i 下标结尾的最长上升子序列的长度
int[] dp = new int[n];
// 初始化
for (int i = 0; i < arr.length; i++) {
dp[i] = 1;
}
for (int i = 1; i < dp.length; i++) {
for (int j = 0; j < i; j++) {
if (arr[j] < arr[i]) {
dp[i] = Math.max(dp[i], dp[j] + 1);
}
}
}
int max = 1;
for (int i = 0; i < dp.length; i++) {
if (dp[i] > max) {
max = dp[i];
}
}
System.out.println(max);
}
}