记录软件测试经典常见面试题
项目背景:现项目主要是做关于机器人的调度系统,涉及到web端、移动端、小程序及服务端和实体机器人端;
迭代背景:敏捷开发
记录方向:软件测试常见面试题
记录时间:长期更新
==========================================================
记录方向:
一、项目
二、接口
三、自动化
四、计算机基础
五、python
六、Linux
七、数据库
八、软件测试理论
九、学习措施
十、中间件
十一、协议
============================================================
一、项目
1、介绍一下目前的项目,担任的角色和做出的成果-------来自于软件测试群
2、在项目或者测试过程中碰到了哪些问题-------来自于软件测试群
##############我是分界线>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
二、接口
1、在项目中你是如何做接口测试的?
1.1、需要明确清楚是接口功能测试、接口自动化测试、接口性能测试、接口安全性测试;
1.2、然后根据面试官具体想问的方向去展开回答;
2、在解耦开发过程中如何进行case用例编写;
只需要定义清楚接口文档以及格式,通过mock工具进行进行mock,完成接口测试用例的编写和调试;
3、如何理解mock,就是模拟接口返回响应报文
3.1、最基础的工具可以使用fiddler的方式进行mock;
3.2、如果需要灵活的方式,可以使用代码层面的方式进行mock,使用python的内置库mock来进行mock;
3.3、或者mockrunner的方式进行mock
4、mock在工作的运用
在前后端解耦后,只需要将接口文档定义出来,就可以进行分离开发,进行校验结构和格式;
5、ddt有了解吗?
ddt:数据驱动测试,主要是和unittest框架进行结合的,pytest可以通过参数化的方式实现ddt的效果
##############我是分界线>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
三、自动化
接口自动化
1、描述一下用到的接口自动化框架--------来自于软件测试群
2、pytest有哪些断言方式-------来自于软件测试群
3、pytest的fixture调用方式有哪些-------来自于软件测试群
4、如果要调用多个fixture,应该怎么做?装饰器嵌套的方式可以实现吗?-------来自于软件测试群
5、多接口依赖怎么处理,比如B接口需要用到A接口的返回值-------来自于软件测试群
6、pytest实现fixture的原理是怎么样的-------来自于软件测试群
UI自动化
1、selenium的元素定位方式有哪些?-------来自于软件测试群
2、不可见的元素怎么定位-------来自于软件测试群
3、selenium的用例怎么替身运行效率?
##############我是分界线>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
四、计算机网络基础、抓包
1、怎么用fiddler打断点,怎么修改响应返回的内容-------来自于软件测试群
2、fiddler怎么抓app的包-------来自于软件测试群
3、http请求有哪些请求头-------来自于软件测试群
4、什么是长连接-------来自于软件测试群
答:在一个TCP连接上传输多个数据包;
自己所了解到的长连接主要有一下三种:
4.1、http1.0以后,请求头部信息中有键值对connection:keep-alive,实现了请求、响应后不断开连接,可以继续进行数据传输;
4.2、websocket的方式,像常规的web网站上的聊天室、咨询窗口都是继续websocket的方式实现的,客户端和服务器双向通信;
4.3、sockct的,socket套接字是直接封装的传输层的协议,实现的长连接;
5、get和post请求有什么区别-------来自于软件测试群
6、python的requests库,get和pst用什么参数传递请求体-------来自于软件测试群
##############我是分界线>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
五、python
1、python的匿名函数-------来自于软件测试群-------来自于软件测试群
2、两个列表合并为一个列表-------来自于软件测试群
3、json跟字典的区别-------来自于软件测试群
4、字典跟列表的区别-------来自于软件测试群
5、字典怎么遍历值-------来自于软件测试群
6、python怎么获取一个对象的所有属性-------来自于软件测试群
7、python的深拷贝和浅拷贝
8、super用法:
1 """ 2 第一种情况:super(B,self).__init__(b) ##子类对父类的构造函数进行了继承;还可以进行扩展 3 第二种情况:super().__init__(4) ####子类对父类的构造函数进行了继承; 4 第三种情况:父类.__init__() ##这种方式是通过父类直接调用父类自身的构造函数 5 这两种方式没有实质性的区别 6 7 8 """ 9 class A(): 10 def __init__(self,a): 11 if a>5: 12 raise AssertionError 13 self.a = a 14 self.data = None 15 16 class B(A): 17 def __init__(self,b,c): 18 super(B,self).__init__(b) ##子类对父类的构造函数进行了继承; 19 self.c = c 20 21 22 obj = B(4,"c") 23 print(dir(obj)) ##'a', 'c', 'data'存在有这几个属性;说明子类B对父类A的构造函数进行了继承,并进行扩展自定义了自己的数据属性; 24 # obj = B(10,"c") 25 # print(dir(obj)) ## 子类B对父类A的构造函数进行了继承,进行了校验,抛出AssertionError的异常; 26 """ 27 28 """ 29 30 class C(): 31 def __init__(self,a): 32 if a>5: 33 raise AssertionError 34 self.a = a 35 self.data = None 36 37 class D(C): 38 def __init__(self,b,c): 39 super().__init__(4) ####子类对父类的构造函数进行了继承; 40 self.b = b 41 self.c = c 42 obj = D(4,"c") ##此种情况下:'a', 'b', 'c', 'data'数据属性就有4个属性了 43 print(dir(obj))
##############我是分界线>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
六、Linux
1、Linux怎么查看进程-------来自于软件测试群
2、找出linux一个日志文件的最后5行,并且包含error信息-------来自于软件测试群
3、linux怎么替换文件中某个单词-------来自于软件测试群
##############我是分界线>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
七、数据库
1、数据库表,有学生id,姓名,性别,科目,成绩,怎么找出平均分大于85的男生;
2、左连接和右连接的区别
3、数据库死锁
所谓死锁:是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。由于资源占用是互斥的,当某个进程提出申请资源后,使得有关进程在无外力协助下,永远分配不到必需的资源而无法继续运行,这就产生了一种特殊现象死锁。 一种情形,此时执行程序中两个或多个线程发生永久堵塞(等待),每个线程都在等待被其他线程占用并堵塞了的资源。例如,如果线程A锁住了记录1并等待记录2,而线程B锁住了记录2并等待记录1,这样两个线程就发生了死锁现象。计算机系统中,如果系统的资源分配策略不当,更常见的可能是程序员写的程序有错误等,则会导致进程因竞争资源不当而产生死锁的现象。锁有多种实现方式,比如意向锁,共享-排他锁,锁表,树形协议,时间戳协议等等。锁还有多种粒度,比如可以在表上加锁,也可以在记录上加锁。
产生死锁的原因主要是:
(1)系统资源不足。
(2) 进程运行推进的顺序不合适。
(3)资源分配不当等。
如果系统资源充足,进程的资源请求都能够得到满足,死锁出现的可能性就很低,否则就会因争夺有限的资源而陷入死锁。其次,进程运行推进顺序与速度不同,也可能产生死锁。
产生死锁的四个必要条件:
(1) 互斥条件:一个资源每次只能被一个进程使用。
(2) 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
(3) 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。
(4) 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
这四个条件是死锁的必要条件,只要系统发生死锁,这些条件必然成立,而只要上述条件之一不满足,就不会发生死锁。
死锁的预防和解除:
理解了死锁的原因,尤其是产生死锁的四个必要条件,就可以最大可能地避免、预防和解除死锁。所以,在系统设计、进程调度等方面注意如何不让这四个必要条件成立,如何确定资源的合理分配算法,避免进程永久占据系统资源。此外,也要防止进程在处于等待状态的情况下占用资源,在系统运行过程中,对进程发出的每一个系统能够满足的资源申请进行动态检查,并根据检查结果决定是否分配资源,若分配后系统可能发生死锁,则不予分配,否则予以分配 。因此,对资源的分配要给予合理的规划。
如何将死锁减至最少
虽然不能完全避免死锁,但可以使死锁的数量减至最少。将死锁减至最少可以增加事务的吞吐量并减少系统开销,因为只有很少的事务回滚,而回滚会取消事务执行的所有工作。由于死锁时回滚而由应用程序重新提交。
下列方法有助于最大限度地降低死锁:
(1)按同一顺序访问对象。
(2)避免事务中的用户交互。
(3)保持事务简短并在一个批处理中。
(4)使用低隔离级别。
(5)使用绑定连接。
按同一顺序访问对象
如果所有并发事务按同一顺序访问对象,则发生死锁的可能性会降低。例如,如果两个并发事务获得 Supplier 表上的锁,然后获得 Part 表上的锁,则在其中一个事务完成之前,另一个事务被阻塞在 Supplier 表上。第一个事务提交或回滚后,第二个事务继续进行。不发生死锁。将存储过程用于所有的数据修改可以标准化访问对象的顺序。
避免事务中的用户交互
避免编写包含用户交互的事务,因为运行没有用户交互的批处理的速度要远远快于用户手动响应查询的速度,例如答复应用程序请求参数的提示。例如,如果事务正在等待用户输入,而用户去吃午餐了或者甚至回家过周末了,则用户将此事务挂起使之不能完成。这样将降低系统的吞吐量,因为事务持有的任何锁只有在事务提交或回滚时才会释放。即使不出现死锁的情况,访问同一资源的其它事务也会被阻塞,等待该事务完成。
保持事务简短并在一个批处理中
在同一数据库中并发执行多个需要长时间运行的事务时通常发生死锁。事务运行时间越长,其持有排它锁或更新锁的时间也就越长,从而堵塞了其它活动并可能导致死锁。
保持事务在一个批处理中,可以最小化事务的网络通信往返量,减少完成事务可能的延迟并释放锁。
使用低隔离级别
确定事务是否能在更低的隔离级别上运行。执行提交读允许事务读取另一个事务已读取(未修改)的数据,而不必等待第一个事务完成。使用较低的隔离级别(例如提交读)而不使用较高的隔离级别(例如可串行读)可以缩短持有共享锁的时间,从而降低了锁定争夺。
使用绑定连接
使用绑定连接使同一应用程序所打开的两个或多个连接可以相互合作。次级连接所获得的任何锁可以象由主连接获得的锁那样持有,反之亦然,因此不会相互阻塞。
用存储过程查出引起死锁的进程和SQL语句
假如发生了死锁,我们怎么去检测具体发生死锁的是哪条SQL语句或存储过程?此时我们可以使用以下存储过程来检测,就可以查出引起死锁的进程和SQL语句。
与锁定有关的两个问题--死锁和阻塞
死锁
死锁是一种条件,不仅仅是在关系数据库管理系统 (RDBMS) 中发生,在任何多用户系统中都可以发生的。当两个用户(或会话)具有不同对象的锁,并且每个用户需要另一个对象的锁时,就会出现死锁。每个用户都等待另一个用户释放他的锁。当两个连接陷入死锁时,Microsoft® SQL Server? 会进行检测。其中一个连接被选作死锁牺牲品。该连接的事务回滚,同时应用程序收到错误。
如果死锁变成单个公用事件,而且它们的回滚造成过多的性能降级,那么就需要再次进行深入彻底的调查。使用跟踪标记 1204。例如,下面的命令从命令提示符启动 SQL Server,并启用跟踪标记 1204:
c:\mssql\binn\sqlservr -T1204
现在所有消息都会显示在启动 SQL Server 的控制台屏幕上和错误日志中。
使用分布式事务时,也可能发生死锁。
阻塞
任何基于锁的并发系统都不可避免地具有可能在某些情况下发生阻塞的特征。当一个连接控制了一个锁,而另一个连接需要冲突的锁类型时,将发生阻塞。其结果是强制第二个连接等待,或在第一个连接上阻塞。
在本主题中,术语"连接"是指数据库的单个登录会话。每个连接都作为系统进程 ID (SPID) 出现。尽管每一个 SPID 一般都不是单独的进程上下文,但这里常常用来指一个进程。更确切的说,每个 SPID 都是由服务器资源和数据结构(为给定客户单个连接的请求提供服务)组成。单个客户应用程序可能有一个或多个连接。就 SQL Server 而言,从单个客户机上的单个客户应用程序来的多个连接和从多个客户应用程序或多个客户机来的多个连接是没有区别的。不管是来自同一应用程序还是来自两台不同客户机上单独的应用程序,一个连接都可以阻塞另一个连接。
4、centos下启动oracle数据库
4.1、切换到oracle用户,使相关的环境变量生效。
切换到数据库用户oracle,命令:su -oracle ;使oracle用户配置文件立即生效,命令:source /home/oracle/.bash_profle,启动监听,命令:lsnrctl start
4.2、启动数据库实例。
登录SQLplus,命令:sqlplus /nolog。,以sysdba 登录数据库,命令:conn / as sysdba。启动数据库,命令:startup
5、mysql数据库索引
- 在企业信息化的过程中,数据库中表的数据量越来越大,性能会急剧下降,创建索引对于保持良好的性能非常关键
- 索引是对查询性能优化最有效的手段,能够轻易地将查询性能提高几个数量级
5.1、索引及分类
- 索引的概念
- 索引是一种特殊的文件,包含着对数据表中所有记录的引用指针,数据库索引就是为了提高表的搜索效率而对某些字段中的值建立的目录
- 索引的作用
- 索引的目的是为了加快表中记录查找和排序,设置了合适的索引之后,数据库利用各种快速定位技术,能够大大加快查询速度,这是创建索引的最主要的原因
- 索引的副作用
- 索引需要占用额外的磁盘空间;
- 索引的分类
- 普通索引
- 这是最基本的索引,而且没有唯一性的限制
- 唯一性索引
- 与普通索引类似,区别是唯一索引列的所有值智能出现一次,即必须唯一;
- 主键索引,主键索引是一种唯一性索引,但他指定为primary key“”,在数据库中为表定义主键将自动创建主键索引;
- 全文索引,索引类型为FULLTEXT,适合在进行模糊查询的时候使用,可用于在一篇文章中检索文本信息 全文索引可以在 CHAR、VARCHAR 或 TEXT 类型的列上创建,每个表只允许有一个全文索引
- 组合索引,(单列索引与多列索引),索引可以是单列上创建的索引,也可以是在多列上创建的索引如果经常同时搜索两列、多列、按两列或多列排序时,索引也很有帮助
- 普通索引
- 创建索引的原则和依据,索引可以提升数据库查询的速度,但并不是任何情况下都适合创建索引因为索引本身会消耗系统资源,在有索引的情况下,数据库会先进行索引查询,然后定位到具体的数据行,如果索引使用不当,反而会增加数据库的负担
-
表的主键、外键必须有索引;主键具有唯一性,索引值也是有唯一的,查询时可以快速定位到数据行;外键一般关联的是另一个表的主键,所以在多表查询时也可以快速定位
-
记录数超过300行的表应该有索引;如果没有索引,需要把表遍历一遍,会严重影响数据库的性能
-
经常与其他表进行连接的表,在连接字段上应该建立索引
-
唯一性太差的字段不适合建立索引,并不能提升查询速度,反而会变慢
-
更新太频繁地字段不适合创建索引;在表中进行增、删、改、查时,索引也会有响应操作产生;字段更新的过于频繁,会导致对于系统资源的过多占用
-
经常出现在 where 子句中的字段,特别是大表的字段,应该建立索引
-
索引应该建在选择性高的字段上;如果很少的字段拥有相同值,即有很多独特之,则选择性很高
-
索引应该建在小字段上,对于大的文本字段甚至超长字段,不要建索引
-
##############我是分界线>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
八、软件测试理论
1、测试用例设计:扫二维码可以领取额红包,红包可以体现到银行卡;
维码概述
二维码本身就是一个URL,只是通过QR码的形式把URL和用户身份信息转换成二进制的0和1,二维码中黑色的色素块代表1,白色的色素块代表0,我们通过相机扫码,就获取了二维码中的URL
测试用例罗列(含扫码支付的相关内容)
界面测试:
界面的按钮和文字说明是否清晰、正确;
界面的设计风格是否符合大众审美,对用户操作是否友好;
功能测试:
扫描成功是否有提示
扫描失败是否有提示
只扫描一半时,是否扫描成功
打开扫描功能一段时间后没有扫描任何二维码,是否有提示用户或自动退出扫描功能
是否支持相册获取二维码,当扫描不是二维码时提示是否正确
是否有点亮功能(考虑到环境较暗的情况)
不是该类型的二维码是否提示正确
是否支持页面之间的链接跳转,跳转是否正确
对 付款码/非收付款码/旧码/手动涂改过的扫码校验
二维码尺寸/清晰度/完整性 扫码校验
二维码扫描距离/角度/阴暗,高亮环境下校验
二维码有效期验证
失效二维码是否可以扫
二维码生成多个扫描后是否正常显示
二维码付款功能的额外测试
验证本人未输入的指纹校验
验证本人已输入的指纹校验
添加新卡支付校验
实名支付本人姓名加密校验
付款页面添加备注校验
取消支付校验
零钱不足切换银行卡支付校验
支付次数限度校验
指纹错误验证次数上线校验
支付凭证校验
输入金额,支付金额 扣款金额一致性校验
扣款后余额校验
查看账单详情校验
密码是否为密文 为空 为零 以及长度校验
密码错误提示及错误次数上限校验
输入金额上下限校验,校验
输入金额为空,为零为
账户余额不足时的校验
单笔超出上限校验
当日超出上限校验
二维码扫码信息正确特殊字符 校验,
输入金额:
密码
金额
切换指纹支付校验
支付到账时间校验
性能测试:
没网的状态下扫码校验
网络不好时切换网络校验
多人同时扫码校验
扫描后响应时间的测试
扫码跳转过程中断测试(扫码时来电/来信息/邮件等)
扫码后切换应用程序,看是否会闪退,黑屏,跳转回去是否会跳到相应的链接
兼容性测试:
使用不同品牌手机/不同手机像素/不同软件/不同软件版本扫码校验
安全性测试:
是否会泄漏用户账号新消息;
盗号和外挂考虑。
文档测试:
如有用户说明,验证用户说明的相关参数和使用指导是否正确
2、输入框可以输入字符串,后端解析,返回包含a的个数;
3、下单到支付,关注哪些测试点,设计用例,并发?
4、常规的下载按钮如何测试?

