接口测试之主流协议测试合集(python版)
01 TCP/IP四层模型&OSI七层模型
1. OSI,TCP/IP,五层协议的体系结构,以及各层协议
-
OSI分层 (7层):物理层、数据链路层、网络层、传输层、会话层、表示层、应用层。
-
TCP/IP分层(4层):网络接口层、 网际层、运输层、 应用层。
-
网络接口层:ip
-
网际层:TCP、UDP
-
运输层
-
应用层
-
五层协议 (5层):物理层、数据链路层、网络层、运输层、 应用层。
-
每层作用
- 物理层:
传输二进制比特流
- 数据链路层:
负责将上层数据封装成帧
- 网络层:
负责路由寻址和广播 ;广播:发送消息和接收消息
*传输层:负责建立一个可靠的端到端的连接;端到端:发送到接收 ;过程:建立、维护、撤销(拆除)
- 会话层:
负责建立维护拆除会话,为端应用之间提供控制功能(可靠性)
- 表示层:
完成对传输数据格式转换:格式化;发:加密;接:解密;发:压缩,接:解压缩
- 应用层:
对应用软件提供网络支持
- 物理层:
02 IP协议
1. IP地址: 所有主机都会分配一个IP地址(不重复) ipv4 4位组成0-255,网关,子掩码。
2.端口: 为了确定主机上的应用程序。0-65535能使用的端口1024-65535
3.域名: 在万维网上注册的网站名称。通过域名解析变成ip地址。
03 TCP协议
1. 定义
- TCP协议又称传输控制协议,是面向连接的可靠传输;
- 发送⽅和接收⽅的成对的两个socket之间必须建⽴连接,以便在TCP协议的基础上进⾏通信,当⼀个socket(通常都是server socket)等待建⽴连接时,另⼀个socket可以要求进⾏连接,⼀旦这两个socket连接起来,它们就可以进⾏双向数据传输,双⽅都可以进⾏发送 或接收操作
2. 特点
- ⾯向连接的协议,在socket之间进⾏数据传输之前必然要建⽴连接,所以在TCP中需要连
接时间。 - TCP传输数据⼤⼩限制,⼀旦连接建⽴起来,双⽅的socket就可以按统⼀的格式传输⼤的数据。
- TCP是⼀个可靠的协议,它确保接收⽅完全正确地获取发送⽅所发送的全部数据。
3.应用场景
- IM及时通信、游戏、工控、物联网、微服务
4. 测试脚本
'''
1. 序列化: 将数据结构或对象转换成二进制串的过程
1) 获取私有协议说明文档
2)google的protobuf作为序列化工具
(1)安装protoc工具
(2)构造私有协议的proto文件
(3)将proto编译成.py文件
`protoc --python_out=生成的py文件存放目录 xxx.proto` 读入xxx.proto,输出python文件到一个指定目录下
`protoc --java_out=生成的jar文件存放目录 xx.proto`
(4)在测试脚本中使用编译生成的.py
2. 创建套接字
3. 连接服务器 socket.con
4. 构造请求并进行序列化:SerializeToString()
5. 发送数据:socket.sendall()
6. 接受数据,并进行反序列化操作:ParseFromString
7. 响应断言
'''
import unittest
import socket
import json
from protocol_test.tcp import data_pb2
class TestTcpDemo(unittest.TestCase):
def setUp(self) -> None:
pass
def setUpClass(cls) -> None:
pass
def tearDown(self) -> None:
pass
def tearDownClass(cls) -> None:
pass
def test_login_01(self):
# 接口地址
self.server = ('127.0.0.1','8889')
# 创建套接字
self.s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# 连接服务器
self.s.connect(self.server)
# 发送数据
self.send_data = data_pb2.SendData()
self.revc_data = data_pb2.RevcData()
# 构造请求
self.send_data.control = 1
self.send_data.action = 1
self.userinfo = {
"username": "test001",
"passwd": "123456",
}
self.send_data.user_data = json.dumps(self.userinfo)
# 序列化,二进制字符串
self.send_data = self.send_data.SerializeToString()
# 发送数据
self.s.sendall(self.send_data)
# 接受数据
self.ret = self.revc_data(65536)
# 反序列化
self.revc_data.ParseFromString(self.ret)
# 断言
self.assertEqual(200,self.revc_data.status)
# 断开连接
self.s.close()
04 UDP协议
1. 定义
- UDP是User Datagram Protocol的简称,是⼀种⽆连接的协议;
- 每个数据报都是⼀个独⽴的信息,包括完整的源地址或⽬的地址;
- 它在⽹络上以任何可能的路径传往⽬的地,因此能否到达⽬的地,到达⽬的地的时间以及内容的正确性都是不能被保证的。
2.特点
- 每个数据报中都给出了完整的地址信息,因此⽆需要建⽴发送⽅和接收⽅的连接。
- UDP传输数据时是有⼤⼩限制的,每个被传输的数据报必须限定在64KB之内。
- UDP是⼀个不可靠的协议,发送⽅所发送的数据报并不⼀定以相同的次序到达接收⽅。
3.TCP和UDP的对比
- TCP,可靠,传输大小无限制,但是需要连接建立时间,差错控制开销大。
- UDP,不可靠,差错控制开销较小,传输大小限制在64K以下,不需要建立连接。
4. UDP服务端
import socket
def main():
#1.创建套接字
udp_socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM) # tcp为SOCK_STREAM
# 2. 绑定一个本地信息
localAddr = ('169.254.148.206', 8001) # 自己电脑的ip以及port号,其他的不行
udp_socket.bind(localAddr)
# 3. 接收数据
while 1:
recv_data = udp_socket.recvfrom(65536) #存储的是一个元组(接收到的数据,(发送方的ip,port)) Tuple[bytes, _RetAddress]
recv_msg = recv_data[0] # 接收的数据
send_addr = recv_data[1] # 发送方的地址
# 4.打印接收到的数据
print('{}:{}'.format(str(send_addr), recv_msg.decode('utf-8')))
if not recv_msg:
break
# 5.关闭套接字
udp_socket.close()
if __name__ == '__main__':
main()
5. UDP客户端
import socket
def main():
# 1.创建一个udp套接字
udp_socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
addr = ('169.254.148.206',8001)
while True:
# 从键盘输入数据
send_data = input('请输入要发送的数据:')
# 如果输入exit,就退出程序
if send_data =='exit':
break
# 可以使用套接字发送数据
#upd_scoket.sendto('ahahahha','对方的ip及端口')
udp_socket.sendto(send_data.encode('utf-8'),addr)
# 关闭套接字
udp_socket.close()
if __name__ == '__main__':
main()
05 web services协议
https://www.w3school.com.cn/ws.asp
1. Web Services定义:
- 一个SOA(面向服务的编程)的架构,它是不依赖于语言,不依赖于平台,可以实现不同的语言间的相互调用,通过Internet进行基于Http协议的网络应用间的交互
2. web services组成元素:
SOAP(简易对象访问协议)
:- 一种使应用程序有能力通过 HTTP 交换信息的基于 XML 的简易协议
- 一种用于访问 web service 的协议
UDDI(通用描述、发现及整合)
:- 基于 XML 的跨平台的描述规范
- 用于存储有关 web services 的信息的目录
WSDL(Web services 描述语言)
:- 基于 XML 的用于描述 网络服务以及如何访问 Web Services 的语言;
- 可描述 web service,连同用于 web service 的消息格式和协议的细节。
3. 基本工作原理
- web
服务提供者
设计实现Web服务,并将调试正确后的Web服务通过Web服务中介者
发布,并在UDDI注册中心注册; (发布) - Web
服务请求者
向Web服务中介者
请求特定的服务,中介者
根据请求查询UDDI注册中心,为请求者
寻找满足请求的服务; (发现) - Web
服务中介者
向Web服务请求者
返回满足条件的Web服务描述信息,该描述信息用WSDL写成,各种支持Web服务的机器都能阅读;(发现) - 利用从Web
服务中介者
返回的描述信息生成相应的SOAP消息,发送给Web服务提供者
,以实现Web服务的调用;(绑定) - Web
服务提供者
按SOAP消息执行相应的Web服务,并将服务结果返回给Web服务请求者
。(绑定)
4. python实现
- 安装suds
pip install suds -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com
import unittest
from suds.client import Client
import json
import sys
from time import sleep
import logging
class WebServiceApi(Client):
def __init__(self, url, **kwargs):
super().__init__(url, **kwargs)
class TestWebServiceDemo(unittest.TestCase):
@classmethod
def setUpClass(cls) -> None:
pass
def setUp(self) -> None:
pass
def tearDown(self) -> None:
pass
@classmethod
def tearDownClass(cls) -> None:
pass
# 无参形式
def testmobilePhone001(self):
global res
mp_url = 'http://ws.webxml.com.cn/webservices/MobileCodeWS.asmx?wsdl'
wsa = WebServiceApi(mp_url)
for i in range(3):
try:
res = wsa.service.getDatabaseInfo()
if res:
body = json.dumps(res[0], ensure_ascii=False)
self.assertTrue(body not in ([], '', None))
self.assertTrue('安徽' in body)
break
else:
sleep(15)
except Exception as e:
logging.warning("第%s次请求失败!信息:%s" % (i + 1, e))
else:
sys.exit('环境异常')
# 有参形式-正常场景
def testmobilePhone002(self):
mp_url = 'http://ws.webxml.com.cn/webservices/MobileCodeWS.asmx?wsdl'
wsa = WebServiceApi(mp_url)
for i in range(3):
res = wsa.service.getMobileCodeInfo(mobileCode='13588888888')
body = json.dumps(res, ensure_ascii=False)
if body:
self.assertTrue('浙江移动' in str(body))
break
else:
sleep(15)
else:
sys.exit('请求接口三次失败')
# 有参形式-异常场景
def testmobilePhone003(self):
mp_url = 'http://ws.webxml.com.cn/webservices/MobileCodeWS.asmx?wsdl'
wsa = WebServiceApi(mp_url)
for i in range(3):
res = wsa.service.getMobileCodeInfo(mobileCode='19988888888')
body = json.dumps(res, ensure_ascii=False)
print(body)
if body:
self.assertTrue('没有此号码记录' in body)
break
else:
sleep(15)
else:
sys.exit('请求3次接口均失败')
06 HTTPS协议
1. 定义
- 身披SSL外壳的HTTP。HTTPS是一种通过计算机网络进行安全通信的传输协议,经由HTTP进行通信,利用SSL/TLS建立全信道,加密数据包。HTTPS使用的主要目的是提供对网站服务器的身份认证,同时保护交换数据的隐私与完整性。
2. 特点
- 基于HTTP协议,通过SSL或TLS提供加密处理数据、验证对方身份以及数据完整性保护,如:内容加密,验证身份,保护数据完整性,混合加密,数字摘要,数字签名技术
import unittest
import requests
import sys
class TestFinance(unittest.TestCase):
http_url = 'http://api.k780.com'
https_url = 'https://sapi.k780.com'
@classmethod
def setUpClass(cls) -> None:
pass
def setUp(self) -> None:
pass
def tearDown(self) -> None:
pass
@classmethod
def tearDownClass(cls) -> None:
pass
def request(self, url, method, data, headers=None):
for i in range(3):
try:
ret = requests.request(method=method, url=url, data=data, headers=headers)
status = ret.status_code
body = ret.json()
return status, body
except requests.exceptions as e:
print("调用接口第(%s)次失败信息:%s" % (i + 1, e))
else:
sys.exit('调用->%s三次均失败' % data['app'])
# 接口地址:https://www.nowapi.com/api/finance.rate
def test_finance_rate(self):
params = {
'app': 'finance.rate',
'scur': 'HKD',
'tcur': 'CNY',
'appkey': '65550',
'sign': 'f9d448dab9b6e7590140279ccffe3c23',
'format': 'json',
}
status, body = self.request(self.https_url, 'post', data=params)
print(body)
self.assertEqual(status, 200, '状态码为200')
if body:
self.assertTrue(body['success'] != '0', 'success==1')
self.assertTrue(body['result']['rate'] not in (None, ""))
else:
print(status)
def test_weather_future(self):
params = {
'app': 'weather.future',
'weaId': '1',
'appkey': '65550',
'sign': '77f6e1bd4e22de810987fcb8423941a5',
'format': 'json',
}
status, body = self.request(self.https_url, 'post', data=params)
print(body)
self.assertEqual(body['success'], '1')
self.assertIn('北京', str(body['result']), '返回北京天气预报')
07 dubbo协议
7.1 RPC&dubbo
1. rpc
: 远程过程调用,通俗地讲RPC就是要解决远程服务间的调用问题,也就是管理服务配置并提供便捷可靠高效的服务间调用。
2. dubbo
:是一个分布式的服务框架,致力于提供高性能和透明化的RPC远程服务调用方案,以及SOA服务治理方案。既是框架也是协议
3. rpc和dubbo的关系
:rpc是一种编程细想或者是通信方式(RPC不是协议),而dubbo是rpc的一种实现方式,dubbo基于tcp协议开发
7.2 dubbo框架概念
1. 节点角色说明
Provider
: 暴露服务的服务提供方。Consumer
: 调用远程服务的服务消费方。Registry
: 服务注册与发现的注册中心。Monitor
: 统计服务的调用次调和调用时间的监控中心。Container
: 服务运行容器。
2. 调用关系说明
0.start
. 服务容器负责启动,加载,运行服务提供者。1. register
服务提供者在启动时,向注册中心注册自己提供的服务。2. subscribe
服务消费者在启动时,向注册中心订阅自己所需的服务。3. notify
: 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。4. invoke
:服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。5. count
服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。
7.3 telnetlib方式实现dubbo测试
1. 模块封装
import logging
from telnetlib import Telnet
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
class DubboApi(Telnet):
prompt = 'dubbo>'
def __init__(self, host, port):
# 1. 创建telnet对象
super().__init__((host, port))
self.write(b'\n')
def command(self, flag, _command=''):
data = self.read_until(flag.encode())
# 3. 用write发送dubbo请求
self.write(_command.encode() + b'\n')
return data
def invoke(self, service_name, method_name, args=None):
if args is None:
args = []
if not args:
cmd_string = "invoke {0}.{1}.()".format(
service_name, method_name
)
else:
cmd_string = "invoke {0}.{1}.({2})".format(
service_name, method_name, args
)
invoke_count = 0
while invoke_count<5:
self.command(DubboApi.prompt, cmd_string) # 读取到标志位
ret = self.command(DubboApi.prompt, "")
body = ret.decode().split('\r\n')[0] # 解码
# 4. 获取返回信息
# read_until()当结果中存在想要的信息时返回。
# read_some() 只要有结果就返回。
# read_very_lazy():返回缓冲区中的数据。
if body:
return body
else:
invoke_count += 1
else:
logging.error("调用dubbo接口超过五次,调用失败")
# 退出telnet
def logout_host(self):
self.write(b"exit\n")
logging.info("登出成功")
2. 测试用例
import unittest
from dubbo.dubbo_api import DubboApi
class TestTelnetLib(unittest.TestCase):
@classmethod
def setUpClass(cls) -> None:
pass
def setUp(self) -> None:
pass
def tearDown(self) -> None:
pass
@classmethod
def tearDownClass(cls) -> None:
pass
def test_dubbo_demo01(self):
dubbo_client = DubboApi('127.0.0.1', 8090)
ret = dubbo_client.invoke(
'com.dubbo.api.DemoService',
'method',
'param1,param2'
)
self.assertEqual('200', ret['status'], '返回200')
if __name__ == '__main__':
unittest.main()