网络
什么是网络
将一方的想要表达的内容通过传给另一方或者多方的工具,叫做网络。
网络是由节点和连线构成,表示诸多对象及其相互联系。在数学上,网络是一种图,一般认为专指加权图。网络除了数学定义外,还有具体的物理含义,即网络是从某种相同类型的实际问题中抽象出来的模型。在计算机领域中,网络是信息传输、接收、共享的虚拟平台,通过它把各个点、面、体的信息联系到一起,从而实现这些资源的共享。(摘自百度百科)
作用
将一方的想要表达的内容通过传给另一方或者多方,网络是信息传输、接收、共享的虚拟平台,通过它把各个点、面、体的信息联系到一起,从而实现这些资源的共享。
网络中的通信流程
通过IP找到网络上的设备,通过端口号找到端口,通过端口给应用提供数据。
IP
怎样找到网络中的另一方?
地址,就像每个人都有家庭住址一样,在网路中也有地址,叫做 IP 地址,可以唯一标识一台设备。
IP地址是指互联网协议地址(英语:Internet Protocol Address,又译为网际协议地址),是IP Address的缩写。IP地址是IP协议提供的一种统一的地址格式,它为互联网上的每一个网络和每一台主机分配一个逻辑地址,以此来屏蔽物理地址的差异。(摘自百度百科)
作用
就像通过地址可以找到你的家一样,通过 IP 地址可以找到网络上的另一个网络或者主机。
查看IP地址
Window中使用 ipconfig
Window键 + R 打开运行,输入cmd 打开命令提示符,输入ipconfig 或者ipconfig -all 就能查看到信息了,默认是简略信息。
ipconfig ... 显示信息
ipconfig /all ... 显示详细信息
Linux中使用 ifconfig
Ctrl + T 打开终端,在终端中输入ifconfig 就能查看到信息了,默认是详细信息。
Ping 查看IP地址
通过本地域名LocalHost 查看本机域名,可以检测网卡有没有问题
ping localhost
PING localhost (127.0.0.1) 56(84) bytes of data.
64 bytes from localhost (127.0.0.1): icmp_seq=1 ttl=64 time=0.016 ms
64 bytes from localhost (127.0.0.1): icmp_seq=2 ttl=64 time=0.055 ms
64 bytes from localhost (127.0.0.1): icmp_seq=3 ttl=64 time=0.023 ms
64 bytes from localhost (127.0.0.1): icmp_seq=4 ttl=64 time=0.026 ms
64 bytes from localhost (127.0.0.1): icmp_seq=5 ttl=64 time=0.037 ms
端口
什么是端口
通过地址可以找到你的家(IP地址),但是想要进入你家的客厅(电脑中的应用程序),需要通过门厅(端口),然后才能进入客厅。端口就是数据通过的一扇门,或者一个通道,经过端口将数据提供给应用程序。
端口的作用
数据由端口传给应用,应用内的数据也可以由端口传出。
端口号
端口号分为知名端口号和动态端口号,范围分别是0-1024 、1024-65535 ,端口总数为 2**16(655356) 个,通过端口号可以找到端口,类似于通过门牌号可以找到你家。
查看端口使用情况
nanetstart -an ............查看端口使用情况
根据端口查找应用
sudo lsof -i [tcp/udp]:端口号 ..........根据端口号查找应用
scoket
什么是socket
网络中的数据从一方到另一方,其中数据的载体或者运输工具就是socket。socket 将从应用中传出的数据通过物理链路传输到接收方的应用程序中,所以可以说socket 网络上不同电脑上的进程之间通信的工具。
socket的使用
基本步骤
- 创建udp 协议的socket
- 发送数据 socket.sendto()
- 接收数据 socket.recvfrom()
- 关闭socket socket.close()
import socket
def main():
# 创建udp 传输协议的socket ,通过socket 模块创建Socket 类的对象,
# 并传值socket.AF_INET(ip协议类型 ipv4),socket.SOCK_DGRAM(传输协议类型 udp协议)
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 数据,字符串编码成二进制数据,编码格式根据接收方编码决定
# window 系统默认GBK 编码,Linux 系统默认UTF-8 编码,
# Python3 encode() decode() 默认编码格式为UTF-8
data = "DragonFang 到此一游".encode("gbk")
# 接收方的IP 以及端口号 ,元组类型
dest_ip_port = ("192.168.13.14", 5210)
# udp socket发送数据使用sendto() 方法,方法需要传值
# data 二进制数据;dest_ip_port 收方的IP 以及端口号,元组类型
udp_socket.sendto(data, dest_ip_port)
while True:
# 如果需要接收数据recvfrom() 方法;参数 1024,接收数据长度为1024 个字节,超过长度的数据丢失
# Window 超过长度报错10040 未解决,双方约定长度可以临时解决
recv_data, recv_ip_port = udp_socket.recvfrom(1024)
recv_content = recv_data.decode("gbk", errors="ignore")
print(recv_content)
if not recv_data:
break
# 使用完成关闭
udp_socket.close()
if __name__ == '__main__':
main()
decode() 的参数errors 有三个值,
# 源码
def decode(self, input, errors='strict'):
if errors not in ('strict', 'replace', 'ignore'):
raise UnicodeError("Unsupported error handling "+errors)
res = punycode_decode(input, errors)
return res, len(input)
# 测试 errors="replace" 与 errors="ignore" 区别
# data = "你猜".encode("gbk")
# print(data)
# gbk_con = data[0:3].decode("gbk", errors="ignore")
# gbk_con_re = data[0:3].decode("gbk", errors="replace")
# print("gbk_con", gbk_con, "end")
# print("gbk_con_re", gbk_con_re, "end")
#
# gbk_con = data[3:].decode("gbk", errors="ignore")
# gbk_con_re = data[3:].decode("gbk", errors="replace")
# print("gbk_con", gbk_con, "end")
# print("gbk_con_re", gbk_con_re, "end")
- errors=“strict”:严格遵守解码格式,遇到无法解码的内容直接报错 UnicodeDecodeError
- errors="replace":会使用特殊字符替换无法解码的内容,不报错
- errors="ignore":忽略无法解码的内容,不报错
传输协议
什么是传输协议
传输协议中各层都为上一层提供业务功能。为了提供这种业务功能,下一层将上一层中的数据并入到本层的数据域中,然后通过加入报头或报尾来实现该层业务功能,该过程叫做数据封装。用户的数据要经过一次次包装,最后转化成可以在网络上传输的信号,发送到网络上。当到达目标计算机后,再执行相反的拆包过程。这类似于日常生活中写信,把自己要表达的意思写到纸上,有兴趣的话还要把纸折叠成特殊的形状,然后放到信封里并封好口,写好收信人的地址、邮政编码和姓名,再贴上邮票,邮局的工作人员再盖上邮戳送到收信人所在邮局,邮递员按信上的地址把信交给收信人,收信人再拆信,阅读其内容。(摘自百度百科)
UDP传输协议
用户数据包协议,当传输出现错误时会将错误信息丢弃
udp socket
基本步骤
- 创建udp 传输协议的socket
- 发送数据 socket.sendto()
- 接收数据 socket.recvfrom()
- 关闭socket socket.close()
import socket
def main():
# 使用udp 传输协议创建socket
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 准备数据
data = "DragonFang 到此一游".encode("gbk")
# 接收方的IP 以及端口号 ,元组类型
dest_ip_port = ("192.168.13.14", 5210)
# 发送数据
udp_socket.sendto(data, dest_ip_port)
while True:
# 接收数据
recv_data, recv_ip_port = udp_socket.recvfrom(1024)
# 解码收到的二进制数据
recv_content = recv_data.decode("gbk", errors="ignore")
print(recv_content)
# 接收到的数据长度为0,退出循环
if not recv_data:
break
# 使用完成关闭
udp_socket.close()
if __name__ == '__main__':
main()
TCP传输协议
传输控制协议,当传输出现错误时能自动予以纠正
tcp client socket
基本步骤
- 创建tcp 传输协议的客户端 client_socket
- 建立连接 client_socket.connect()
- 发送数据 client_socket.send()
- 接收数据 client_socket.recv()
- 关闭socket client_socket.close()
import socket
def main():
# 创建tcp 传输协议的socket ,通过socket 模块创建Socket 类的对象,
# 并传值socket.AF_INET(ip协议类型 ipv4),socket.SOCK_STREAM(传输协议类型 tcp协议)
tcp_client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 服务端ip 服务端端口号,元组类型
server_ip_port = ("192.168.109.1", 8080)
# 建立连接
tcp_client_socket.connect(server_ip_port)
# 数据
data = "DragonFang 到此一游".encode("gbk")
# 发送数据
tcp_client_socket.send(data)
while True:
# 接收数据,超过接收长度,本次不接收,下次再接收;参数 1024,接收数据长度为1024 个字节
sever_data = tcp_client_socket.recv(12)
# 解码数据
sever_content = sever_data.decode("gbk", errors="ignore")
# 二进制数据为0 ,退出
if not sever_data:
print("退出")
break
# 关闭连接
tcp_client_socket.close()
if __name__ == '__main__':
main()
tcp server socket
基本步骤
- 创建tcp 传输协议的服务端 server_socket
- 绑定端口 server_socket .bind()
- 设置监听 server_socket .listen()
- 建立连接 server_socket .accept(),得到client_socket
- 接收数据 client_socket.recv()
- 发送数据 client_socket.send()
- 关闭客户端client_socket client_socket .close()
- 关闭服务端server_socket server_socket .close()
import socket
def main():
# 创建tcp 传输协议的socket ,通过socket 模块创建Socket 类的对象,
# 并传值socket.AF_INET(ip协议类型 ipv4),socket.SOCK_STREAM(传输协议类型 tcp协议)
tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 服务端ip 服务端端口号,元组类型 ;ip 缺省,用于适应多个IP 地址的情况
server_ip_port = ("", 8080)
# 绑定端口号
tcp_server_socket.bind(server_ip_port)
# 监听建立连接的请求;参数128 最大等待连接数
tcp_server_socket.listen(128)
# 建立连接
tcp_client_socket, client_ip_port = tcp_server_socket.accept()
while True:
# 接收数据
client_data = tcp_client_socket.recv(1024)
# 解码数据 ,解码方式与客户端编码方式相同
client_content = client_data.decode("gbk", errors="ignore")
if not client_data:
break
# 数据
data = "DragonFang 到此一游".encode("gbk")
# 发送数据
tcp_client_socket.send(data)
# 关闭客户端socket ,断开与客户端的连接
tcp_client_socket.close()
# 关闭服务器socket,不再接收连接请求
tcp_server_socket.close()
if __name__ == '__main__':
main()
TCP与UDP的区别
面向连接
- TCP提供的是面向连接的、可靠的数据流传输;
- UDP提供的是非面向连接的、不可靠的数据流传输。
可靠性
- TCP提供可靠的服务,通过TCP连接传送的数据,无差错、不丢失,不重复,按序到达;
- UDP尽最大努力交付,即不保证可靠交付。
内容形式
- TCP面向字节流;
- UDP面向报文。
服务形式
- TCP连接只能是点到点的;
- UDP支持一对一、一对多、多对一和多对多的交互通信。
资源占用
- TCP首部开销20字节,资源开销大
- UDP的首部开销小,只有8个字节。
逻辑信道
- TCP的逻辑通信信道是全双工的可靠信道;
- UDP的逻辑通信信道是不可靠信道。
传输速度
- UDP 传输速度快
- TCP 传输速度慢,TCP需要建立连接,
适用场景
- UDP 快速通信,一对多通信,对于通信质量要求不严苛,比如实时语音通话,实时视频通话,广播等
- TCP 可靠传输,比如文件上传下载,网页浏览等
TCP的三次握手
TCP建立连接时发生,三次握手(three times handshake;three-way handshake)所谓的“三次握手”即对每次发送的数据量是怎样跟踪进行协商使数据段的发送和接收同步,根据所接收到的数据量而确定的数据确认数及数据发送、接收完毕后何时撤消联系,并建立虚连接。(摘自百度百科)
过程 (摘自百度百科)
- 第一次
- 第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SENT状态,等待服务器确认;SYN:同步序列编号(Synchronize Sequence Numbers)。
- 第二次
- 第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;
- 第三次
- 第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED(TCP连接成功)状态,完成三次握手。
个人理解:一次完整握手礼的不同步骤,我伸出手,对方伸出手,两手相握,握手礼完成
我伸出手
TCP第一次握手,我见到朋友(建立连接),伸出我的手(发送syn包到服务器,进入SYN_SENT状态),等待朋友作出反应(等待服务器确认)
对方伸出手
TCP第二次握手,朋友看到我伸出手(收到syn包),明白这是要握手(确认客户的SYN),很给面的伸出了手(发送SYN+ACK包到客户端,服务器进入SYN_RECV状态)
两手相握
TCP第三次握手,我看到朋友很给面的伸出了手(收到服务器的SYN+ACK包),我主动迎上去(发送确认包ACK),两手相遇,紧紧地握在一起(TCP连接成功),兄弟情深。。。。
TCP的四次挥手
TCP关闭连接的步骤如下: (摘自百度百科)
- 第一步,当主机A的应用程序通知TCP数据已经发送完毕时,TCP向主机B发送一个带有FIN附加标记的报文段(FIN表示英文finish)。
- 第二步,主机B收到这个FIN报文段之后,并不立即用FIN报文段回复主机A,而是先向主机A发送一个确认序号ACK,同时通知自己相应的应用程序:对方要求关闭连接(先发送ACK的目的是为了防止在这段时间内,对方重传FIN报文段)。
- 第三步,主机B的应用程序告诉TCP:我要彻底的关闭连接,TCP向主机A送一个FIN报文段。
- 第四步,主机A收到这个FIN报文段后,向主机B发送一个ACK表示连接彻底释放。 [1]
理解:
- 中午我正在忙着(主机B,TCP连接中),同事说都中午了(主机A,TCP数据已经发送完毕),一起去吃饭吧(TCP向B发送FIN)
- 我说手上有点事(收到FIN ),等我一下(发送ACK),我抓紧忙手上的事情(对方要求关闭连接)
- 敲击键盘的声音停止了(关闭连接),我说道忙完了(向A送一个FIN)
- 同事转过头(收到FIN),对我说到工作狂终于忙完了(发送ACK),走吃饭去,我都要饿死了,你请客。(TCP连接中断)
端口占用问题
第四次握手,客户端收到FIN后,接着发送一个ACK给服务端,服务端关闭,但是客户端会监听服务端端口,看服务端是否会再次请求数据,造成服务端端口被占用。
到此结 DragonFangQy 2018.4.21
发送长度大于接收长度,Window 报错10040 未解决,双方约定长度可以临时解决
udp_socket.recvfrom(1024)