5、仅用户名和密码和一个登录按钮如何测试登录界面
一、功能测试 1、输入正确的用户名和密码,点击提交按钮,验证是否能正常登录 2、登录成功后是否跳转到正确的页面,是否在当前窗口打开 3、输入错误得到用户名或者密码,验证登录失败,并给出相应的提示信息 4、不输入用户名或者密码,或者都不输入,验证登录失败,并给出相应的提示信息 5、用户名和密码,太短和太长的处理 6、用户名和密码,有特殊字符和其他非英文的情况 7、用户名和密码前后有空格的处理 8、记住用户名和密码的功能 9、登录失败,不能记住密码 10、密码是否不是明文 11、用户登录后修改密码,是否能继续操作,退出后可以用新密码成功登录 12、同一用户同时通过不同浏览器登录,是否会导致其中一个下线
二、界面测试 1、布局是否合理,2个testbox 和一个按钮是否对齐 2、testbox 和按钮的长度和高度是否符合要求 3、界面是否好看 4、图片、颜色、字体、超链接是否都显示正确
三、性能测试 1、打开登录页面,需要几秒 2、输入正确用户名和密码,登录成功到跳转到新页面,不超过5秒 3、能支持多少用户同时登录
四、安全测试 1、登录成功后生成的Cookie,是否是httponly (否则容易被脚本盗取) 2、用户名和密码是否通过加密的方式发送给web服务器 3、用户名和密码的验证,应该是用服务器验证,而不单单是在客户端用javascript验证 4、用户名和密码的输入框,是否屏蔽SQL注入攻击 5、用户名和密码的输入框,应该禁止输入脚本(防止XSS攻击) 6、是否有错误登录的次数限制(防止暴力破解)
五、可用性测试 1、是否可以全用键盘操作,是否有快捷键 2、输入用户名和密码后,按回车键,是否可以登录成功
六、兼容性测试 1、主流的浏览器下能否显示正常 2、不同的操作系统下能否正常工作,如Windows, Mac 3、移动设备上能否正常工作,比如Iphone, Andriod 4、不同的分辨率 5、不同的浏览器大小(浏览器最大化和非最大化)
七、软件辅助性测试(是否向残疾用户提供足够的辅助功能) 1、高对比度下能否正常显示
##############我是分界线>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
九、学习措施
##############我是分界线>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
十、中间件
##############我是分界线>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
1、消息队列中的重复消费;
1.1、消息队列中存储多个消息,消费者消费完了之后一般都会做出响应,例如Kafka有一个offset概念,每次写入消息便会分配一个offset,代表消息的序号。当消费者消费完之后便会把自己消费过的消息提交一下,表示已经被消费。如果消费者已经消费但是返回offset过程中宕机了,那么下次重启之后,会再次消费已经被消费的消息。
1.2、重复消费带来的问题:例如已经插入了一条数据,再次消费会再次插入。我们需要保证一个数据重复多次时对应的数据不会被改变,不能出错。
1.3、如何解决重复消费
① 如果写入数据库就先根据主键查一下,如果已存在就不插入,update即可。
② 如果是写入Redis,那就没问题,反正每次都是set,天然幂等性。
③ 生产者每次写入消息可以加入一个全局唯一ID,类似订单ID,当消费时,现根据ID去Redis查一下之前是否被消费过,如果被消费过就不处理。
④ 基于数据库的唯一键来保证重复数据不会重复插入多条。因为有唯一键约束,再次插入重复数据只会报错。
2、中间件redis是如何进行测试的?
##############我是分界线>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
十一、协议
##############我是分界线>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
1、RPC
1.1、RPC定义
RPC的语义是远程过程调用,在一般的印象中,就是将一个服务调用封装在一个本地方法中,让调用者像使用本地方法一样调用服务,对其屏蔽实现细节。而具体的实现是通过调用方和服务方的一套约定,基于TCP长连接进行数据交互达成。
1.2、RPC特点
广义上来讲,所有本应用程序外的调用都可以归类为RPC,不管是分布式服务,第三方服务的HTTP接口,还是读写Redis的一次请求。从抽象的角度来讲,它们都一样是RPC,由于不在本地执行,都有三个特点:
- 需要事先约定调用的语义(接口语法)
- 需要网络传输
- 需要约定网络传输中的内容格式
以一次Redis调用为例,执行redis.set("rpc", 1)这个调用,其中:
set及其参数("rpc", 1),就是对调用语义的约定,由redis的API给出- RedisServer会监听一个服务端口,通过TCP传输内容,用异步事件驱动实现高并发
- 底层库会约定数据如何进行编解码,如何标识命令和参数,如何表示结果,如何表示数据的结尾等等
这三个特点都是因为调用不在本地而不得不衍生出来的问题,也因此决定了RPC的形态。所有的RPC解决方案都是在解决这三个问题,不断地在提出更加优良的解决方案,试图达到更好的性能,更低的使用成本。 本文也将围绕这三个特点来展开内容。
常规的RPC一般都是基于一个大的内部服务,进行分布式拆分,由于其语义上以本地方法的作为入口,那么天然的就更倾向于具备高性能、支持复杂参数和返回值、跨语言等特性。下图是RPC调用的过程示意图:

