文章目录
- 网络基础
- osi协议
- 简单的网络通信
- TCP文件传输
- UDP文件的传输
- 粘包现象
- socketserver模块
网络基础
打基础
了解一些网络的基础知识
简单了解一些底层的网络通信
3-4天
网络的概念
基于原生的网络模块来实现通信
完成一些简单的程序
了解一些协议的特点,扬长避短
概念
学号:临时的编号/变化的
身份证号:唯一标识/不变的
不变的:mac地址 能够唯一标识你这台机器
变化的:IP地址 能够更方便的找到你的机器
vnc/飞秋 都不涉及mac
局域网
连在一台交换机上的每台机器组成一个局域网
交换机只认mac,第一次会把包转发到局域网内所有的设备,只有对应的才回答
ARP:地址解析协议。交换机的广播和单播。
局域网 – > 网关<-路由器->网关 —> 局域网
IP地址
ipv4:四位点分十进制
192.168.12.78
公网地址:需要我们自己申请购买的地址
内网地址:保留字段
192.168.X.X 内网地址 学校
172.16.0.0 学校
10.0.0.0- 10.255.255.255 公司
特殊的ip地址
127.0.0.1 本地回环地址 测试的时候用的
ipconfig 查看自己的IP地址
子网掩码
用来判断两台机器在不在一个局域网内
192.168.12.1
11000000.10101000.00001100.00000001
255.255.255.0
11111111.11111111.11111111.00000000
11000000.10101000.00001100.00000000
192.168.12.0
看子网掩码判断两个IP地址是不是在同一个局域网内
ipv6
0:0:0:0:0:0-
ip/mac 确认机器
端口 0-65535 确认机器上的具体应用程序
osi协议
osi7/5层协议
应用层 表示层 会话层(三层合并成应用层) python 5 6 7层
传输层 port 4层 四层路由器/交换机
网络层 ip 3层 路由器 三层交换机
数据链路层 mac 2层 网卡 二层交换机
物理层 二进制串 1层
tcp 和 udp 传输层
tcp (语音聊天/视频聊天)- 线下缓存/qq远程控制
需要先建立链接 然后才能通信
占用连接/可靠(消息不会丢失)/实时性高/慢
建立连接 - 三次握手
全双共通信
server SYN < - client
server - > ACK SYN client
server ACK < - client
断开连接 - 四次挥手
server FIN < - client
server - > ACK client
server - > FIN client
server ACK < - client
因为对方可能还有一些数据没传完,要双方都确定断开才断开
udp (发消息)-在线播放视频
不需要建立链接
不占用连接/不可靠(消息因为网络不稳定而丢失)/快
简单的网络通信
网络开发架构
C/S架构 : 需要安装一下才能使用
CLIENT
SERVER
可以离线使用/更安全
B/S架构
browser
server
不需要安装也能使用
B/S也是C/S的一种
统一用户的入口
server端
import socket
sk = socket.socket()
sk.bind(('127.0.0.1', 9000))
sk.listen()
while True:
conn, addr = sk.accept()
while True:
send_m = input('>>>')
conn.send(send_m.encode('utf-8'))
if send_m.upper() == 'Q':
break
msg = conn.recv(1024)
msg2 = msg.decode('utf-8')
if msg2.upper() == 'Q':
break
print(msg2)
conn.close()
sk.close()
client端
import socket
sk = socket.socket()
sk.connect(('127.0.0.1', 9000))
while True:
msg = sk.recv(1024)
msg2 = msg.decode('utf-8')
if msg2.upper() == 'Q':
break
print(msg2)
send_m = input('>>>')
sk.send(send_m.encode('utf-8'))
if send_m.upper() == 'Q':
break
sk.close()
TCP文件传输
server端
import socket
import json
import struct
# 接收
sk = socket.socket()
sk.bind(('127.0.0.1', 9000))
sk.listen()
conn, _ = sk.accept()
blen = conn.recv(4)
blen = struct.unpack('i', blen)
msg = conn.recv(blen[0]).decode('utf-8')
msg = json.loads(msg)
# print(msg)
with open(msg['filename'], mode='wb') as f:
while msg['filesize'] > 0:
content = conn.recv(1024)
msg['filesize'] -= 1024
f.write(content)
conn.close()
sk.close()
client端
import socket
import os
import json
import struct
# 发送
sk = socket.socket()
sk.connect(('127.0.0.1', 9000))
# 文件名/文件大小
abs_path = r'C:\Users\libo\Downloads\大圣换肤盒子v1.7 (1).exe'
filename = os.path.basename(abs_path)
filesize = os.path.getsize(abs_path)
dic = {'filename': filename, 'filesize': filesize}
str_dic = json.dumps(dic)
blen = struct.pack('i', len(str_dic))
sk.send(blen)
sk.send(str_dic.encode('utf-8'))
with open(abs_path, mode='rb') as f:
while filesize > 0:
content = f.read(1024)
filesize -= len(content)
sk.send(content)
sk.close()
UDP文件的传输
server端
import socket
sk = socket.socket(type=socket.SOCK_DGRAM) # UDP 协议
sk.bind(('127.0.0.1', 9000))
msg, addr = sk.recvfrom(1024)
print(msg)
sk.sendto(b'recv', addr)
client端
import socket
sk = socket.socket(type=socket.SOCK_DGRAM) # UDP 协议
server = ('127.0.0.1', 9000)
sk.sendto(b'info', server)
msg = sk.recv(1024)
print(msg)
粘包现象
连续发送的两条消息,成为了一条消息发送过去
发送消息 缓存机制 不一一发 浪费时间
可能发生在 发送端 和 接收端
粘包现象只发生在TCP协议中, 因为tcp多条消息之间没有边界
发送端:两条消息很短,发送时间间隔也很短
接收端:多条消息由于没有及时接收,而在接收方的缓存短堆在一起导致的粘包
导致粘包的本质:设置边界。你发多少,我就接多少。
做一个自定义长度协议
宪法一个长度,我们规定长度的为4个字节
然后对面接收4个字节,把长度得到, 然后接收固定长度的数据
server端
import struct
import socket
sk = socket.socket()
sk.bind(('127.0.0.1', 9000))
sk.listen()
conn, addr = sk.accept()
msg1 = input('...').encode('utf-8')
msg2 = input('...').encode('utf-8')
blen1 = struct.pack('i', len(msg1))
conn.send(blen1)
conn.send(msg1)
blen2 = struct.pack('i', len(msg2))
conn.send(blen2)
conn.send(msg2)
sk.close()
# encode() decode() 用什么方式编码 就用什么方式解码
# zfil()自动在左边补零
# # num = 6
# # s = str(num)
# # res = s.zfill(4)
# # print(res) # 0006
# import struct
#
# num = 12345
# ret = struct.pack('i', num)
# print(ret) # b'90\x00\x00'
#
# re = struct.unpack('i', ret)
# print(re) # (12345,)
# struct.pack:自动把传入的num解析为四个字节的数据
# struct.unpack:再解回来
client端
import socket
import struct
import time
sk = socket.socket()
sk.connect(('127.0.0.1', 9000))
time.sleep(0.1)
blen1 = sk.recv(4)
blen1 = struct.unpack('i', blen1)
msg1 = sk.recv(blen1[0])
print(msg1.decode('utf-8'))
blen2 = sk.recv(4)
blen2 = struct.unpack('i', blen2)
msg2 = sk.recv(blen2[0])
print(msg2.decode('utf-8'))
sk.close()
socketserver模块
socket 底层
socketserver 基于socket完成的 封装度高
tcp协议的server端处理并发的客户端请求
server.py
import socketserver
import time
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', 9000), Myserver)
server.serve_forever()
client.py
import socket
sk = socket.socket()
sk.connect(('127.0.0.1', 9000))
while True:
sk.send(b'hello')
content = sk.recv(1024).decode('utf-8')
print(content)