网络基础
- mac地址:不会改变的,不会重复的,每个电脑出厂网卡上的序列。能够唯一标识你的机器
- ip地址:会改变。能够更好更方便的找到你的机器
- ipv4:四位点分十进制
- 192.168.0.0 8位的二进制 范围0.0.0.0到255.255.255.255
- 公网地址:需要自己申请购买的地址
- 内网地址:保留字段,永不和公网冲突
- 192.168.0.0——192.168.255.255
- 172.16.0.0——172.31.255.255
- 10.0.0.0——10.255.255.255
- 子网掩码:用来判断两台机器是否在同一个局域网内(用ip和子母掩码做按位与,相同即统一局域网)
- ipv6:六位的冒分十六进制
- 0:0:0:0:0:0——FFFFFF:FFFFFF:FFFFFF:FFFFFF:FFFFFF:FFFFFF
- 端口:确认机器上的具体应用程序的(0-65535)
- ipv4:四位点分十进制
- 局域网
- 在同一个局域网内的机器由交换机负责通信
- 交换机只认识mac地址
- 可以完成广播,,单播和组播
- 多个局域网通信
- 路由器
- 需要提供网关ip,同一个局域网的所有机器共享一个网关
- 不能访问除了本局域网外的其他内网的ip地址
- 路由器
- arp协议:地址解析协议,通过一台机器的ip地址获取到它的mac地址。用到了交换机的广播和单播功能
网络开发架构
- C/S架构:需要安装才可使用
- client:客户端
- server:服务端
- B/S架构:需要浏览器
- browers:浏览器
- server:服务端
osi五层协议
- 物理层
- 数据链路层 mac arp协议相关 硬件:网卡 二层交换机
- 网络层 ipv4和ipv6 硬件:路由器 三层交换机
- 传输层 port 硬件:四层路由器 四层交换机
- 应用层
tcp和udp
tcp(语音聊天、视频聊天、线下缓存电影、发邮件)
- 需要先建立连接,然后才能通信
- 占用连接、可靠(消息不会丢失)、实时性高、慢
- 建立连接——三次握手(全双工通信)
- client端向server端发送请求连接SYN
- server端回复client端SYN+ACK
- client端再次向server端回复ACK
- 断开连接——四次挥手
- 断开连接发送FIN信号(A)
- 回复ACK信号(B)
- 发送FIN信号(B)
- 回复ACK信号(A)
udp(发信息、在线播放)
- 不需要建立连接,就可以通信
- 不占用连接、不可靠(消息因网络不稳定丢失)、快
tcp
# tcp——server
import socket
sk = socket.socket()
sk.bind(("127.0.0.1", 8080)) # 申请的操作系统资源
sk.listen()
conn, addr = sk.accept() # conn存储一个client端和server端的连接信息
conn.send('你好'.encode("utf-8"))
msg = conn.recv(1024)
print(msg)
conn.close() # 挥手断开连接
sk.close() # 归还操作系统资源
# tcp——client
import socket
sk = socket.socket()
sk.connect(("127.0.0.1",8080))
msg = sk.recv(1024)
print(msg.decode("utf-8"))
sk.send(b'bye')
sk.close()
# tcp——server 聊天
import socket
sk = socket.socket()
sk.bind(("127.0.0.1", 8080)) # 申请的操作系统资源
sk.listen()
while True:
conn, addr = sk.accept() # conn存储一个client端和server端的连接信息
while True:
send_msg = input(">>>")
conn.send(send_msg.encode("utf-8"))
if send_msg.upper() == "Q":
break
msg = conn.recv(1024)
print(msg.decode("utf-8"))
conn.close() # 挥手断开连接
sk.close() # 归还操作系统资源
# tcp——client 聊天
import socket
sk = socket.socket()
sk.connect(("127.0.0.1", 8080))
while True:
msg = sk.recv(1024).decode("utf-8")
if msg.upper() == "Q":break
print(msg)
send_msg = input(">>>")
sk.send(send_msg.encode("utf-8"))
if send_msg.upper() == "Q": break
sk.close()
udp
# udp——server
import socket
sk = socket.socket(type=socket.SOCK_DGRAM)
sk.bind(("127.0.0.1", 8080))
msg, addr = sk.recvfrom(1024)
print(msg)
sk.sendto(b'hello', addr)
# udp——client
import socket
sk = socket.socket(type=socket.SOCK_DGRAM)
addr = ("127.0.0.1", 8080)
sk.sendto(b'hi', addr)
msg = sk.recv(1024)
print(msg)
# udp——server 聊天
import socket
sk = socket.socket(type=socket.SOCK_DGRAM)
sk.bind(("127.0.0.1", 8080))
while True:
msg, addr = sk.recvfrom(1024)
print(msg.decode("utf-8"))
send_msg = input(">>>").encode("utf-8")
sk.sendto(send_msg, addr)
# udp——client 聊天
import socket
sk = socket.socket(type=socket.SOCK_DGRAM)
addr = ("127.0.0.1", 8080)
while True:
send_msg = input(">>>").encode("utf-8")
if send_msg.upper() == "Q":break
sk.sendto(send_msg, addr)
msg = sk.recv(1024).decode("utf-8")
if msg.upper() == "Q":
break
print(msg)
粘包——tcp
- 粘包只出现在tcp协议中,因为tcp协议多条信息之间没有边界,并且还有一大堆优化算法
- 服务端:两条信息发送间隔很短,信息很短(都在缓存中一起发送过去)
- 客户端:接收信息不及时(缓存堆积)
# tcp——server 解决粘包问题
import struct
import socket
sk = socket.socket()
sk.bind(("127.0.0.1", 8080))
sk.listen()
conn, addr = sk.accept()
msg1 = input(">>>").encode()
msg2 = input(">>>").encode()
blen = struct.pack("i", len(msg1)) # 将长度信息转换为4字节的byte
conn.send(blen)
conn.send(msg1)
conn.send(msg2)
conn.close()
sk.close()
# tcp——client
import struct
import socket
sk = socket.socket()
sk.connect(('127.0.0.1', 8080))
length = sk.recv(4) # 接收4字节的长度信息,从而确定第一次的信息长度
length = struct.unpack('i', length)[0]
msg1 = sk.recv(length)
msg2 = sk.recv(1024)
print(msg1.decode('utf-8'))
print(msg2.decode('utf-8'))
sk.close()
文件传输
# server
import json
import struct
import socket
# 接收
sk = socket.socket()
sk.bind(('127.0.0.1',9001))
sk.listen()
conn,_ =sk.accept()
msg_len = conn.recv(4)
dic_len = struct.unpack('i',msg_len)[0]
msg = conn.recv(dic_len).decode('utf-8')
msg = json.loads(msg)
with open(msg['filename'],'wb') as f:
while msg['filesize'] > 0:
content = conn.recv(1024)
msg['filesize'] -= len(content)
f.write(content)
conn.close()
sk.close()
# client
import os
import json
import struct
import socket
# 发送
sk = socket.socket()
# sk.connect(('192.168.14.109',9012))
sk.connect(('127.0.0.1',9001))
# 文件名\文件大小
abs_path = r'D:\python22期\day28 课上视频\3.网络基础概念.mp4'
filename = os.path.basename(abs_path)
filesize = os.path.getsize(abs_path)
dic = {'filename':filename,'filesize':filesize}
str_dic = json.dumps(dic)
b_dic = str_dic.encode('utf-8')
mlen = struct.pack('i',len(b_dic))
sk.send(mlen) # 4个字节 表示字典转成字节之后的长度
sk.send(b_dic) # 具体的字典数据
with open(abs_path,mode = 'rb') as f:
while filesize>0:
content = f.read(1024)
filesize -= len(content)
sk.send(content)
sk.close()
sockerserver
- 对底层socket的封装
- 实现tcp的并发
# server
import time
import socketserver
class Myserver(socketserver.BaseRequestHandler):
def handle(self):
conn = self.request
while True:
try:
content = conn.recv(1024).decode('utf-8')
conn.send(content.upper().encode('utf-8'))
time.sleep(0.5)
except ConnectionResetError:
break
server = socketserver.ThreadingTCPServer(('127.0.0.1', 8080), Myserver)
server.serve_forever()
# client
import socket
sk = socket.socket()
sk.connect(('127.0.0.1', 8080))
while True:
sk.send(b'hello')
content = sk.recv(1024).decode('utf-8')
print(content)