1、网络通信原理
互联网的本质就是一系列的网络协议, 统称为互联网协议.
互联网协议的功能:定义计算机如何接入internet,以及接入internet的计算机通信的标准。
互联网协议按照功能不同分为osi七层或tcp/ip五层或tcp/ip四层.
对于tcpip 五层协议, 每层运行常见物理设备有以下几种:
2、tcpip五层协议模型讲解
我们将应用层,表示层,会话层并作应用层,从tcp/ip五层协议的角度来阐述每层的由来与功能,搞清楚了每层的主要协议就理解了整个互联网通信的原理.
首先,用户感知到的只是最上面一层应用层,自上而下每层都依赖于下一层,所以我们从最下一层开始切入,比较好理解.
每层都运行特定的协议,越往上越靠近用户,越往下越靠近硬件.
2.1 物理层
孤立的计算机之间要想一起玩,就必须接入internet,言外之意就是计算机之间必须完成组网.
物理层功能:主要是基于电器特性发送高低电压(电信号),高电压对应数字1,低电压对应数字0
2.2 数据链路层
单纯的电信号0和1没有任何意义,必须规定电信号多少位一组.
数据链路层的功能:定义了电信号的分组方式.
以太网协议----ethernet
以太网协议规定: 一组电信号组成一个数据包(叫做帧), 每一帧数据由报头(head)和数据体(date)组成.
报头(18个字节): 源Mac地址+目标Mac地址+数据类型
data数据包含: (最短46字节,最长1500字节)
每组数据包的大小: head长度+data长度=最短64字节,最长1518字节,超过最大限制就分片发送
通信方式: 广播
ethernet(以太网) 采用最原始的方式,广播的方式进行通信,即计算机通信基本靠吼. 这个包会以广播的方式在发送端所处的子网内传输, 所有主机接收后拆开包, 发现目标ip为自己的, 就响应, 返回自己的mac.
2.3 网络层
有了ethernet、mac地址、广播的发送方式,世界上的计算机就可以彼此通信了,问题是世界范围的互联网是由一个个彼此隔离的小的局域网组成的,那么如果所有的通信都采用以太网的广播方式,那么一台机器发送的包全世界都会收到,数以万计的机器发送巨量的包不仅会造成网络拥堵瘫痪, 而且数据还不安全.
网络层功能:引入一套新的地址用来区分不同的广播域/子网,这套地址即网络地址.
IP协议
规定网络地址的协议叫ip协议, 它定义的地址称之为ip地址, 一个ip地址通常写成四段十进制数,例:172.16.10.1.
IP协议的作用主要有两个:
1,是为每一台计算机分配IP地址
2, 是确定哪些地址在同一个子网络(通过子网掩码和and运算), 如果不是一个子网内的, 就通过Arp协议获取网关的Mac地址.
IP数据包也分为head和data部分, IP数据包直接放入以太网包的data部分.
以太网数据包的”数据”部分, 最长只有1500字节. 因此, 如果IP数据包超过了1500字节, 它就需要分割成几个以太网数据包, 分开发送了.
Arp协议
计算机通信基本靠吼, 即广播的方式, 所有上层的包到最后都要封装上以太网头, 然后通过以太网协议发送, 以太网通信是基于mac的广播方式实现, 计算机在发包时,获取自身的mac是容易的, 如何获取目标主机的mac, 就需要通过arp协议.
arp协议功能: 广播的方式发送数据包, 获取目标主机的mac地址.
具体的IP包长什么样子?
如果不在同一个子网内, 将IP包里的目标Mac替换成获取到的网关Mac.
2.4 传输层
网络层的IP帮我们区分子网, 以太网层的Mac帮我们找到主机, 但是只找到主机没用,程序之间进行的沟通啊像QQ、浏览器和京东服务器, 大家使用的都是应用程序, 你的电脑上可能同时开启qq, 暴风影音等多个应用程序, 那么我们通过IP和Mac找到了一台特定的主机,如何标识这台主机上的应用程序,答案就是端口,端口即应用程序与网卡关联的编号。
传输层功能:建立端口到端口的通信(端对端通信)
注意: 端口范围0-65535,0-1023为系统占用端口
tcp协议
TCP把连接作为最基本的对象, 每一条TCP连接都有一个套接字(socket), 端口号拼接到IP地址即构成了套接字, 例如IP地址为192.3.4.16, 而端口号为80, 那么得到的套接字为192.3.4.16:80.当应用程序希望通过 TCP 与另一个应用程序通信时, 它会发送一个通信请求, 这个请求必须被送到一个确切的地址. 在双方“握手”之后, TCP 将在两个应用程序之间建立一个全双工 (full-duplex,双方都可以收发消息) 的通信. 这个全双工的通信将占用两个计算机之间的通信线路, 直到它被一方或双方关闭为止.
tcp协议和udp协议的对比:
tcp: 提供的是面向连接、可靠的字节流服务. 当客户和服务器彼此交换数据前, 必须先在双方之间建立一个tcp连接, 之后才能传输数据. tcp提供超时重发, 丢弃重复数据, 检验数据, 流量控制等功能, 保证数据能从一端传到另一端.
udp: 是一个简单的面向数据报的运输层协议. udp不提供可靠性, 它只是把应用程序传给IP层的数据报发送出去, 但是并不能保证它们能到达目的地. 由于udp在传输数据报前不用在客户和服务器之间建立一个连接, 且没有超时重发等机制, 故而传输速度很快.
tcp的三次握手,四次挥手?(具体见后章节)
2.5 应用层
应用层功能: 规定应用程序的数据格式.
例:tcp协议可以为各种各样的程序传递数据, 比如Email、WWW、FTP等等. 那么, 必须有不同协议规定电子邮件、网页、FTP数据的格式, 这些应用程序协议就构成了”应用层”.
网络通信之全流程示意图
3、socket
什么是socket呢?我们经常把socket翻译为套接字,socket是在应用层和传输层之间的一个抽象层,它把TCP/IP层复杂的操作抽象为几个简单的接口供应用层调用已实现进程在网络中通信。
基于TCP的socket流程图片
基于UDP的socket流程图片
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 # 服务端---------------------------------------------------------------------- 2 import socket 3 4 server = socket.socket() # 创建一个socket对象 5 ip_port = ("192.168.15.73",8520) # 给定服务端的IP和端口 6 server.bind(ip_port) # 服务端绑定IP和端口 7 server.listen(3) # 服务端监听数量为3个, 即排队人数为3 8 while 1: 9 conn,addr = server.accept() # 服务端和客户端之间建立通道 10 info = "服务端提供服务" 11 conn.send(bytes(info,"utf8")) # 服务端直接用conn 通道来传输数据(必须是bytes类型), 客户端的话通过客户端对象来传输数据. 12 13 while 1: 14 recv_msg = str(conn.recv(1024),"utf8") # 1024b 意思是接收到的最大数据长度为1024b 15 print(recv_msg) 16 if recv_msg == "88": 17 break 18 send_msg = input("服务端输入信息: ") 19 conn.send(bytes(send_msg,"utf8")) 20 conn.close() 21 22 server.close() 23 24 25 # 客户端-------------------------------------------------------------------------- 26 import socket 27 28 client = socket.socket() 29 ip_port = ("192.168.15.73",8520) 30 client.connect(ip_port) 31 32 recv_msg = client.recv(1024) 33 print(str(recv_msg,"utf8")) 34 35 while 1: 36 info = input("客户端输入请求: ") 37 client.send(bytes(info,"utf8")) 38 if info == "88": 39 break 40 recv_msg = client.recv(1024) 41 print(str(recv_msg,"utf8")) 42 43 client.close()
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 import socket 2 3 # 服务端 4 server = socket.socket(type=socket.SOCK_DGRAM) # type参数为遵循 udp协议的意思 5 ip_port = ("127.0.0.1",8520) 6 server.bind(ip_port) 7 8 recv_msg,addr = server.recvfrom(1024) # recvfrom接收两个参数, 数据内容和ip+端口号 9 print(f"服务端收到来自{addr}的信息>>>>",str(recv_msg,"utf8")) 10 11 send_info = "商城信息balabala......" 12 server.sendto(bytes(send_info,"utf8"),addr) 13 14 # 客户端 15 client = socket.socket(type=socket.SOCK_DGRAM) 16 ip_port = ("127.0.0.1",8520) 17 client.sendto(bytes("给我你商城的信息","utf8"),ip_port) 18 19 recv_msg,addr = client.recvfrom(1024) 20 print("客户端收到来自服务端的信息:",str(recv_msg,"utf8"))
练习:
写一个udp协议下的socket简单聊天工具(类似于QQ)
1. 服务端
- 接收客户端发送的信息并作出回复
2. 多个客户端
- 客户端向服务端发送信息
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 import socket 2 3 # 服务端------------------------------------------------------------------------- 4 server = socket.socket(type=socket.SOCK_DGRAM) 5 ip_port = ("192.168.12.42",8520) 6 server.bind(ip_port) 7 8 while 1: 9 recv_msg,addr = server.recvfrom(1024) 10 print(f"一条来自客户端{addr}的消息: {str(recv_msg,'utf8')}") 11 send_msg = input("输入回复内容: ") 12 if not send_msg: continue 13 server.sendto(bytes(send_msg,"utf8"),addr) 14 15 16 # 客户端------------------------------------------------------------------------- 17 client = socket.socket(type=socket.SOCK_DGRAM) 18 qq_name_dic={ 19 'taibai':('192.168.12.42',8520), 20 'taihei':('192.168.12.42',8520), 21 'libai':('192.168.12.42',8520), 22 'lihei':('192.168.12.42',8520), 23 } 24 while 1: 25 who = input("请选择聊天对象[Q退出对话]: ") 26 if who == "Q": break 27 ip_port = qq_name_dic[who] 28 while 1: 29 send_msg = input("输入聊天内容[Q结束对话]: ") 30 if send_msg == "Q": break 31 if not send_msg or not ip_port: continue 32 client.sendto(bytes(send_msg,"utf8"),ip_port) 33 recv_msg,addr = client.recvfrom(1024) 34 print(str(recv_msg,"utf8"))