1.2.1、内容组织协定
Stub会负责封装命令和参数,并以特定的数据格式进行打包。其中命令、参数和返回值的需要客户端和服务端的Stub事先进行协商,双方都需要维护一份完全一样的方法及参数列表。更进一步需要知道对方如何进行压缩打包,如何压缩结构体,如何压缩Class等等,并严格按照标准进行解压缩,中途有任何一丝的差错都会的导致调用失败。所以一般情况下可能会对数据进行一定的校验,同时要协商方法、参数等错误时如何返回。 这是一个比较繁杂的过程,混合了调用语法和 内容解压缩两部分内容,可被理解为如何组织内容的问题。
1.2.2、网络传输
搞定了协议约定问题后,接下来就是要通过Runtime进行内容传输了,这又是一大难题,一般是需要通过Socket编程来实现,使用TCP或UDP来进行传输,如果是UDP可以用数据报来区分每一次请求和回复。但如果是字节流的TCP,就需要用特殊的方式来标示请求或回复的末尾,用来区分不同的请求。同时当对调用性能有要求时,可能会使用Socket的异步编程模型,消除等待中的消耗,这会引入事件机制,通过状态机来解析处理或回复请求。当出现超时、丢包等情况时还进行做重试、重传、报错等等。
拆解到协议约定和网络传输时,就会发现实现RPC调用是一件非常复杂的事情,自己实现千难万难,接下来就了解一番已有的,针对协议约定和网络传输的解决方案。
当然,在技术高度成熟的今天,已经又很多先烈将传输问题解决掉了,接下来就介绍几款常见的案例组合。
1.3、GRPC HTTP2.0 ProtoBuf
gRPC是一款RPC框架,也是本系列的主角,在性能和版本兼容上做了提升和让步:
- Protobuf进行数据编码,提高数据压缩率
- 使用HTTP2.0弥补了HTTP1.1的不足
- 同样在调用方和服务方使用协议约定文件,提供参数可选,为版本兼容留下缓冲空间
protobuf是一款用C++开发的跨语言、二进制编码的数据序列化协议,以超高的压缩率著称。它和早期的RPC方案一样,需要双方维护一个协议约束文件,以.proto结尾,使用proto命令对文件进行解析,会生成对应的Stub程序,客户端和服务端都需要保存这份Stub程序用来进行编解码。对于这种协议文件导致的升级困难问题,protobuf 3 中定义的字段默认都是可选的(可以不传),在接口升级时,部分客户端不需要升级自己的Stub程序。

浙公网安备 33010602011771号