网络编程
软件开发架构:
c/s架构(client/server)
c:客户端
s:服务端
b/s架构(browser/server)
b:浏览器
s:服务器
bs架构本质也是cs架构
服务端:24小时不间断服务
客户端:什么时候体验服务,就去服务端寻求服务
计算机与计算机实现远程通信除了物理连接介质之外, 还需要有一套公共的标准协议
OSI协议
七层协议:应用层 表示层 会话层 传输层 网络层 数据链路层 物理连接层
五层协议:应用层 传输层 网络层 数据链路层 物理连接层
1. 物理连接层
基于电信号传输的二进制
2. 数据链路层
规定了电信号分组方式,
规定任何一台接入互联网的计算机都必须有一个网卡,每一个网卡上都有唯一的编号,
编号是12位的16进制数, 前六位是厂商编号, 后六位为流水线编号
这12位数叫做mac地址
以上两点合称为''以太网协议''
交换机
基于以太网协议通信,不能跨越局域网通信
互联网是由n多个局域网彼此之间连接而成
3.网络层
IP协议:规定只要连接互联网的计算机都必须有唯一的ip地址
ip地址特点:一个ip地址通常写成四段十进制数, 点分十进制,版本:IPV4,IPV6
0.0.0.0 ip地址最小. 255.255.255.255 ip地址最大
ip地址是动态分配的
arp协议: 根据ip地址解析对方的mac地址
4.传输层
TCP/UDP都是基于端口工作的协议
端口(port)
计算机与计算机之间通信其实是计算机上的应用程序与应用程序之间的通信
端口是用来唯一标识计算机上的某个应用程序
端口的范围:0-65535
0-1024这些都是操作系统默认使用的端口号
MySQL默认端口3306 Redis 默认端口6379 django默认端口8000 flask 默认端口5000
端口是动态分配的,启动一个应用程序,然后关了,再次启动,端口号可能变了
ip地址:标识接入互联网的一台计算机
port:标识一台计算机上的某个应用程序
ip+port:标识接入互联网上的一台计算机的某个应用程序
5.应用层
HTTP协议
FTP协议
TCP协议
流式协议,可靠协议, 基于TCP协议通信 , 必须先建立双向通道
三次握手四次挥手
三次握手建连接
四次挥手断连接
洪水攻击:服务器在同一时间接收了大量的请求
TCP传输数据的可靠原因在于它有反馈机制,当发出消息之后,只有对方确认消息之后,才会将数据从内存中清理,否则在限定的时间里每隔一段时间在发出一次.
实现单次接收与发送
客户端 import socket client = socket.socket() client.connect(('127.0.0.1',8080)) client.send(b'hi') data = client.recv(1024) print(data) # b'hello' client.close() 服务端 import socket # socket 套接字 from socket import SOL_SOCKET,SO_REUSEADDR server = socket.socket() # 不传参数默认的TCP协议 server.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) server.bind(('127.0.0.1',8080)) # 把端口绑定到套接字 server.listen() # 监听链接 sock, addr = server.accept() #接收客户端链接 data = sock.recv(1024) # 接收客户端信息 print(data) #打印客户端信息 sock.send(b'hello') #向客户发送信息 b'hi' sock.close() # 关闭客户套接字 server.close() # 关闭服务器套接字
实现连续通信
客户端 import socket client = socket.socket() client.connect(('127.0.0.1',8080)) while True: res = input('>>>:').strip() if len(res) == 0:continue client.send(res.encode('utf-8')) data = client.recv(1024) print(data) 服务端 import socket from socket import SOL_SOCKET,SO_REUSEADDR server = socket.socket() server.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) server.bind(('127.0.0.1',8080)) server.listen(3) while True: coon,addr = server.accept() while True: try: data = coon.recv(1024) print(data) if len(data) == 0:break res = input('>>>:').strip() if len(res) == 0:continue coon.send(res.encode('utf-8')) except ConnectionResetError: break coon.close()
import struct import json d = {'name':'jason', 'file_size':1243} json_d = json.dumps(d) print(len(json_d)) # 36 res1 = struct.pack('i',len(json_d)) # i 表示的是4段 print(res1) # b'$x00x00x00' res2 = struct.unpack('i',res1)[0] print(res2) # 36
# 解决粘包问题
客户端 import socket import struct import json client = socket.socket() # TCP协议 client.connect(('127.0.0.1',8080)) #连接地址 while True: res = input('>>>:').strip() #发送 if len(res) == 0: continue client.send(res.encode('utf-8')) header_dict = client.recv(4) dict_size = struct.unpack('i',header_dict)[0] dict_bytes = client.recv(dict_size) dict_json = json.loads(dict_bytes.decode('utf-8')) print(dict_json) recv_size = 0 real_data = b'' while recv_size < dict_json.get('file_size'): data = client.recv(1024) real_data += data recv_size += len(data) print(real_data.decode('gbk')) 服务端 import socket import struct import json import subprocess server = socket.socket() # TCP协议 server.bind(('127.0.0.1',8080)) # 回还地址 server.listen(5) # 监听 while True: coon,addr = server.accept() while True: try: cmd = coon.recv(1024) # 接收 if len(cmd) == 0:break cmd = cmd.decode('utf-8') obj = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE) res = obj.stdout.read() + obj.stderr.read() d = {'name': 'jason', 'file_size': len(res), 'info': 'asdhjkshasdad'} json_d = json.dumps(d) #先制作一个字典的报头 header = struct.pack('i',len(json_d)) #发送字典报头 coon.send(header) #发送字典 coon.send(json_d.encode('utf-8')) #再发真是数据 coon.send(res) except ConnectionResetError: break coon.close()
TCP粘包问题
struct模块 对数据进行打包处理固定长度
服务端:
1.先生成一个字典,
2. 制作该字典的报头 json 序列化 编码
3.发送字典的报头
4.发送字典
5.发送真实数据
客户端
1.先接收固定长度的4个字节字典报头
2. 解析获取字典的报头
3. 接收字典数据 解码 反序列化
4. 接收真实数据