端口
【网络通信必备IP和端口】
端口就类似一个房子的门,是出入这间房子(进程)的必经之路
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ebBbOjsX-1596703074877)(D:\学习笔记\放在typora里的图片\1595255328455.png)]
端口是通过端口号来标记的,端口号只有整数,端口号按照一定的规定进行分配。端口的分类标准:
- 知名端口:众所周知的端口,范围从0到1023
80端口分配给HTTP服务
21端口分配给FTP服务 - 动态端口:范围从1024到65535,动态端口一般不固定分配某种服务,而是动态分配;
动态分配指的是当一个系统程序或应用程序需要网络通信时,它向主机申请一个端口,主机从可用的端口号中分配一个供它使用;当这个程序关闭时,同时也就释放了所占用的端口号。
总结:
一台拥有IP地址的主机可以提供许多服务,如HTTP(万维网服务)、FTP(文件传输)、SMTP(电子邮件)等。这些服务完全可以通过一个IP地址来实现。IP地址和网络服务是一对多的关系,主机想要区分不同的网络服务,就需要通过“IP地址+端口”的方式。需要注意的是,端口并不是一一对应的,服务器用80端口来与客户端通信的时候,客户端的端口不一定是80。
域名和端口号:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-e6NjJGdK-1596703074879)(D:\学习笔记\放在typora里的图片\1595607769304.png)]
Socket
不同电脑上的进程之间如何通信:
首先要解决的问题就是如何唯一标识一个进程。在1台电脑上可以通过进程号PID来唯一标识一个进程,但在网络中行不通。
TCP/IP协议中解决了这个问题,网络层的“IP地址”可以唯一标识网络中的主机,而传输层的“协议+端口”可以唯一标识主机中的应用进程。
这样利用IP地址+协议+端口就可以标识网络中的进程了。网络中的进程通信就可以利用这个标志与其他进程进行交互。
【网络通信就是两台主机的运行程序之间的数据共享】
socket介绍
socket(套接字)是进程间通信的一种方式,它与其他进程间通信的一个主要不同是:它能实现不同主机间的通信。我们网络上各种各样的服务大多都是基于Socket来完成通信的。【Socket是网络通信必备的东西】
创建socket
使用socket模块中的socket函数,该函数带有两个参数:
import socket
socket.socket(AddressFamily,Type)
- AddressFamily(协议域/协议族):可以选择AF_INET(用于Internet进程间通信)或者AF_UNIX(同于同一台机器进程间通信),实际工作中常用AF_INET
- Type:套接字类型,可以是SOCK_STREAM(流式套接字,主要用于TCP协议)或者SOCK_DGRAM(数据报套接字,主要用于UDP协议)
创建一个tcp socket
import socket
#创建tcp套接字
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#...这里使用套接字的功能
#不用的时候,关闭套接字
s.close()
创建一个udp socket
import socket
#创建udp套接字
s = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
#...这里使用套接字的功能
#不用的时候,关闭套接字
s.close()
套接字使用流程和文件使用流程类似:
【因为socket起源于Unix,而Unix/Linux基本哲学之一就是“一切皆文件”,都可以用“打开open –> 读写write/read –> 关闭close”模式来操作】
- 创建套接字 打开文件
- 使用套接字收/发数据 使用文件进行读/写
- 关闭套接字 关闭文件
udp网络通信
UDP通信模型中,在通信开始之前,不需要建立相关的链接,直接发送数据即可。UDP通信模型:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aoFPw9J5-1596703074882)(D:\学习笔记\放在typora里的图片\1595321659720.png)]
用upd套接字发送数据:
import socket
# 1.创建udp套接字
udp_socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
# 2.准备接收方的地址
# 注意!括号里是元组,目的IP地址是字符串,目的端口号是int
dest_addr = ('192.168.1.103',8080)
# 从键盘获取数据
send_data = input('请输入要发送的内容:')
# 3.用sendto函数发送数据到指定电脑上的指定端口的程序中
udp_socket.sendto(send_data.encode('utf-8'),dest_addr)
# 也可以把2和3合在一起写
udp_socket.sendto(b'hahaha',('192.168.1.103',8080))
# 4.关闭套接字
udp_socket.close()
流程为:
- 创建套接字s
- s.sendto(数据.encode(‘utf-8’),(IP,port))
- s.close()
用upd套接字接收数据:
import socket
# 1.创建套接字
s = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
# 2.绑定本地信息
# IP地址不用写,表示本机的任意一个IP
local_addr = ('',7788)
s.bind(local_addr)
# 3.等待接收对方发送的数据
# 1024表示本次接收的最大字节
data = s.recvfrom(1024)
# 4.显示接收到的数据
# data变量中存储的是收到的数据,
# 是一个元组:(发送的消息的utf-8编码,(发送方IP,发送方port))
# 所以这里把发送的消息取出来并解码
print(data[0].decode('utf-8'))
# 5.关闭套接字
s.close()
流程为:
-
创建套接字s
-
绑定本地信息 s.bind((’’,port)) 注意里面是元组!!
-
接收信息并解码
data = s.recvfrom(字节大小)
tem = data[0].decode(‘utf-8’)
-
s.close()
如果发送数据时没绑定端口,操作系统会随机分配一个端口号【就是单例模式】
先绑定端口再发送:
import socket
# 1.创建套接字
s = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
# 2.绑定端口
s.bind(('',7890))
# 3.发送
s.sendto('1234'.encode('utf-8'),('192.168.1.23',8080))
# 4.关闭
s.close()
recvfrom()在没有数据到来时,会阻塞
可以用同一个套接字发、收数据;套接字是可以同时收发数据的
import socket
def func():
# 创建套接字
s = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
# 绑定本地信息
s.bind(('',7788))
# 获取对方的ip/port
dest_ip = input('请输入对方IP:')
dest_port = int(input('请输入port:'))
# 从键盘获取数据
send_data = input('请输入要发送的数据')
#使用套接字发送数据
s.sendto(send_data.encode('utf-8'),(dest_ip,dest_port))
#接收回送过来的数据
recv_data = s.recvfrom(1024)
print(recv_data)
# 关闭套接字
s.close()
单工:只能单向走;也就是只能收(收音机)
半双工:可以双向走,但是同一时刻只能单向;收的时候发不了,发的时候收不了(对讲机)
全双工:同一时刻既能收也能发;socket套接字是全双工
TCP网络通信
TCP协议:传输控制协议,是一种面向连接的、可靠的、基于字节流的传输层通信协议
TCP通信需要经过创建连接、数据传送、终止连接三个步骤;
TCP实现可靠传输:
- TCP采用发送应答机制:TCP发送的每个报文段都必须得到接收方的应答才认为这个TCP报文段传输成功
- 超时重传:发送端发出一个报文段后就启动定时器,如果在定时时间内没有收到应答就重新发送这个报文段。
TCP为了保证不发生丢包,就给每个包一个序号,同时序号也保证了传送到接收端实体的包的按序接收。然后接收端实体对已成功收到的包发回一个相应的确认ACK,如果发送端实体在合理的往返时延RTT内未收到确认,那么对应的数据包就被假设为已丢失并进行重传 - 错误校验:TCP用一个校验和函数来检验数据是否有错误;在发送和接收时都要计算校验和;
- 流量控制和阻塞管理:用来避免发送方发送得过快而使接收方来不及完全收下
TCP通信模型:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HJvS4Pej-1596703074885)(D:\学习笔记\放在typora里的图片\1595321784073.png)]
###TCP严格区分客户端和服务器:
服务器端:提供服务的一方;客户端:需要被服务的一方
TCP客户端
TCP的客户端比服务端简单很多,示例代码如下:
from socket import *
# 1.创建套接字
s = socket(AF_INET,SOCK_STREAM)
# 目的信息
server_ip = input('请输入服务器ip:')
server_port = input('请输入服务器port:')
# 2.链接服务器,注意是元组!【这里就是和UDP的不同】
s.connect((server_ip,server_port))
# 3.发送数据/接收数据
send_data = input('请输入要发送的数据:')
s.send(send_data.encode('utf-8'))
# 接收对方发来的数据,最大接收1024个字节
recv = s.recv(1024)
print(recv.decode('utf-8'))
# 4.关闭套接字
s.close()
流程为:
- 创建socket
- connect链接服务器
- 发/收数据
- 关闭socket
TCP服务器
想要完成tcp服务器的功能,需要以下流程:
- socket创建一个套接字
- bind绑定ip和port
- listen使套接字变为可以被动链接
- accept等待客户端的链接
- recv/send接收/发送数据
from socket import *
# 1.创建套接字
s = socket(AF_INET,SOCK_STREAM)
# 2.bind本地ip和port
s.bind(('',7890))
# 3.listen使套接字变为被动链接
# 使用socket创建的套接字默认是主动的,使用listen将其变成被动的,就可以接收别人的链接了
s.listen(128)
# 4.accept等待客户端的链接
# accept的返回值是一个元组,用两个变量进行拆包
# 第一个变量client_socket用来产生一个新的套接字,负责通信
# 第二个变量clientAddr用来接收链接客户端的地址(IP和port)
# 原来的套接字s只负责等待客户端链接,也就是负责监听
# 监听套接字负责等待有新的客户端进行链接;监听套接字默认阻塞,直到有新客户端链接
# accept产生的新的套接字用来为客户端服务
client_socket, clientAddr = s.accept()
# 5.用accept产生的新套接字来接收数据
# 如果recv()解堵塞,那么有2种方式:
# if recv,说明客户端发送的数据不为空,
# else,说明recv为None,客户端调用了close()关闭了套接字
recv = client_socket.recv(1024)
print(recv.decode('utf-8'))
#发送数据给客户端
client_socket.send('123'.encode('utf-8'))
# 6.关闭俩套接字
client_socket.close()
s.close()
TCP注意点:
【客户端一般不绑定,如果绑定了,就不能多开了,因为端口是唯一的;或者如果运行程序之前这个端口被占,那么这个程序也无法运行】
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jONs8qgb-1596703074886)(D:\学习笔记\放在typora里的图片\1595406626863.png)]
TCP和UDP的不同点
现在大多都用TCP
- TCP面向连接(三次握手确定连接已创建才传输)
- 有序数据传输
- 超时重传
- 舍弃重复的数据包
- 无差错的数据传输
- 阻塞/流量控制
HTTP协议
协议就是一种规范 一种约束;HTTP协议:是浏览器和服务器之间的用来传输的一种规定。浏览器是客户端!!网站就是服务器
HTTP超文本传输协议:浏览器发送数据,自己写的TCP服务器程序解析数据,并把数据按照一定规则发给浏览器,浏览器就可以显示页面内容了。HTTP规定了:不管是什么,首先用TCP协议,其次要发送怎样格式的数据,这样就不会出现不同浏览器访问不了同一个服务器的问题。
协议:规定数据传输的格式
浏览器向服务器发送的请求格式:【就是请求头信息】
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sYNHdu2c-1596703074887)(D:\学习笔记\放在typora里的图片\1595421146924.png)]
服务器向浏览器回送的响应格式:【就是响应头信息 header】
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-r2Pc1GqY-1596703074887)(D:\学习笔记\放在typora里的图片\1595421520679.png)]
请求是怎样的,响应是怎样的,这些都是HTTP协议规范的。
在TCP服务器的代码中,TCP套接字s.send(data.encode(‘utf-8’))发送的数据data,只要按照头信息的格式来进行组织,发过去之后浏览器就会把data里的数据认为是HTTP协议,就会按照HTTP协议的形式来组织,在15到19行:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ca81GSpt-1596703074888)(D:\学习笔记\放在typora里的图片\1595424026962.png)]
实现并发服务器
多进程
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bIDRhmGp-1596703074889)(C:\Users\cxy\AppData\Local\Temp\1595490027444.png)]
多线程
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-C5F5Exsg-1596703074889)(C:\Users\cxy\AppData\Local\Temp\1595490077735.png)]
gevent
随着用户增加,多进程和多线程会使服务器不堪重负
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rCJoujiO-1596703074890)(D:\学习笔记\放在typora里的图片\1595490256424.png)]
【并发越高,协程效率才最高】
TCP三次握手:
客户端connent(),服务端从listen(128)状态被唤醒
##单线程单进程非阻塞实现并发的原理
将套接字设为非堵塞的状态:s.setblocking(False)
用多进程多线程实现并发服务器的原因:
如果是单进程单线程阻塞的状态,在接收数据recv()的时候,服务端必阻塞到数据收到为止,此时就无法为新的客户端服务;
用单进程单线程单任务实现多个客户端一起服务:将套接字设为非堵塞的状态:s.setblocking(False),如图【这种方式就类似协程】
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PFGvsBqb-1596703074891)(D:\学习笔记\放在typora里的图片\1595471217582.png)]
但是这种实现多任务,一旦在for遍历里有阻塞block,会阻塞整个程序
长连接、短连接
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SOv4JF3j-1596703074892)(D:\学习笔记\放在typora里的图片\1595474019073.png)]
浏览器与HTTP服务器通信示意图:【3次握手之后】
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JZvNvaOO-1596703074893)(D:\学习笔记\放在typora里的图片\1595474547091.png)]
长连接和短连接的优缺点:
-
长连接可以省去较多的TCP建立和关闭的操作,减少浪费,节约时间;
对于频繁请求资源的客户端来说,较适用长连接
【长连接减少服务器使用的资源,减轻服务器压力】
-
client和server之间的连接如果一直不关闭的话,会存在一个问题:
随着客户端连接越来越多,server会逐渐扛不住,这时候server需要采取一些策略,比如关闭一些长时间没有读写事件发生的连接,这样可以避免一些恶意连接导致server端服务受损。
长连接的服务器在响应头信息里要写上Content-Length,让客户端知道本次发送的资源(也就是响应体 response body)的长度,客户端就知道服务端发完了;
短连接的话直接调用close(),就知道发完了
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Tp5E4vK3-1596703074894)(D:\学习笔记\放在typora里的图片\1595475761900.png)]
IO多路复用:epoll
epoll是linux服务器中采用的方式,而不用多进程多线程多协程非阻塞等方式。gevent的底层就是epoll实现的。目前大多数服务器都用的epoll,比如nginx,目前基本所有网站都用nginx
epoll是一种方案,用单进程单线程来实现高并发。前面写的单进程单线程非阻塞也能实现高并发,但是远远比不上epoll
所以只要是服务器,操作系统就考虑用linux。所以效率最高的还是linux里的网络。
非阻塞的方式:在程序里建了一个列表client_socket_list,用for循环挨个遍历,列表越长遍历一遍的时间越长,因为每次都要把用户态内存空间里的列表元素复制一份给内核态的操作系统,列表越长复制的次数越多。这就是单进程单线程非阻塞的效率瓶颈。
所以epoll就诞生了,epoll有一个特殊的内存空间,操作系统和应用程序共有这个空间,此时这个内存空间不属于应用程序,也不属于操作系统内核,而是它俩共享。这个时候操作系统去检查套接字是否收到数据时就不需要再拷贝一份套接字,减少了复制过程。
从第一个遍历到最后一个的方式叫做轮询,效率还是较低。【select和poll都是轮询】
为了进一步提高效率, 使用事件通知。操作系统一直在运行,当对方数据来的时候,操作系统会主动告诉哪个套接字可以接收数据。
因此,epoll:
-
有一个应用程序和kernel共享的特殊内存;【共享内存】【内存映射(mmap)技术】
-
这个内存中添加的所有要监听的套接字对应的文件描述符,不使用轮询,而是事件通知。【事件通知】【采用基于事件的就绪通知方式】
把更多的时间花在数据修改上,而不是遍历/轮询上。
通过这两个方面,保证了epoll的效率极高。
【注意对比一下,不用epoll的话,非阻塞是怎么做的,效率差从哪儿来,瓶颈在哪儿】
之前是应用程序在自己的内存空间里建list,自己去挨个儿检测,每次都要拷贝给操作系统一份,列表越大拷贝次数越多,效率越慢;因此建一个特殊的内存空间epoll,把应用程序每次遍历列表的过程交给操作系统去执行,操作系统效率相当高,这个轮询过程就比应用程序自己来要快;再将轮询改为事件通知机制,进一步大大提高效率。(轮询效率慢,但是写起来简单;事件通知效率高,但是写起来麻烦)
做服务器的时候,多进程多线程谁快?epoll最快。单进程单线程非阻塞的协程也还行。
epoll实现的并发web服务器:
import select
import socket
tcp_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
tcp_socket.bind(('',7890))
tcp_socket.listen(128) #变为监听套接字
tcp_socket.setblocking(False) #将套接字变为非阻塞
# 创建一个epoll对象
epl = select.epoll()
# 将监听套接字对应的fd注册到epoll中;
# 注意是套接字对象对应的文件描述符fd
# s.fileno()返回的对象就是套接字s的文件描述符
# select.EPOLLIN监测该套接字是否有输入
epl.register(tcp_socket.fileno(), select.EPOLLIN)
# 定义字典用来存放客户端fd对应的套接字对象
fd_event_dict = dict()
while True:
# poll()默认会阻塞,直到os监测到数据到来,通过事件通知的方式告诉这个程序,才会解阻塞
# 返回值是一个列表
fd_event_list = epl.poll()
# [(fd,event),(套接字对应的文件描述符,这个文件描述符到底是什么事件:例如,可以调用recv接收)]
for fd,event in fd_event_list:
# 找到fd对应的套接字对象,
# 如果fd对应的是服务器套接字,说明来的是一个新的客户端,服务器需要用accept()来接收客户端信息
if fd == tcp_socket.fileno():
client_socket, client_addr = tcp_socket.accept()
# 把新的客户端套接字丢到epoll中
epl.register(client_socket.fileno(),select.EPOLLIN)
# 把客户端fd和套接字加入字典
fd_event_dict[client_socket.fileno()] = client_socket
# 否则,此时到来的一定是已经链接的客户端,此时事件类型一定是有输入,就是select.EPOLLIN
elif event == select.EPOLLIN:
# 取出fd对应的客户端套接字对象
client_socket = fd_event_dict[fd]
# 判断已经链接的客户端是否有数据发送
recv_data = client_socket.recv(1024).decode('utf-8')
if recv_data:
print(recv_data) #或进行其他处理
else:
# 发送数据为空说明断开连接
client_socket.close()
# 在epl里注销
epl.unregister(fd)
# 删除dict里的键值对
del fd_event_dict[fd]
##TCP/IP
为了把全世界的所有不同类型的计算机都连接起来,实现互联网,就规定了一套全球通用的协议,就是通用协议标准:互联网协议族
互联网协议族包含了上百种协议标准,其中最重要的两个协议就是TCP和IP协议,所以大家把互联网协议简称为TCP/IP协议(族)
也就是说:TCP/IP是一个协议族,是互联网协议族的简称,其中最重要的两个协议就是TCP和IP协议。
TCP/IP协议族根据功能不一样,将协议分为四层:链路层/网络接口层,网络层,传输层,应用层。
其中每层常用的协议包括:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wLQtiD2V-1596703074894)(D:\学习笔记\放在typora里的图片\1595490934032.png)]
【ICMP】:网络控制协议,就是ping命令用的协议,它不走TCP和UDP协议,直接从应用层进入网络层,用来判断是否能连通
【原始套接字】:直接通到IP,可以伪装IP
TCP/IP协议传输示意图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ix3eDYaP-1596703074896)(D:\学习笔记\放在typora里的图片\1595493714813.png)]
mac地址:网卡的序列号
发送方:补包,越来越大;接收方:一层一层解包并判断协议是否合适
##OSI:
另一套标准,是理论标准,主要用的还是TCP/IP
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZTW3efKb-1596703074897)(D:\学习笔记\放在typora里的图片\1595494039450.png)]
##子网掩码:
用来区分IP地址中哪些是网络号哪些是主机号;
子网掩码与IP地址进行按位与操作,最后为0的值就是主机号,不变的值就是网络号
##交换机:
集线器Hub:将多台电脑组成一个网,但是集线器以广播的方式发送任何数据
交换机Switch将多台电脑组成网络,且克服了集线器那种全是广播的方式;当需要广播的时候就广播,需要单播的时候就能以单播的方式发送。企业中就是用交换机来完成多台电脑设备的链接成网络的
每一个网卡都有一个唯一的mac地址序列号,网卡是收发数据中最核心的硬件设备,这个设备上有个固定的序列号,就是mac地址/物理地址。也就是说,发送数据之前,必须得先得到对方的mac地址
##ARP协议:
地址解析协议,通过ARP广播找到对应的mac地址;【将已知的IP地址映射到mac地址】
当进行主机间的通信/也就是发送数据时:
- 首先,查看自己的缓存区中有没有对方的mac地址;【通过命令arp -a可以查看】
- 如果没有,发送ARP广播数据包给交换机Switch,数据包中的目的mac地址为【FF:FF:FF:FF:FF:FF,该地址所有网卡默认接收】,交换机对其进行广播,所有收到该数据包的主机都会对数据包进行处理,因为mac地址正确,所以链路层通过,然后就到了网络层,发现此时的协议是ARP;然后判断数据包里的ip地址,此时只有相匹配的主机才会接收该数据包,其他主机把包丢掉。然后接收方以单播的方式回送数据,然后就得到了接收方的ip对应的mac地址
路由器、网关
路由器Router将多个网络连接到一起。路由器最核心的功能:连接两个或两个以上不同的网络为一个大网,使它们之间可以进行通信。万维网就是把多个网络连接在一起组成的。一个交换机连接的电脑都处在同一个网络。路由器可以让不在同一个网络内的电脑之间进行通信。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JFDxnhgi-1596703074898)(D:\学习笔记\放在typora里的图片\1595555249228.png)]
路由器至少有两个网卡,每个网卡链接一个交换机/网络,就可以从网卡A收到信息,然后从网卡B发走。路由器自己链接了两个网络,就等于把这俩网络链接到了一起
**网关:**收到数据,把数据转发出去。具有这种转发数据的能力的设备称为网关。
默认网关:当一台电脑发送的目标IP地址和本机电脑所在的网络号不在同一个网络号时【也就是不在同一个网络】,会默认把数据转发给默认网关这台电脑,由默认网关进行数据收发。因此想要把数据发给不同网络号中的电脑时,必须要设置默认网关。
默认网关一般都是路由器。因为路由器至少有两个网卡。
ip地址已经可以能标记一台电脑,为什么还要有mac地址:IP仅仅是在逻辑上标记电脑
浏览器访问服务器的整个过程
DNS服务器:根据运营商不同,会有不同的DNS服务器IP地址。DNS服务器是国家控制的
-
解析域名:
先检查缓冲区是否有默认网关的mac地址,如果没有,电脑发送ARP广播得到默认网关的mac地址,然后把域名解析的请求数据发送给默认网关;然后路由器发到互联网上,根据DNS服务器的ip地址得到往哪个地区发送,然后DNS服务器就收到了请求,回送解析出来的ip地址数据包
-
向服务器发送TCP三次握手
-
发送HTTP请求数据,以及等待服务器的应答
-
浏览器显示页面
路由器至少有两个网卡,每个网卡链接一个交换机/网络,就可以从网卡A收到信息,然后从网卡B发走。路由器自己链接了两个网络,就等于把这俩网络链接到了一起
**网关:**收到数据,把数据转发出去。具有这种转发数据的能力的设备称为网关。
默认网关:当一台电脑发送的目标IP地址和本机电脑所在的网络号不在同一个网络号时【也就是不在同一个网络】,会默认把数据转发给默认网关这台电脑,由默认网关进行数据收发。因此想要把数据发给不同网络号中的电脑时,必须要设置默认网关。
默认网关一般都是路由器。因为路由器至少有两个网卡。
ip地址已经可以能标记一台电脑,为什么还要有mac地址:IP仅仅是在逻辑上标记电脑
浏览器访问服务器的整个过程
DNS服务器:根据运营商不同,会有不同的DNS服务器IP地址。DNS服务器是国家控制的
-
解析域名:
先检查缓冲区是否有默认网关的mac地址,如果没有,电脑发送ARP广播得到默认网关的mac地址,然后把域名解析的请求数据发送给默认网关;然后路由器发到互联网上,根据DNS服务器的ip地址得到往哪个地区发送,然后DNS服务器就收到了请求,回送解析出来的ip地址数据包
-
向服务器发送TCP三次握手
-
发送HTTP请求数据,以及等待服务器的应答
-
浏览器显示页面
-
发送TCP的四次挥手