应用层协议
- http [Hypertext Transfer Protocol]
- ftp [File Transfer Protocol]
- smtp [Simple Mail Transfer Protocol]
- dns [Domain Name System]
- telnet 提供了一种通过终端[远程登录]服务器的方式
- nfs [Network File System]. It allows remote hosts to mount file systems over a network and interact with those file systems as though they are mounted locally.
- ntp 网络时间协议基于UDP,用于网络时间同步
ICMP and ping
Internet Control Message Protocol (ICMP) is a** network layer protocol** used to diagnose communication errors by performing an error control mechanism. Since IP does not have an inbuilt mechanism for sending error and control messages. It depends on Internet Control Message Protocol(ICMP) to provide error control.
Ping is a simple kind of traceroute known as the echo-request message, it is used to measure the time taken by data to reach the destination and return to the source, these replies are known as echo-replies messages.
DNS
DNS 可以使用 UDP 或者 TCP 进行传输,使用的端口号都为 53。
大多数情况下 DNS 使用 UDP 进行传输 (due to its speed and low overhead) ,这就要求域名解析器和域名服务器都必须自己处理超时和重传从而保证可靠性。
在两种情况下会使用 TCP 进行传输:
- 如果返回的响应超过的 512 字节 (UDP 最大只支持 512 字节的数据)
- or if a server is managing zone transfers (the transferring of DNS records from primary to secondary DNS servers) or similar tasks
但是,这里就有个问题了。UDP支持的最大数据不是受限于以太网帧的MTU1500字节吗?那么计算下来,也应该是1500-20-8=1472字节啊。怎么就是512了?
解答 进行了一波搜索,终于找到原因了。以太网帧在局域网中的MTU (Maximum Transmit Unit)是1500byte,但是在非局域网环境,如:internet下的时候,MTU是各个路由器进行一个配置的。所以,通常路由器默认的MTU为576字节。所以,为了适应网络环境,DNS协议在返回的数据报大于512的时候,就转化为了TCP协议。
tcp mss
TCP 数据包每次能够传输的最大数据分段称为 MSS(Maxitum Seament Size),为了达到最佳的传输效能,在建立 TCP 连接时双方协商 MSS 值,双方提供的 MSS 值的最小值为这次连接的最大 MSS 值。MSS 往往基于 MTU 计算出来,通常 MSS=MTU-sizeof(IP Header)-sizeof(TCP Header)=1500-20-20=1460.
Tcp建立连接的时候,必须进行三次握手,在前两个握手包中,双方互相声明了自己的MSS
- [三次握手中协商了 MSS 就不会改变了吗?] 当然不是,每次执行 TCP 发送消息的函数时,会重新计算一次 MSS,再进行分段操作。
- [对端不传 MSS 会怎么样?]
-
其实 MSS 是作为可选项引入的,只不过一般情况下 MSS 都会传,但是万一遇到了哪台机器的实现上比较调皮,不传 MSS这个可选项。那对端该怎么办?
-
如果没有接收到对端 TCP 的 MSS,本端 TCP 默认采用 MSS=536Byte**。
-
536(data) + 20(tcp头)+20(ip头)= 576Byte
-
前面提到了 IP 会切片,那会切片,也就会重组,而这个 576 正好是 IP 最小重组缓冲区的大小。
-
mtu
MTU: Maximum Transmit Unit,最大传输单元。 其实这个是由数据链路层提供,为了告诉上层 IP 层,自己的传输能力是多大。IP 层就会根据它进行数据包切分。一般 MTU=1500 Byte。
[为什么 IP 层会分片,TCP 还要分段]
假设有一份数据,较大,且在 TCP 层不分段,如果这份数据在发送的过程中出现丢包现象,TCP 会发生重传,那么重传的就是这一大份数据(虽然 IP 层会把数据切分为 MTU 长度的 N 多个小包,但是 TCP 重传的单位却是那一大份数据)。
数据在 TCP 分段,就是为了在发生重传的时候只重传分段后的小份数据。
[TCP 分段了,IP 层就一定不会分片了吗]
整个传输链路中,可能还会有其他网络层设备,而这些设备的 MTU 可能小于发送端的 MTU。此时虽然数据包在发送端已经分段过了,但是在 IP 层就还会再分片一次。
如果链路上还有设备有更小的 MTU,那么还会再分片,最后所有的分片都会在接收端处进行组装。
[IP 层怎么做到不分片]
如果有办法知道整个链路上,最小的 MTU 是多少,并且以最小 MTU 长度发送数据,那么不管数据传到哪个节点,都不会发生分片。
整个链路上,最小的 MTU,就叫 PMTU(path MTU)。
有一个获得这个 PMTU 的方法,叫 Path MTU Discovery。
$cat /proc/sys/net/ipv4/ip_no_pmtu_disc
0
默认为0,意思是开启 PMTU 发现的功能。现在一般机器上都是开启的状态。
原理比较简单,首先我们先回去看下 IP 的数据报头。
这里有个标红的标志位DF(Don't Fragment),当它置为 1,意味着这个 IP 报文不分片。
当链路上某个路由器,收到了这个报文,当 IP 报文长度大于路由器的 MTU 时,路由器会看下这个 IP 报文的DF
-
如果为
0(允许分片),就会分片并把分片后的数据传到下一个路由器 -
如果为
1,就会把数据丢弃,同时返回一个 ICMP (Internet Control Message Protocol) 包给发送端,并告诉它"达咩!"数据不可达,需要分片,同时带上当前机器的 MTU
iptables
Iptables is used to set up, maintain, and inspect the tables of IP packet filter rules in the Linux kernel. Several different tables may be defined. Each table contains a number of built-in chains and may also contain user-defined chains.
Each chain is a list of rules which can match a set of packets. Each rule specifies what to do with a packet that matches. This is called a 'target', which may be a jump to a user-defined chain in the same table.
ssh (Secure Shell)
过程:
(1)远程主机收到用户的登录请求,把自己的公钥发给用户。(2)用户使用这个公钥,将登录密码加密后,发送回来。(3)远程主机用自己的私钥,解密登录密码,如果密码正确,就同意用户登录。
中间人攻击
这个过程本身是安全的,但是实施的时候存在一个风险:如果有人截获了登录请求,然后冒充远程主机,将伪造的公钥发给用户,那么用户很难辨别真伪。因为不像https协议,SSH协议的公钥是没有证书中心(CA)公证的,也就是说,都是自己签发的。
可以设想,如果攻击者插在用户与远程主机之间(比如在公共的wifi区域),用伪造的公钥,获取用户的登录密码。再用这个密码登录远程主机,那么SSH的安全机制就荡然无存了。这种风险就是著名的["中间人攻击"](Man-in-the-middle attack)。
SSH协议是如何应对的呢?
口令登录 (确认公钥指纹)
如果你是第一次登录对方主机,系统会出现下面的提示:
$ ssh user@host
The authenticity of host 'host (12.18.429.21)' can't be established.
RSA key fingerprint is 98:2e:d7:e0:de:9f:ac:67:28:c2:42:2d:37:16:58:4d.
Are you sure you want to continue connecting (yes/no)?
这段话的意思是,无法确认host主机的真实性,只知道它的公钥指纹,问你还想继续连接吗?
所谓"公钥指纹",是指公钥长度较长(这里采用RSA算法,长达1024位),很难比对,所以对其进行MD5计算,将它变成一个128位的指纹。上例中是98:2e:d7:e0:de:9f:ac:67:28:c2:42:2d:37:16:58:4d,再进行比较,就容易多了。
很自然的一个问题就是,用户怎么知道远程主机的公钥指纹应该是多少?回答是没有好办法,远程主机必须在自己的网站上贴出公钥指纹,以便用户自行核对。
当远程主机的公钥被接受以后,它就会被保存在文件$HOME/.ssh/known_hosts之中。下次再连接这台主机,系统就会认出它的公钥已经保存在本地了,从而跳过警告部分,直接提示输入密码。
每个SSH用户都有自己的known_hosts文件,此外系统也有一个这样的文件,通常是/etc/ssh/ssh_known_hosts,保存一些对所有用户都可信赖的远程主机的公钥。
公钥登录
使用密码登录,每次都必须输入密码,非常麻烦。好在SSH还提供了公钥登录,可以省去输入密码的步骤。
所谓"公钥登录",原理很简单,就是用户将自己的公钥储存在远程主机上。登录的时候,远程主机会向用户发送一段随机字符串,用户用自己的私钥加密后,再发回来。远程主机用事先储存的公钥进行解密,如果成功,就证明用户是可信的,直接允许登录shell,不再要求密码。
这种方法要求用户必须提供自己的公钥。如果没有现成的,可以直接用ssh-keygen生成一个:
参考:ruanyifeng.com/blog/2011/1…
ssl tls
SSL 表示 Secure Sockets Layer(安全套接字层)。 | TLS 表示 Transport Layer Security(传输层安全)。
安全套接字层(SSL)是一种通信协议或一组规则,用于在网络上的两个设备或应用程序之间创建安全连接。传输层安全性协议(TLS)是 SSL 的升级版本,用于修复现有 SSL 漏洞,以及更高效地进行身份验证.
所有版本的 SSL 目前均已弃用。在大多数情况下,SSL 都是指 TLS 协议和 TLS 证书。
three primary services
TLS provides three primary services that help ensure the safety and security of data exchanged with it:
-
[Authentication]
Authentication lets each party to the communication verify that the other party is who they claim to be.
-
[Encryption]
Data is encrypted while being transmitted between the user agent and the server, in order to prevent it from being read and interpreted by unauthorized parties.
-
[Integrity]
TLS ensures that between encrypting, transmitting, and decrypting the data, no information is lost, damaged, tampered with, or falsified.
A TLS connection starts with a handshake phase where a client and server agree on a shared secret and important parameters, like cipher suites, are negotiated. Once parameters and a data exchange mode where application data, such HTTP, is exchanged.
https
SSL/TLS 证书中包含哪些内容?
SSL/TLS 证书包含以下信息。
- 域名
- 证书颁发机构
- 证书颁发机构的数字签名
- 颁发日期
- 到期日期
- 公钥
- SSL/TLS 版本
为什么数字证书是可信的?
浏览器会验证 SSL/TLS 证书
CAs establish ownership of their signing key by holding a self-issued certificate (called the root) for the corresponding public key.
签名过程:
- A计算消息m的消息摘要,记为 h(m)
- A使用私钥(n,d)对h(m)加密,生成签名s, s满足:s=(h(m))^d mod n;
由于A是用自己的私钥对消息摘要加密,所以只用使用s的公钥才能解密该消息摘要,这样A就不可否认自己发送了该消息给B. - A发送消息和签名(m,s)给B
验签过程:
- B计算消息m的消息摘要(计算方式和A相同),记为h(m)
- B使用A的公钥(n,e)解密s,得到 H(m), H(m) = s^e mod n
- B比较H(m)与h(m),相同才能证明验签成功
http vs http2
- 新的二进制格式
- 多路复用
- HTTP2采用多路复用是指,在同一个域名下,开启一个TCP的connection,每个请求以stream的方式传输,每个stream有唯一标识,connection一旦建立,后续的请求都可以复用这个connection并且可以同时发送,server端可以根据stream的唯一标识来响应对应的请求。
- 服务端推送
- server push功能:在无需客户端请求资源的情况下,服务端会直接推送客户端可能需要的资源到客户端。当服务器想用Server Push推送资源时,会先向客户端发送PUSH PROMISE帧,因为推送的响应必须与客户端的某个请求相关联
- header 压缩
- Flow Control, receiver 端可以对某些stream进行流控也可以针对整个connection流控
- 主动重置链接
-
HTTP1的body的length的被送给客户端后,服务端就无法中断请求了,只能断开整个TCP connecion,但这样导致的代价就是需要重新通过三次握手建立-个新的TCP连接。
HTTP2引入了一个 RST_STREAM frame 来让客户端在已有的连接中发送重置请求,从而中断或者放弃响应。当浏览器进行页面跳转或者用户取消下载时它可以防止建立新连接,避免浪费所有带宽。
-
URL vs URI
- URL:Uniform Resource Locator 统一资源定位符;
- URI: Uniform Resource Identifier 统一资源标识符;
轮询 长轮询
- 在 HTTP1.1 里。只要客户端不问,服务端就不答。基于这样的特点,对于登录页面这样的简单场景,可以使用定时轮询或者长轮询的方式实现服务器推送(comet)的效果。
- 对于客户端和服务端之间需要频繁交互的复杂场景,比如网页游戏,都可以考虑使用 websocket 协议。
短轮询
轮询的原理就是客户端以一定的时间间隔向服务端发出请求,频繁的请求保持客户端和服务端同步。
长轮询
页面发起一个到服务器的请求,然后服务器一直保持连接打开,直到有数据可以发送。
优点:在无消息的情况下不会频繁的请求,节省了网络流量,解决了服务端一直疲于接受请求的窘境。
缺点:服务器hold连接会消耗资源,需要同时维护多个线程,服务器所能承载的TCP连接数是有上限的,这种轮询很容易把连接数顶满。
一台机器最多建立多少个tcp链接
On the TCP level the tuple (source ip, source port, destination ip, destination port) must be unique for each simultaneous connection. That means a single client cannot open more than 65535 (TCP端口号是16位无符号整数,最大65535) simultaneous connections to a single server. But a server can (theoretically) serve 65535 simultaneous connections per client.
TCP连接的服务器机:每一个监听的端口虽然理论值很大、但这个数字没有实际意义。最大并发数取决你的内存大小,每一条静止状态的TCP连接大约需要吃3.3K的内存。 假设你只保持连接不发送数据,那么你服务器可以建立的连接最大数量 = 你的内存/3.3K。 假如是4GB的内存,那么大约可接受的TCP连接数量是100万左右。 zhuanlan.zhihu.com/p/290651392
DNS
DNS(Domain Name System,域名系统),因特网上作为域名和IP地址互相映射的一个分布式数据库,能够使用户更方便的访问互联网,而不用去记住能够被机器直接读取的IP数串。通过主机名,最终得到该主机对应的IP地址的过程叫做域名解析(或主机名解析)。DNS协议运行在UDP协议之上,使用端口号53。
DNS系统的作用
正向解析:根据主机名称(域名)查找对应的IP地址
反向解析:根据IP地址查找对应的主机域名
浏览器请求到web服务器的全过程
- 域名解析
- 1、浏览器检查浏览器缓存中是否存在该域名与IP地址的映射关系,如果有则解析结束,没有则继续
- 2、到系统本地查找映射关系,一般在hosts文件中,如果有则解析结束,否则继续
- 3、到本地域名服务器去查询,有则结束,否则继续(mac用此命令看本地域名服务器cat /etc/resolv.conf)
- 4、本地域名服务器查询根域名服务器,该过程并不会返回映射关系,只会告诉你去下级服务器(顶级域名服务器)查询
- 5、本地域名服务器查询顶级域名服务器(即com服务器),同样不会返回映射关系,只会引导你去二级域名服务器查询
- 6、本地域名服务器查询二级域名服务器(即baidu.com服务器),引导去三级域名服务器查询
- 7、本地域名服务器查询三级域名服务器(lmail.baidu.comn服务器),此时已经是最后一级了,如果有则返回映射关系、则本地域名服务器加入自身的映射表中,方便下次查询或其他用户查找,同时返回给该用户的计算机,没有找到则网页报错
- 8、如果还有下级服务器,则依此方法进行查询,直至返回映射关系或报错
- 与服务器建立连接,tcp 3次握手
- 发起http请求
- 服务器响应HTTP请求,浏览器得到html代码
- 浏览器解析html代码,并请求html代码中的资源(如is、css、图片)
- 浏览器对页面进行渲染呈现给用户
NAT
- Network Address Translator,网络地址转换
To access the Internet, one public IP address is needed, but we can use a private IP address in our private network. The idea of NAT is to allow multiple devices to access the Internet through a single public address.
是用于在本地网络中使用私有地址,在连接互联网时转而使用全局 IP 地址的技术。NAT实际上是为解决[IPv4地址短缺]而开发的技术。
Loopback address
A loopback address is a distinct reserved IP address range that starts from 127.0.0.0 and ends at 127.255.255.255 though 127.255.255.255 is the broadcast address for 127.0.0.0/8. The loopback addresses are built into the IP domain system.
127.0.0.1 is generally known as localhost.
TCP/IP protocol manages all the loopback addresses in the operating system. It mocks the TCP/IP server or TCP/IP client on the same system.
broadcast address
Each network or [subnet] has a reserved broadcast address that can be used by all participants of the network to send a [broadcast]. Broadcasts allow information and services to be transmitted to all devices and components of the network without the need to know their individual [IP addresses]. Among other things, routers in a local area network use the broadcast IP to send HELLO packets to all endpoints, switches, and other routers to maintain interrelationships on the network and discover neighboring devices.
长连接 短连接
zhuanlan.zhihu.com/p/484645386
短连接
短连接的优缺点 管理起来比较简单,存在的连接都是有用的连接,不需要额外的控制手段。
使用场景 通常浏览器访问服务器的时候就是短连接。对于服务端来说,长连接会耗费服务端的资源,如果有几十万,上百万的连接,服务端的压力会非常大,甚至会崩溃。
所以对于并发量大,请求频率低的,建议使用短连接。
什么是长连接
client向server发起连接,server接受client连接,双方建立连接。
Client与server完成一次读写之后,它们之间的连接并不会主动关闭,后续的读写操作会继续使用这个连接。
长连接的生命周期
正常情况下,一条TCP长连接建立后,只要双不提出关闭请求并且不出现异常情况,这条连接是一直存在的.操作系统不会自动去关闭它。
优缺点
- 长连接可以省去较多的TCP建立和关闭的操作耗时
- 减少CPU及内存的使用,因为不需要经常的建立及关闭连接
缺点:
- 连接数过多时,影响服务端的性能和并发数量
使用场景 数据库的连接就是采用TCP长连接.
RPC,远程服务调用,在服务器,一个服务进程频繁调用另一个服务进程,可使用长连接,减少连接花费的时间。
长连接的实现
心跳机制
应用层协议大多都有HeartBeat机制,通常是客户端每隔一小段时间向服务器发送一个数据包,通知服务器自己仍然在线。 并传输一些可能必要的数据。使用心跳包的典型协议是IM,比如QQ等协议。 在TCP的机制里面,本身是存在有心跳包的机制的,setsockopt SO_KEEPALIVE
tcp keepalive
默认KeepAlive状态是不打开的。 需要setsockopt将SO_KEEPALIVE设置为1才是打开状态 (SO_KEEPALIVE: Enable sending of keep-alive messages on connection- oriented sockets. )
What is TCP keepalive?
The keepalive concept is very simple: when you set up a TCP connection, you associate a set of timers. Some of these timers deal with the keepalive procedure. When the keepalive timer reaches zero, you send your peer a keepalive probe packet with no data in it and the ACK flag turned on. You can do this because of the TCP/IP specifications, as a sort of duplicate ACK, and the remote endpoint will have no arguments, as TCP is a stream-oriented protocol. On the other hand, you will receive a reply from the remote host (which doesn't need to support keepalive at all, just TCP/IP), with no data and the ACK set.
If you receive a reply to your keepalive probe, you can assert that the connection is still up and running without worrying about the user-level implementation. In fact, TCP permits you to handle a stream, not packets, and so a zero-length data packet is not dangerous for the user program.
This procedure is useful because if the other peers lose their connection (for example by rebooting) you will notice that the connection is broken, even if you don't have traffic on it. If the keepalive probes are not replied to by your peer, you can assert that the connection cannot be considered valid and then take the correct action.
Why use TCP keepalive?
it generates extra network traffic, which can have an impact on routers and firewalls.
two target tasks for keepalive:
- Checking for dead peers
- Preventing disconnection due to network inactivity
Checking for dead peers
A和B建立连接后B重启
The situation resolves itself when A tries to send data to B over the dead connection, and B replies with an RST packet, causing A to finally to close the connection.
Preventing disconnection due to network inactivity
It's a very common issue, when you are behind a NAT proxy or a firewall, to be disconnected without a reason. This behavior is caused by the connection tracking procedures implemented in proxies and firewalls, which keep track of all connections that pass through them. Because of the physical limits of these machines, they can only keep a finite number of connections in their memory. The most common and logical policy is to keep newest connections and to discard old and inactive connections first.
Because the normal implementation puts the connection at the top of the list when one of its packets arrives and selects the last connection in the queue when it needs to eliminate an entry, periodically sending packets over the network is a good way to always be in a polar position with a minor risk of deletion.
tcp_keepalive 选项 under Linux
tcp_keepalive_intvl (integer; default: 75; since Linux 2.4)
The number of seconds between TCP keep-alive probes.
tcp_keepalive_probes (integer; default: 9; since Linux 2.2)
The maximum number of TCP keep-alive probes to send before
giving up and killing the connection if no response is
obtained from the other end.
tcp_keepalive_time (integer; default: 7200; since Linux 2.2)
The number of seconds a connection needs to be idle before
TCP begins sending out keep-alive probes. Keep-alives are
sent only when the SO_KEEPALIVE socket option is enabled.
The default value is 7200 seconds (2 hours). An idle
connection is terminated after approximately an additional
11 minutes (9 probes an interval of 75 seconds apart) when
keep-alive is enabled.
Note that underlying connection tracking mechanisms and
application timeouts may be much shorter.
socket
www.cs.cornell.edu/courses/cs4…
A socket is a method for accomplishing inter-process communication (IPC)
- Allows one process to communicate with another process on the same or different machine
ip
ip地址表示
IP地址分类
- A类:10.0.0.0到127.255.255.255主要分配给大量主机而局域网网络数量较少的大型网络
- B类:128.0.0.0到191.255.255.255一般用于国际性大公司和政府机构
- C类:192.0.0.0到223.255.255.255用于一般小公司校园网研究机构等
- D类:224.0.0.0到239.255.255.255用于特殊用途,又称作广播地址
- E类:240.0.0.0到255.255.255.255暂时保留
为什么家里的IP都是192.168开头的
当我们家里的设备连接到局域网时,它们通常会获得一个以192.168开头的IP地址。 这是因为192.168.x.x是C类私有地址的一个子网,被广泛用于家庭和小型企业网络中。
子网掩码
- 子网掩码用于识别ip地址中的网络地址和主机地址。
- 子网掩码也是32位二进制数字,在子网掩码中,对应于网络地址部分全用1表示,主机部分全用0表示
- 还可以用网络前缀表示子网掩码,即"/<网络地址位数>",如172.16.45.0/24表示B类网络172.16.45.0的子网掩码为255.255.255.0
子网划分
子网划分是通过借用ip地址的若干位主机位来充当子网地址的从而将原来的网络分为若干个彼此隔离的子网实现的
子网划分步骤
- 确定要划分的子网数以及每个子网的主机数
- 求出子网数目对应的二进制的位数N及主机数目对应的二进制数的位数M
- 对该ip地址的原子网掩码,将其主机地址部分的前N位置1(其余全部置0)或后M位置0(其余全置1)即得出该ip地址划分子网后的子网掩码
子网划分案例
给C类网络211.168.10.0划分5个子网
2^2-2<5<2^3-2所以需要3位网络号,主机号为8-3=5
子网掩码为255.255.255.224
每个子网可容纳2^5-2=30台主机
VLAN(Virtual Local area network)
info.support.huawei.com/info-finder…
早期以太网是一种基于CSMA/CD(Carrier Sense Multiple Access/Collision Detection)的共享通讯介质的数据网络通讯技术。当主机数目较多时会导致冲突严重、广播泛滥、性能显著下降甚至造成网络不可用等问题。通过二层设备实现LAN互连虽然可以解决冲突严重的问题,但仍然不能隔离广播报文和提升网络质量。
在这种情况下出现了VLAN技术。这种技术可以把一个LAN划分成多个逻辑的VLAN,每个VLAN是一个广播域,VLAN内的主机间通信就和在一个LAN内一样,而VLAN间则不能直接互通,广播报文就被限制在一个VLAN内。如下图所示。
VLAN vs 子网
通过将IP地址的网络部分进一步划分为若干个子网,可以解决IP地址空间利用率低和两级IP地址不够灵活的问题。
与VLAN相类似的是,子网也可以隔离主机间的通信。属于不同VLAN的主机之间不能直接通信,属于不同的子网的主机之间也不能直接通信。但二者没有必然的对应关系。
nat工作原理
cloud.tencent.com/developer/a…
NAT路由器会将IP数据包里的源IP地址和端口号修改一下,从192.168.30.5:5000改写成20.20.20.20:6000。并且还会在NAT路由器内部留下一条 192.168.30.5:5000 -> 20.20.20.20:6000的映射记录。之后数据包经过公网里各个路由器的转发,发到了接收端30.30.30.30:3000,到这里发送流程结束
接收数据时,NAT路由器发现下自己之前留下过这么一条 192.168.30.5:5000 -> 20.20.20.20:6000的记录,就会将这个数据包的目的IP地址和端口修改一下,变回原来的192.168.30.5:5000。之后将其转发给你的电脑上
[两个内网的应用如何直接建立连接]
上面的情况,是两个客户端通过第三方服务器进行通讯,但有些场景就是要抛开第三端,直接进行两端通信,比如 P2P 下载,这种该怎么办呢?
这种情况下,其实也还是离不开第三方服务器的帮助。
假设还是 A 和 B 两个局域网内的机子,A 内网对应的 NAT 设备叫NAT_A,B 内网里的 NAT 设备叫NAT_B,和一个第三方服务器server。
流程如下。
step1 和 2: A 主动去连 server,此时 A 对应的NAT_A就会留下 A 的内网地址和外网地址的映射关系,server 也拿到了 A 对应的外网 IP 地址和端口。
step3 和 4: B 的操作和 A 一样,主动连第三方 server,NAT_B内留下 B 的内网地址和外网地址的映射关系,然后 server 也拿到了 B 对应的外网 IP 地址和端口。
step5 和 step6 以及 step7: 重点来了。此时 server 发消息给 A,让 A 主动发UDP消息到 B 的外网 IP 地址和端口。此时 NAT_B 收到这个 A 的 UDP 数据包时,这时候根据 NAT_B 的设置不同,导致这时候有可能NAT_B 能直接转发数据到 B,那此时 A 和 B 就通了。但也有可能不通,直接丢包,不过丢包没关系,这个操作的目的是给 NAT_A 上留下有关 B 的映射关系。
step8 和 step9 以及 step10: 跟 step5 一样熟悉的配方,此时 server 再发消息给 B,让 B 主动发UDP消息到 A 的外网 IP 地址和端口。NAT_B 上也留下了关于 A 到映射关系,这时候由于之前 NAT_A 上有过关于 B 的映射关系,此时 NAT_A 就能正常接受 B 的数据包,并将其转发给 A。到这里 A 和 B 就能正常进行数据通信了。这就是所谓的NAT 打洞。
step11: 注意,之前我们都是用的UDP 数据包,目的只是为了在两个局域网的 NAT 上打个洞出来,实际上大部分应用用的都是 TCP 连接,所以,这时候我们还需要在 A 主动向 B 发起 TCP 连接。到此,我们就完成了两端之间的通信。
[端口已经被 udp 用过了,TCP 再用,那岂不是端口重复占用(address already in use)?]
其实并不会,端口重复占用的报错常见于两个 TCP 连接在不使用SO_REUSEADDR的情况下,重复使用了某个 IP 端口。而 UDP 和 TCP 之间却不会报这个错。之所以会有这个错,主要是因为在一个 linux 内核中,内核收到网络数据时,会通过五元组(传输协议,源IP,目的IP,源端口,目的端口)去唯一确定数据接受者。当五元组都一模一样的时候,内核就不知道该把数据发给谁。而 UDP 和 TCP 之间"传输协议"不同,因此五元组也不同,所以也就不会有上面的问题。
集线器、交换机、路由器、光猫
cloud.tencent.com/developer/a…
- 两台电脑可以通过一根网线直接连接,进行通信。
- 机器一多,可以把网线都接到集线器(物理层)上,但是集线器会不管三七二十一进行广播。
- 不想广播,可以用(二层)交换机(数据链路层),又叫多端口网桥,它比较聪明,会自我学习生产MAC地址表,知道消息发到哪,那就不需要广播啦
- 互联网电脑这么多,交换机MAC地址表总不能全放下吧。改用路由器(网络层),也叫三层交换机,通过网段的方式定位要把消息转发到哪,就不需要像交换机那样苦哈哈一条条记录MAC地址啦。
- 路由器和光猫之间是好搭档,光猫负责把光纤里的光信号转换成电信号给路由器。
- 现在一般情况下,家里已经不用集线器和交换机了,大部分路由器也支持交换机的功能。所以可以看到,家里的台式机电脑一般就连到一个路由器,再连个光猫就够能快乐上网了。