面试java八股文知识点补充(osi7层、java成对知识点)部分线程以及iot
一、TCP大概了解
图源:太厉害了,终于有人能把TCP/IP 协议讲的明明白白了
简单通俗地说TCP:TCP,全称是“Transmission Control Protocol”(传输控制协议)是一种帮助你确保数据可靠传输的方法。具体看后面的代码就知道这句话什么意思了。
TCP负责数据的分割、传输、重组和确认,以确保数据的完整性和顺序性。它是基于连接的协议,通过握手、数据传输和连接终止等步骤来管理通信过程。
常用带数值的标志位的名词解释
SYN(Synchronize):用于建立连接。如果 SYN 标志位为 1,表示发送方希望建立连接。
大写的ACK:ACK(Acknowledgment)是一个标志位,用于表示确认。当ACK标志位被设置为1时,表示接收方已经成功收到前面的数据,或者确认了连接的状态。
小写的ack(acknowledgment number):这就像是接收方给发送方的信号,告诉发送方接收方期望收到的下一个数据的序列号是多少。它告诉发送方,在这个确认号之前的数据已经成功收到。发送方需要根据接收方发送的ack值来确定哪些数据已经被成功接收。
seq(sequence number):在 TCP 通信中,每个发送的数据包都有一个唯一的序列号,用于标识数据包的顺序和重组。
FIN(Finish):用于终止连接。如果 FIN 标志位为 1,表示发送方不再发送数据,希望终止连接。
工作方式
-
连接建立(握手):当你想要与另一台设备建立通信时,你会通过发送一个特殊的消息(称为SYN)来告诉对方你想要建立连接。对方会回复一个消息,表示它同意建立连接(SYN+ACK)。然后你再发一个消息表示你同意了(ACK)。这个过程就像是握手,确认双方都准备好通信。
-
数据传输:一旦连接建立,你可以开始传输数据了。你的数据会被分成小块,每块都会带有编号,这样对方就能知道数据的顺序。TCP会确保这些数据块按正确的顺序到达对方,而且如果有数据块丢失,TCP会帮你要求对方重新发送。
-
连接终止:当你完成通信后,你会发送一个消息表示你不想再继续通信了(称为FIN)。对方会回复一个消息表示它也不想通信了(FIN)。然后你会再回复一个消息,表示你收到了对方的意愿(ACK)。最后,对方也会回复一个消息,表示它也收到了你的意愿(ACK)。这个过程就是连接的终止。
重点理解:三次握手与四次挥手
握手(Handshake):在计算机网络中,握手是指在建立连接或终止连接时,通信双方通过交换特定的控制信息来确认彼此状态的过程。握手确保双方都同意进行连接或断开,并在这些操作中达成一致。
挥手:终止一个 TCP 连接需要四次通信,分为主动关闭和被动关闭两个方向,以确保双方都停止数据传输并关闭连接。
主动关闭和被动关闭:主动关闭指的是发起关闭连接的一方,它发送 FIN 来表示它不再发送数据。被动关闭是指另一方接收到 FIN 并确认后,发送自己的 FIN 来表示它也不再发送数据。这样双方都确认不再发送数据后,连接才会完全关闭。
全双工(Full Duplex):全双工是指在通信中,数据可以同时双向传输,也就是可以同时进行发送和接收,就像是两个人可以同时交谈而不需要等待对方。断开一个TCP连接时,需要客户端和服务端总共发送4个包以确认连接的断开,在socket编程中,这一过程由客户端或服务端任一方执行close来触发,由于TCP连接是全双工的,因此,每个方向都必须要单独进行关闭。
ESTABLISHED 状态:表示连接已经建立并可以进行数据传输。
一条视频讲清楚TCP协议与UDP协议-什么是三次握手与四次挥手
连接建立过程(三次握手):
- 客户端发送SYN=1,随机产生一个值seq=J的数据包给服务器端,进入SYN_SENT状态,等待服务器端确认。
- 服务器端收到数据包后,由标志位SYN=1知道客户端请求建立连接,发送SYN=1、ACK=1、ack=J+1、随机产生一个值seq=K的数据包给客户端以确认连接请求,进入SYN_RCVD状态。
- 客户端收到确认后,检查ack是否为J+1,ACK是否为1,如果正确则将标志位ACK置为1,ack=K+1,并将该数据包发送给服务器端,服务器端检查ack是否为K+1,ACK是否为1,如果正确则连接建立成功,客户端和服务器端进入ESTABLISHED状态,完成三次握手,随后客户端与服务器端之间可以开始传输数据了。
连接终止过程(四次挥手):
- 客户端想要断开连接,发送FIN=1,seq=X的数据包给服务器端。
- 服务器端收到FIN后,发送ACK=1,ack=X+1的数据包给客户端,进入CLOSE_WAIT状态。
- 服务器端自己也要断开连接时,发送FIN=1,seq=Y的数据包给客户端,进入LAST_ACK状态。
- 客户端收到服务器端的FIN后,发送ACK=1,ack=Y+1的数据包给服务器端,进入TIME_WAIT状态。服务器端收到ACK后,连接关闭。
如图,A是客户端,B是服务端
二、TCP协议在代码中如何简单使用
实现完整的 TCP 协议栈是一个庞大且复杂的任务,通常需要涉及底层的网络编程、数据包处理、错误处理等。因此,在实际项目中,很少有人从头开始实现整个 TCP 协议栈。相反,大多数开发者会使用操作系统提供的网络库或现成的网络框架来简化这个过程。
TCP 服务器端和客户端的代码可以在两台不同的计算机上运行,通过网络进行通信,实现数据传输和交互。
以下是一个使用Python标准库中的socket
模块来实现简单的TCP服务器和客户端的示例代码:
TCP服务器端示例:
import socket
# 创建一个TCP/IP套接字
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 绑定服务器地址和端口
server_address = ('localhost', 12345)
server_socket.bind(server_address)
# 开始监听连接
server_socket.listen(1)
print("等待连接...")
# 等待客户端连接
client_socket, client_address = server_socket.accept()
try:
print("连接已建立:", client_address)
while True:
data = client_socket.recv(1024)
if not data:
break
print("收到数据:", data.decode())
finally:
# 关闭客户端连接
client_socket.close()
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
-
socket
模块:socket
模块是 Python 中用于进行网络编程的标准库。它提供了各种函数和类,可以用来创建、连接和管理套接字,从而实现网络通信。 -
socket.AF_INET
:这是地址族(Address Family)的一种常量,表示 IPv4 地址族。它告诉socket
模块我们将使用 IPv4 地址格式。 -
socket.SOCK_STREAM
:这是套接字类型(Socket Type)的一种常量,表示使用面向连接的 TCP 套接字类型。它告诉socket
模块我们将使用 TCP 协议。 -
创建套接字:
socket.socket()
是一个函数,用于创建一个新的套接字对象。通过指定地址族和套接字类型,我们可以创建不同类型的套接字,例如 TCP、UDP 等。
client_socket, client_address = server_socket.accept()
对应客户端的client_socket.connect(server_address),不解释了,这个不难理解
server_socket.listen(1)
-
listen()
方法:这是套接字对象的一个方法,用于开始监听连接。当服务器套接字调用listen()
方法后,它就会处于监听状态,等待客户端连接。 -
(1)
:这是作为参数传递给listen()
方法的数字,表示服务器端可以同时接受的连接请求的数量。在这里,参数是1
,意味着服务器端最多可以同时处理一个连接请求。如果有多个客户端同时尝试连接,后续的连接请求会在队列中等待。
data = client_socket.recv(1024) if not data: break print("收到数据:", data.decode())
对应客户端中的message = "Hello, server!" client_socket.sendall(message.encode())
-
data = client_socket.recv(1024)
:这一行代码从客户端套接字client_socket
中接收数据。recv()
方法返回一个字节串,最多接收指定数量的字节。在这里,它尝试接收最多 1024 个字节的数据。 -
if not data:
:这是一个条件判断,检查接收到的数据是否为空。如果接收到的数据为空(长度为0),则表示客户端已经关闭连接,此时会执行下面的break
语句来跳出循环。 -
print("收到数据:", data.decode())
:如果接收到数据,这一行代码将数据解码成字符串并打印出来。data.decode()
将接收到的字节串解码为字符串,以便查看数据的内容。
TCP客户端示例:
import socket
# 创建一个TCP/IP套接字
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 连接服务器
server_address = ('localhost', 12345)
client_socket.connect(server_address)
try:
# 发送数据给服务器
message = "Hello, server!"
client_socket.sendall(message.encode())
finally:
# 关闭客户端连接
client_socket.close()
三、利用pyshark
通过 Python 脚本来捕获网络数据包的标志位数值
如何从 TCP 头部中看出这些标志位的值的变化的步骤:
-
打开一个网络抓包工具,例如 Wireshark,在捕获的数据包中找到 TCP 报文。
-
在 TCP 报文中,通常会有一个叫做 TCP Flags 或 TCP Control Flags 的部分,其中列出了 SYN、ACK、FIN 等标志位。
-
这些标志位通常以二进制形式表示。例如,如果一个标志位的值为 1,就会在相应的位置上显示为 1,如果值为 0,就会显示为 0。
如果你想通过 Python 使用 Wireshark 进行网络数据包捕获和分析,你可以使用名为 pyshark
的 Python 模块。pyshark
允许你通过 Python 脚本来捕获和分析网络数据包,而不必手动打开 Wireshark 软件。
对于某些操作系统,你可能需要管理员权限才能捕获网络数据包。在实际使用中,你可以根据自己的需求进一步研究和定制代码。如果你只是想简单地观察数据包,Wireshark 软件可能更加友好,但如果你希望将数据包捕获集成到自己的应用程序中,使用 pyshark
可以更好地实现这一目标。
首先,你需要安装 pyshark
模块。你可以使用以下命令通过 pip
安装:
pip install pyshark
在 Python 脚本中,你可以导入 pyshark
模块并使用它的函数来捕获和分析网络数据包。
import pyshark
# 指定抓包接口,例如 'eth0' 或 'en0'
capture = pyshark.LiveCapture(interface='eth0')
# 启动数据包捕获
capture.sniff()
# 处理捕获到的数据包
for packet in capture:
# 输出数据包的详细信息
print("Packet Number:", packet.number)
print("Timestamp:", packet.sniff_time)
print("Source IP:", packet.ip.src)
print("Destination IP:", packet.ip.dst)
# 如果是 TCP 数据包,可以访问 TCP 属性
if 'TCP' in packet:
print("Source Port:", packet.tcp.srcport)
print("Destination Port:", packet.tcp.dstport)
print("Flags:", packet.tcp.flags)
print("\n")
你可以根据数据包的类型和你关心的属性进一步定制你的代码。
四、为什么提TCP的时候总是还要提到IP
TCP和IP的区别与联系
TCP(Transmission Control Protocol)和IP(Internet Protocol)是互联网通信的两个关键协议,它们一起构成了TCP/IP协议栈,这是在互联网上进行数据传输的基础。它们之间的关系可以用以下方式来描述:
-
IP(Internet Protocol): IP是一种网络层协议,负责在网络上寻址和路由数据包。它为数据包分配源和目标IP地址,以便数据包可以在网络中正确地传递。IP协议负责解决数据包从一个网络节点到另一个网络节点的传输路径问题,但它本身并不关心数据包的传输是否可靠,也不保证数据包的顺序。
-
TCP(Transmission Control Protocol): TCP是一种传输层协议,构建在IP协议之上。TCP提供了可靠的、面向连接的数据传输,确保数据包按照正确的顺序到达目标,而且在数据传输过程中不丢失、不重复、不错乱。TCP通过一系列的握手、数据传输和连接终止阶段来管理数据的传递。
因此,TCP和IP之间的关系可以总结为:IP负责在网络中定位和路由数据包,而TCP则负责在建立的连接上提供可靠的、有序的数据传输。当使用TCP协议进行数据传输时,它依赖于底层的IP协议来实际发送和接收数据包。
TCP和IP之间的关系可以将其比喻为寄信的过程,假设你的朋友住在另一个城市,你需要邮寄信件——
TCP就像你写信的方式。你会在信中清楚地写下信息,确保没有遗漏,并按照正确的顺序编写内容,这样你的朋友在收到信后能够正确地理解你要传达的内容。这就是TCP的作用,它在数据传输中负责数据的可靠性和有序性。
IP就像邮递员和邮寄服务一样。你的信需要被放入信封中,并写上你朋友的地址和你的地址,这就相当于IP协议在数据上附加了源IP地址和目标IP地址。然后,邮递员将信件送到邮局,邮局将其通过不同的邮递路径送到你的朋友所在的城市,这就是IP协议路由数据包的过程。最终,你的朋友在他们的邮箱中收到信,并按照信封上的地址来确定发件人,(只是确定发件人而不会确定内容,IP协议不会解析传递的数据内容,它仅负责路由和传输数据包)这就相当于接收方的IP协议解析数据包。
隐藏在代码中的IP作用
在之前(二)的示例代码中,虽然没有显式地展示TCP依赖于IP来发送和接收数据包,但实际上,这是因为操作系统和网络协议栈在背后完成了这个过程。TCP协议位于更高的层次,依赖于IP协议来实现数据包的传输。以下是更详细的解释:
-
数据封装: 当应用程序要通过TCP发送数据时,TCP会将这些数据分割成适当大小的数据块,这些数据块被称为"TCP段"。每个TCP段都会附加TCP头部信息,包括源端口号、目标端口号、序列号等。这个过程在操作系统的网络协议栈中进行。
-
传递给IP: 一旦TCP段被封装完毕,操作系统的网络协议栈将这些TCP段交给底层的IP协议。IP协议负责在每个TCP段前添加IP头部信息,包括源IP地址、目标IP地址等。这样,TCP段就被封装在IP数据包中。
-
数据包传输: 封装在IP数据包中的TCP段(和IP头部)被传递到物理网络。这个过程涉及到路由器、交换机等网络设备,它们使用IP地址来决定将数据包传输到何处。
-
接收端处理: 在接收端,IP协议解析收到的数据包,并将其中的TCP段交给操作系统的网络协议栈。
-
TCP重组: 在接收端的网络协议栈中,TCP会解析TCP头部信息,根据序列号将TCP段重新组装成完整的数据。TCP还会处理确认应答(ACK)等。
-
交付应用程序: 最终,TCP将接收到的完整数据交付给应用程序,应用程序可以从中提取出原始的数据内容。
五、IPv4地址和IPv6地址
IP地址是用于在网络上唯一标识设备的数字地址。IP地址分为IPv4和IPv6两个版本,其中IPv4使用32位表示,而IPv6使用128位表示。
一些常见的IPv4地址类型
-
公共IPv4地址: 这些地址是全球范围内唯一标识设备的地址,用于在互联网上进行通信。公共IPv4地址在互联网上是可路由的,用于标识特定的设备。
-
私有IPv4地址: 这些地址用于在局域网内部进行通信,不会在互联网上路由。私有IPv4地址的使用有助于在局域网内部创建内部网络,如家庭网络或企业内部网络。
-
回环地址(Loopback Address): IPv4的回环地址是"127.0.0.1",它用于将数据发送给本地设备,类似于设备给自己发送消息的方式。
-
广播地址(Broadcast Address): 广播地址用于向网络上的所有设备发送数据,即发送给整个网络。IPv4广播地址通常是网络的最后一个地址,例如网络地址为192.168.1.0,广播地址为192.168.1.255。
-
网络地址和主机地址: 在IPv4地址中,通常将地址分为网络地址和主机地址两部分,用于标识网络和网络中的特定设备。网络地址用于表示网络本身,而主机地址用于表示在该网络内的设备。
-
保留地址: IPv4地址空间中有一些地址是保留的,不可用于分配给实际设备。这些地址用于特殊用途,如私有网络、测试等。
一些常见的IPv6地址类型
-
全球单播地址(Global Unicast Address): 这些地址在全球范围内是唯一的,用于标识设备在全球互联网上的位置。全球单播地址的格式通常为:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx,其中每个"xxxx"是一个16位的十六进制数。
-
链路本地地址(Link-Local Address): 这些地址用于同一链路(例如局域网)上的通信。它们在链路范围内是唯一的,通常用于设备之间的直接通信,格式为:fe80::xxxx:xxxx。
-
站点本地地址(Site-Local Address): 这些地址用于特定站点(例如企业内部网络)内部的通信。然而,站点本地地址在IPv6中已经不推荐使用,因为全球单播地址已经足够满足内部通信需求。
-
唯一本地地址(Unique Local Address): 这些地址是用于站点内部的通信,类似于IPv4的私有地址。唯一本地地址在全球范围内不重复,但仍被限制在特定站点内使用,格式为:fc00::xxxx:xxxx。
-
回环地址(Loopback Address): 类似于IPv4的回环地址,IPv6的回环地址是"::1",用于将数据发送给本地设备。
-
多播地址(Multicast Address): 多播地址用于一对多通信,可以将数据发送到特定的一组设备。IPv6多播地址的格式为:ffxx::xxxx:xxxx,其中"xx"表示多播组的标识。
-
任播地址(Anycast Address): 任播地址用于标识一组具有相同功能的设备,但数据只会发送给最近的一个设备。任播地址允许多个设备共享同一IP地址。
IPv4地址和IPv6地址区别
IPv4地址和IPv6地址在内容上有明显的区别,主要体现在地址长度、表示方式和可用地址数量上:
-
地址长度:
- IPv4地址长度为32位,通常用点分十进制表示,如 192.168.0.1。
- IPv6地址长度为128位,通常用冒号分隔的十六进制表示,如 2001:0db8:85a3:0000:0000:8a2e:0370:7334。
-
表示方式:
- IPv4地址由4个8位字段组成,每个字段用十进制表示,范围从0到255。
- IPv6地址由8组16位字段组成,每个字段用十六进制表示,范围从0x0000到0xFFFF。
-
地址数量:
- IPv4地址空间有限,共有约42亿个可能的地址。
- IPv6地址空间巨大,共有340 undecillion(后面跟36个零)个可能的地址。
-
分配和分级:
- IPv4地址分为A、B、C、D、E五类,每个类别具有不同的网络和主机部分,但随着CIDR(无类别域间路由)的引入,地址分配更加灵活。
- IPv6地址分为全球单播地址、链路本地地址、站点本地地址等,但不再像IPv4那样需要采用不同的类别。
-
私有地址和保留地址:
- IPv4中,私有地址范围(如 192.168.0.0/16、10.0.0.0/8、172.16.0.0/12)用于局域网内部通信,而一些地址被保留供特殊用途。
- IPv6中,有唯一本地地址(Unique Local Address)用于局域网内通信,但IPv6没有像IPv4那样专门保留地址,而是采用其他机制来实现特殊用途。
总体而言,IPv6地址相对于IPv4来说更为复杂,但也提供了更大的地址空间,以满足现代互联网中日益增长的设备数量需求,并提供更多的特性来提高网络安全性和性能。
六、TCP协议在实际生活中怎么应用
TCP 在实际生活中有很多应用,下面是一些常见的应用场景:
-
网页浏览:当你在浏览器中输入网址并按下回车键时,浏览器通过 TCP 协议与目标服务器建立连接,然后服务器将网页内容按照一定的顺序传输给你的浏览器,确保页面元素的正确显示和顺序。
-
电子邮件:当你发送或接收电子邮件时,邮件客户端与邮件服务器之间使用 TCP 协议来传输邮件内容。TCP 的可靠性确保邮件不会丢失或损坏。
-
文件传输:在下载文件、上传文件或使用 FTP(文件传输协议)时,TCP 确保文件可以准确地传输,即使在网络传输过程中出现丢包或其他问题。
-
实时通信:VoIP(Voice over IP)和视频通话等实时通信应用使用 TCP 来传输音频和视频数据,确保通话的清晰性和稳定性。
-
远程登录:当你使用 SSH(Secure Shell)等远程登录工具登录到远程服务器时,TCP 提供了一个安全的通信通道,使你可以在远程服务器上执行命令而不暴露明文数据。
-
即时通讯:即时通讯应用如 WhatsApp、WeChat、Telegram 等使用 TCP 来传输即时消息,以确保消息的可靠传递和有序呈现。
-
在线游戏:网络游戏利用 TCP 来在游戏客户端和服务器之间传输游戏数据,保证玩家之间的游戏状态同步和操作的准确传递。
-
数据库访问:当你在应用程序中访问远程数据库时,TCP 用于传输查询和响应,确保数据的一致性和完整性。
-
数据备份:企业和个人可以使用 TCP 来备份数据到远程服务器,以确保数据安全性和完整性。
总之,TCP 协议在互联网中扮演着重要的角色,它提供了一种可靠的数据传输机制,使得各种应用能够稳定地在网络上运行。无论是浏览网页、收发邮件、进行实时通信还是使用在线服务,TCP 都在背后默默地保障着数据的传输和交换。