一.网络基础
1.网络基础相关的知识
(1) 架构
a. C/S 架构 : client 客户端 和 server 服务器端
优势: 能充分发挥PC机的性能
b. B/S 架构 : browser 浏览器 和 server 服务器端
优点 : 统一了应用的接口
(2)通信
a. 同一台电脑上两个程序通信 : 打开一个文件
b. 两个电脑如何通信 : 连一个网线
c. 多个电脑通信:
ex : 电脑1(源)要找电脑2(目标)
电脑1首先发送一个请求帧,期中包含(我的ip是192.168.1.1,我的mac地址是xxxxxxxx,我要找ip地址为192.168.1.2的主机),将此请求发送给交换机.
交换机要广播这条消息给其他所有的主机
目标主机接收到消息后,对比发现自己就是被找的主机,回复给交换机信息(我的ip地址是192.168.1.2,我的mac地址是yyyyyyyyy,请回复给ip地址为192.168.1.1,mac地址为xxxxxxx的主机)
交换机单播形式返回给源主机
2.mac地址: 是一个物理地址,全球唯一, 类似于身份证
3.ip地址 : 是一个四位点分十进制,它标识了计算机在网络中的位置
4.交换机的通信方式:
广播: 吼一嗓子
单播 : 一对一
组播 : 一对多
5.arp协议 : 通过目标ip地址获取目标mac地址的一个协议
6.端口 : 操作系统位本机每一运行的程序都随机分配一个端口, 其他电脑上的程序可以通过端口来获取到这个程序 (ip地址 + 端口 能唯一找到某台电脑上的某一个服务程序)(0-65535 0-1023不能用)
7.网段 : 一个局域网内 ip 地址的范围
8.子网掩码 : 用来计算网段的, 子网掩码 & ip 地址 获取网段
9.arp协议 : 同过目标ip地址获取目标mac 地址的一个协议
二.socket模块
一.OSI 五层模型 :
1.应用层 http,https,ftp
2.传输层 四层交换机,四层路由器 UDP和 TCP
3.网络层 路由器,以太网交换机 IP协议
4.数据链路层 交换机,网卡,网桥 arp协议
5.物理层 光纤,集成器,网线
二.socket模块
TCP协议 面向连接,可靠的,面向字节流形式的
UDP协议 无连接的,不可靠,面向数据报形式的,传输速度快
1.交换价和路由器的区别?
交换机的主要功能是组织局域网,经过交换机内部处理解析信息之后,将信息以点对点,点对多的形式,发送给固定端
路由器的主要功能: 进行跨网段进行数据传输,路由选择最佳路径
EX:
如果你需要将多台电脑连接到一根网线,用交换机即可
如果你只有一个外网ip, 但是你有好多台电脑需要上网, 用路由器
2.TCP协议编码流程
服务器端: 客户端
实例化对象 实例化对象
绑定ip地址和端口号
监听
接收客户端的连接 连接服务器
收发 收发
关闭 关闭
# 服务端
import socket
import time
sk = socket.socket()
sk.bind(('127.0.0.1', 65534))
sk.listen()
conn, addr = sk.accept()
while 1:
mag_r = conn.recv(1024).decode('utf-8')
print(mag_r)
mag_s = input('>>>')
conn.send(mag_s.encode('utf-8'))
sk.close()
conn.close()
# 客户端
import socket
import time
sk = socket.socket()
sk.connect(('127.0.0.1', 65534))
while 1:
mag_r = input('>>>')
sk.send(mag_r.encode('utf-8'))
mag_s = sk.recv(1024).decode('utf-8')
print(mag_s)
sk.close()
3.回环地址: 127.0.0.1 每个计算机都有的这么一个本机地址,只能被本机识别,不会被其他机器识别
4.tcp三次握手: 一定是client先发起请求
a. 客户端发起请求连接服务器
b.服务器返回 : 接收到请求, 并要求连接客户端
c.客户端回复: 可以连接
5.四次挥手: 谁先发起断开连接的请求都可以
a. 客户端发起断开连接的请求
意思是: 我想和你断开连接,我没有数据要继续发送,但是如果你有数据需要发送,我可以继续接收
b.服务器回复 : 我接收到你的请求了
c.服务器发送 : 我已经准备好断开连接了
d.客户端回复: 收到你的信息, 断开连接
6.UDP协议
type = SOCK_DGRAM
UDP协议的通信的优势:
允许一个服务器同时和多个客户端通信, TCP不行
# UDP 服务端
import socket
sk = socket.socket(type=socket.SOCK_DGRAM)
sk.bind(('127.0.0.1', 8880)) # 绑定ip地址和端口
dic = {'alex': '\033[34m', 'wusir': '\033[37m'} # 配颜色
while 1:
conn, addr = sk.recvfrom(1024) # 接收客户端的信息和地址
mag_r = conn.decode('utf-8')
name = mag_r.split(':')[0].strip()
color = dic.get(name, '')
print('%s %s \033[0m' % (color, mag_r))
# print(conn.decode('utf-8'), addr)
mag_s = input('>>>')
sk.sendto(mag_s.encode('utf-8'), addr)
# if conn == '88':
# break
sk.close()
# 客户端
# UDP
import socket
sk = socket.socket(type=socket.SOCK_DGRAM) # 指定UDP协议
name = input('请输入您的名字: ')
while 1:
mag_s = input('>>>')
info = name + ' : ' + mag_s
sk.sendto(info.encode('utf-8'), ('127.0.0.1', 8880))
conn, addr = sk.recvfrom(1024)
print(conn.decode('utf-8'), addr)
sk.close()
7.pycharm输出带颜色
\033[ 字体颜色: 背景颜色 m 数据 \033[0m
8.自定义编码和解码类继承socket
import socket
# 自定义编码解码类继承socket文件中的socket类
class My_socket(socket.socket): # 继承自 socket文件中的socket类,此时socket就是父类
def __init__(self, encoding='utf-8'):
self.encoding = encoding
super(My_socket, self).__init__(type=socket.SOCK_DGRAM) # 执行父类socket中的__init__方法
def my_sendto(self, mag, addr):
return self.sendto(mag.encode(self.encoding), addr) # 调用父类中的init方法
def my_recvfrom(self, num):
mag_s, addr = self.recvfrom(num) # 调用父类中recvfrom方法
return mag_s.decode(self.encoding), addr
from My_UDP import My_socket
# server端
sk = My_socket()
sk.bind(('127.0.0.1', 8850))
conn, addr = sk.my_recvfrom(1024)
print(conn, addr)
sk.close()
from My_UDP import My_socket
# client端
sk = My_socket()
mag_s = input('>>>')
sk.my_sendto(mag_s, ('127.0.0.1', 8850))
sk.close()
三.执行命令
1.在py代码中如何去调用操作系统的命令
# 服务器端
import socket
import subprocess
sk = socket.socket()
sk.bind(('127.0.0.1', 8080))
sk.listen()
conn, addr = sk.accept()
while 1:
mag_r = conn.recv(1024).decode('utf-8')
r = subprocess.Popen(mag_r, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout = r.stdout.read()
stderr = r.stderr.read()
if stderr:
conn.send(stderr)
else:
conn.send(stdout)
conn.close()
sk.close()
# 客户端
# 客户端发送要执行的命令
# 服务器执行, 执行完将结果返回给客户端
# 客户端拿到结果呈现到用户眼前
import socket
sk = socket.socket()
sk.connect(('127.0.0.1', 8080))
while 1:
cmd = input('请输入一个命令>>>')
sk.send(cmd.encode('utf-8'))
result = sk.recv(2048).decode('gbk')
print(result)
sk.close()
2.新模块; subprocess
r = subprocess.Popen(mag_r, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout = r.stdout.read()
stderr = r.stderr.read()
# mag_r : 代表系统命令
# shell=True 代表这条命令是系统命令,告诉操作系统,将mag_r当做系统命令去执行
# stdout 是执行完系统命令之后,用于保存正确结果的一个管道
# stderr 实执行完系统命令之后,用于保存错误结果的一个管道
print(r.stdout.read().decode('gbk'))
print(r.stderr.read().decode('gbk')) # 操作系统默认编码是gbk
四.粘包问题
1.只有tcp协议才会有粘包,udp不会发生
EX: 发送端发送数据, 接收端不知道应该去如何去接收, 造成的一种数据混乱的现象
2.在tcp协议中有两个机制
1.合包机制(nagle算法) 将多次连续发送且间隔较小的数据, 进行打包成一块数据发送过去
2.拆包机制,在发送端,因为受到网卡的MTU限制, 会将大的超过MTU限制的数据, 拆分成多个小的数据,进行传输, 当传输到目标主机的操作系统层时, 会重新将多个小的数据合并成原本的数据
3.MTU(数据链路层)
MTU是Maximum Transmission Unit 的缩写. 意思是网络上传送的最大数据包, MTU的单位是字节, 大部分网络设备的MTU都是1500, 如果本机的MTU比网关的MTU大, 大的数据包就会被拆开来发送,这样会产生很多数据包碎片,增加丢包率,降低网络速度