复习
1.C/S结构
2.网络通讯
3.OSI 开放式系统互联参考模型 七层模型
详解:
1.C/S结构
client server
网络通讯是为了共享数据
拥有数据的一方 称之为服务器server
需要数据的一方称之为客户端client
B/S
浏览器 服务器
2.网络通讯
1.物理连接介质
2.通讯协议 (使双方能看懂数据)
协议即标准/规范 发送方和接收需要共同遵守
3.OSI 开放式系统互联参考模型 七层模型
应用层 表示层 会话层 传输层 网络层 数据链路层 物理层
应用层(应用层 表示层 会话层)
传输层
网络层
网络接口层( 数据链路层 物理层 )
1) 物理层
定义一堆物理相关协议 例如接口外观等
有了物理层就能传输二进制数据 010101010101010
2) 数据链路层
主要是以太网协议
1.数据传输格式 数据帧
[head | data]
2.每个设备要联网 必须具备网卡 每个网卡拥有一个全球唯一的MAC地址
数据链路层通过广播的方式来查找某一台计算机
在这一层 出现了交换机 用于组成一个局域网
在局域网中要查找某一台计算机 就通过广播的方式
如果每一次都需要广播 就浪费资源了, 所以交换机会自动保存 网口和MAC地址表的映射关系
问题: 广播风暴 没有交换机可以同时处理所有计算机
3) 网络层
主要是ip协议
1. 每一台设备都必须有一个ip地址
格式: 四段三位点分十进制 0.0.0.0-255.255.255.255
其中前三段是网络号(常规情况下) 最后一段是主机号
2.ip数据包 格式
[ 以太帧头 | [head | data] ]
3.子网掩码
用于标示iP中哪些是网络号 哪些是主机号
255.255.255.0
11111111.11111111.11111111.0000000
1表示网络号 0标示主机号
将ip转为二进制 子网掩码转为二进制
使用AND来计算两个ip是否处于同一局域网
例如 1号ip 转换的结果如下
11011111.00001111.10101010.00001
11111111.11111111.11111111.0000000
结果: 11011111.00001111.10101010.00000
例如 1号ip 转换的结果如下
11011111.00001111.10101010.00010
11111111.11111111.11111111.0000000
结果: 11011111.00001111.10101010.00000
4. ARP Address Resolution Protocol
该协议用于将ip转为MAC地址
1.先 比对子网掩码 判断两个ip是否处于同一子网中
2.1如果是 则直接在当前局域网中进行广播
2.2如果不是 同一局域网 则将数据包发送对方的网关
2.3对方网关收到数据包后回复自己的MAC地址
2.4发送的交换机收到数据包在发送给 发送方 同时存储对方网关与MAC的对应关系
2.5发送已经明确 对方网关的MAC 以及对方的IP
3.发送数据
[我的MAC 对方网关的MAC [我的ip 对方的ip]]
5.路由协议:
找到一条最佳的路径
到此可以使用IP 来定位到全球的某一个局域网 中的某一台计算机
4)传输层
1.端口号
每个应用程序都必须绑定一个端口号,用于标识你是谁 是qq还是微信
端口号不能重复
端口号就是一个整形数字 取值范围0-65535 0-1023为系统保留端口
有了ip和端口号就能 定位到全球某一台计算机上的某一个应用程序
2.传输层主要的传输协议
TCP (传输控制协议) 就像打电话
可靠传输
如何保障可靠
1.三次握手建立链接 其目的是为了确认传输路径可用
2.传输过程中 每一个数据包都需要 确认信息
3.四次挥手断开链接 是为了保障双方数据都已经传输完毕
传输效率低
UDP 像是校园广播
用户数据报协议
不关心数据是否传输成功 ,甚至不关心是否存在
优点:传输效率高
5) 应用层
数据已经通过下面各种协议传入了应用程序
应用程序该如何解析这些数据 ,用它们来干什么
这就是应用程序协议需要关心的问题了
每个应用程序都可以自己定义自己的协议 只要客户端程序和服务器程序能看懂就行
HTTP/HTTPS SMTP FTP
今日内容
网络编程之socket
1.socket在OSI中的位置
1.socket在OSI中的位置
1.1socket
什么是socket 翻译为套接字
是一套编程接口,内部封装了一堆底层协议,隐藏了内部复杂的实现细节,提供简单的使用接口
咱们只要按照socket编程接口来编写出的代码,就已经遵循了各种协议
简单的说就是一个封装好的模块
要学习的就是模块的使用方法
1.2socket的发展
最开始socket使用来完成进程间通讯的,并不是用来网络通讯,那时候还没有网络
后来有了网络之后 .基于之前的socket来进行了更新 使其可以支持网络通讯
所以socket分为两种类型
AF_UNIX : 进程间通讯
AF_INET : 网络通讯
1.3 socket在OSI中的位置
案例说明:
socket客户端.py
import socket
1.# 买个电话
client = socket.socket()
# 作为客户端 ip和端口可以变化 所有系统会自动分配随机端给客户端
client.connect(("127.0.0.1",1688))
2.# 开始通话
# 发送数据 注意发送的内容只能是二进制 bytes
client.send("hello".encode("utf-8"))
3.# 接收数据 单位为字节
data = client.recv(1024)
print(data)
client.close()
socket服务器.py
import socket
# 作为服务器必明确自己的ip和端口号 并且不应该变化
# 参数1指定 socket类型AF_INET 表示网络类型
#参数2指定的传输协议为 SOCK_STREAM表示TCP协议 SOCK_DGRAM UDP协议
server = socket.socket(socket.AF_INET,socket.SOCK_STREAM) # 1.买电话机
# 默认就是网络类型 TCP协议
#server = socket.socket()
# 127.0.0.1这叫回送地址 表示当前电脑本身
# ip一定本机ip 本机可能会有多个IP (无线|有限)
# 注意:需要参数是一个元组 端口就是普通整数
server.bind(("127.0.0.1",1688)) # 2.插入手机卡
# 无论是服务器端还是客户端 都是socket 类型
# 开始监听1688端口 盯着这个端口看以后没有数据过来
server.listen() # 3.手机开始待机
# 接收链接请求
# 第一个是表示客户端的socket 第二个客户端的地址信息
client,addr = server.accept() # 4.接电话
# print(type(client))
# print(addr)
# 5.收发数据
data = client.recv(1024)
print(data)
client.send("copy!".encode("utf-8"))
server.close() # 关机
1.4常见的异常:
1.端口占用问题
# 如果已经开启了服务器 再次运行将会抛出 端口占用异常 把之前开启的服务器关掉即可
"""
有些情况 明明已经关闭了进程 但是 还是端口占用
可能是进程正在后台运行 可以通过端口查出进程 进行关闭
windows下
netstat -ano | findstr 9898
tasklist | findstr 进程id 拿到进程名称
taskkill /f /t /im 进程名称
大招: 重启电脑
"""
有些情况 明明已经关闭了进程 但是 还是端口占用
可能是进程正在后台运行 可以通过端口查出进程 进行关闭
windows下
netstat -ano | findstr 9898
tasklist | findstr 进程id 拿到进程名称
taskkill /f /t /im 进程名称
大招: 重启电脑
案例:说明
import socket
server = socket.socket()
server.bind(("127.0.0.1",9891))
server.listen()
server.accept()
server.close()
# 如果已经开启了服务器 再次运行将会抛出 端口占用异常 把之前开启的服务器关掉即可
"""
有些情况 明明已经关闭了进程 但是 还是端口占用
可能是进程正在后台运行 可以通过端口查出进程 进行关闭
windows下
netstat -ano | findstr 9898
tasklist | findstr 进程id 拿到进程名称
taskkill /f /t /im 进程名称
大招: 重启电脑
"""
2.常见异常实例
服务器.py
import socket
server = socket.socket()
server.bind(("127.0.0.1",8888)) # 只有服务器需要绑定
server.listen()
# accept 是一个阻塞函数 会一直等到有客户端链接过来 在继续执行
client,addr = server.accept() # 完成了三次握手
# print(client)
# print(addr)
print("握手成功!")
# 收发数据 注意都是用表示客户端的socket来收发数据
# client.send("world".encode("utf-8"))
import time
time.sleep(3)
try:
# data = client.recv(1024)
# print("客户端发来的数据:", data)
# 发送数据时 对方可能也会异常下线 也会抛出异常
# 接收数据 和发送数据都应该放到try
client.send("test".encode("utf-8"))
except:
print("client 下线了")
# 断开链接
client.close() # 完成四次挥手
server.close()
print("服务器关机!")
客户端.py
import socket
client = socket.socket()
# connect本质实在进行三次握手 也是一个数据传输的过程 如果服务器没有立马响应 也会阻塞
#
client.connect(("127.0.0.1",8888)) # 三次握手
print("握手成功! client")
# 发送数据 本质上是把数据交给操作系统来进行发送 一旦数据交给了操作系统 后续的发送
# 应用程序就无法控制了 ,send一般不会卡 当然 如果数据量很大就会阻塞
# client.send("hello".encode("utf-8"))
# print("发送完成")
# 是从操作系统缓存区读取数据 如果当前还没有任何数据 就会进入阻塞
# 会一直等到有数据到来 再继续执行
# try:
# data = client.recv(1024)
# print("接收完成!")
# print(data)
# except:
# print("服务器 强行下线了!")
import time
time.sleep(10)
# 客户端执行close 是正常关闭链接 会给服务器送空字节 用于表示要断开链接
client.close()
print("关机了!")
1.5加上循环
服务器.py
import socket
server = socket.socket()
server.bind(("127.0.0.1",8989))
server.listen()
while True:
client_socket,client_addr = server.accept()
buffer_size = 1024 #缓冲区 就是一个临时的容器
# 缓冲区大小 不能随便写 太大会导致内存溢出 太小效率低 在内存能够承受的情况下 大一些
while True:
try:
data = client_socket.recv(1024)
# 在linux中 对方如果强行下线了 服务器不会抛出异常 只会收到空消息
# 得加上判断 如果为空则意味着 对方下线了 应该关闭链接 跳出循环
# windows上正常关闭 也会收到空消息 if 必须要加
if not data:
client_socket.close()
break
print(data.decode("utf-8")) # 解码时必须保证双方同意编码方式
# 转为大写在发回去
client_socket.send(data.upper())
except ConnectionResetError as e:
print("%s %s" % (client_addr[0],client_addr[1]),e)
# 如果对方下线了 那服务器也应该关闭对应的客户端对象
client_socket.close()
break
# 通常服务器不会关闭
# server.close()
客户端.py
import socket
client = socket.socket()
# 指定服务器的端口和ip 客户端的端口系统自动分配的
client.connect(("127.0.0.1",8989)) #
# 添加循环 用来重复收发数据
while True:
# 收发的顺序 必须很对面相反 否则卡死了
msg = input("输入内容:")
if not msg:continue
client.send(msg.encode("utf-8"))
print("sended!")
data = client.recv(1024)
print(data.decode("utf-8"))
client.close()
1.6window正常结束
服务器.py
import socket
server = socket.socket()
server.bind(("127.0.0.1",8989))
server.listen()
while True:
client_socket,client_addr = server.accept()
buffer_size = 1024 #缓冲区 就是一个临时的容器
# 缓冲区大小 不能随便写 太大会导致内存溢出 太小效率低 在内存能够承受的情况下 大一些
while True:
try:
data = client_socket.recv(1024)
# 在linux中 对方如果强行下线了 服务器不会抛出异常 只会收到空消息
# 得加上判断 如果为空则意味着 对方下线了 应该关闭链接 跳出循环
if not data:
client_socket.close()
break
print("收到数据:",data.decode("utf-8")) # 解码时必须保证双方同意编码方式
# 转为大写在发回去
client_socket.send(data.upper())
except ConnectionResetError as e:
print("%s %s" % (client_addr[0],client_addr[1]),e)
# 如果对方下线了 那服务器也应该关闭对应的客户端对象
client_socket.close()
break
# 通常服务器不会关闭
# server.close()
客户端.py
import socket
client = socket.socket()
# 指定服务器的端口和ip 客户端的端口系统自动分配的
client.connect(("127.0.0.1",8989)) #
# 添加循环 用来重复收发数据
while True:
# 收发的顺序 必须很对面相反 否则卡死了
msg = input("输入内容:(q:退出)")
if msg == "q":break
if not msg:continue
client.send(msg.encode("utf-8"))
print("sended!")
data = client.recv(1024)
print(data.decode("utf-8"))
client.close()