Python接口测试实战之搭建自动化测试框架

🍅 视频学习:文末有免费的配套视频可观看

🍅 点击文末小卡片,免费获取软件测试全套资料,资料在手,涨薪更快

一.数据分离:从Excel中读取数据

之前的用例中,数据直接写在代码文件里,不利于修改和构造数据,这里我们使用Excel保存测试数据,实现代码和数据的分离,新建Excel文件test_user_data.xlsx包含两个工作簿TestUserLogin和TestUserReg,并复制到项目根目录下。

图片

更新: excel表格中,增加一个headers列,内容为json格式, 如下

图片

二.Excel读取方法

Python我们使用三方库xird来读取Excel,使用pip install xlrd安装xlrd。

import xlrdwb = xlrd.open_workbook("test_user_data.xlsx")  # 打开excel
sh = wb.sheet_by_name("TestUserLogin")  # 按工作簿名定位工作表
print(sh.nrows)  # 有效数据行数
print(sh.ncols)  # 有效数据列数
print(sh.cell(0, 0).value)  # 输出第一行第一列的值`case_name`
print(sh.row_values(0))  # 输出第1行的所有值(列表格式)# 将数据和标题组装成字典,使数据更清晰
print(dict(zip(sh.row_values(0), sh.row_values(1))))# 遍历excel,打印所有的数据
for i in range(sh.nrows):print(sh.row_values(i))

输出结果

3
5
case_name
['case_name', 'url', 'method', 'data', 'expect_res']
{'case_name': 'test_user_login_normal', 'url': 'http://115.28.108.130:5000/api/user/login/', 'method': 'POST', 'data': '{"name": "张三","password":"123456"}', 'expect_res': '<h1>登录成功</h1>'}
['case_name', 'url', 'method', 'data', 'expect_res']
['test_user_login_normal', 'http://115.28.108.130:5000/api/user/login/', 'POST', '{"name": "张三","password":"123456"}', '<h1>登录成功</h1>']
['test_user_login_password_wrong', 'http://115.28.108.130:5000/api/user/login/', 'POST', '{"name": "张三","password":"1234567"}', '<h1>失败,用户不存在</h1>']

三.封装读取excel操作

1.新建read_excel.py图片
我们的目的是获取某条用例的数据,需要3个参数,excel数据文件名data_file,工作簿名sheet,用例名case_name。如果我们只封装一个函数,每次调用(每条用例)都要打开一次excel并遍历一次,这样效率比较低,我们可以拆分成两个函数,一个函数excel_to_list(data_file, sheet),一次获取一个工作表的所有数据,另一个函数get_test_data(data_list, case_name)从所有数据中去查找到该条用例的数据。

import xlrddef excel_to_list(data_file, sheet):data_list = []  # 新建个空列表,来乘装所有的数据wb = xlrd.open_workbook(data_file)  # 打开excelsh = wb.sheet_by_name(sheet)  # 获取工作簿header = sh.row_values(0)  # 获取标题行数据for i in range(1, sh.nrows):  # 跳过标题行,从第二行开始取数据d = dict(zip(header, sh.row_values(i)))  # 将标题和每行数据组装成字典data_list.append(d)return data_list  # 列表嵌套字典格式,每个元素是一个字典def get_test_data(data_list, case_name):for case_data in data_list:if case_name == case_data['case_name']:  # 如果字典数据中case_name与参数一致return case_data# 如果查询不到会返回Noneif __name__ == '__main__':   # 测试一下自己的代码data_list = excel_to_list("test_user_data.xlsx", "TestUserLogin")  # 读取excel,TestUserLogin工作簿的所有数据case_data = get_test_data(data_list, 'test_user_login_normal')  # 查找用例'test_user_login_normal'的数据print(case_data)

输出结果

{'case_name': 'test_user_login_normal', 'url': 'http://115.28.108.130:5000/api/user/login/', 'method': 'POST', 'data': '{"name": "张三","password":"123456"}', 'expect_res': '<h1>登录成功</h1>'}

2.用例中使用方法(test_user_login.py)

import unittest
import requests
from read_excel import *  # 导入read_excel中的方法
import json  # 用来转化excel中的json字符串为字典class TestUserLogin(unittest.TestCase):@classmethoddef setUpClass(cls):   # 整个测试类只执行一次cls.data_list = excel_to_list("test_user_data.xlsx", "TestUserLogin")  # 读取该测试类所有用例数据# cls.data_list 同 self.data_list 都是该类的公共属性def test_user_login_normal(self):case_data = get_test_data(self.data_list, 'test_user_login_normal')   # 从数据列表中查找到该用例数据if not case_data:   # 有可能为Noneprint("用例数据不存在")url = case_data.get('url')   # 从字典中取数据,excel中的标题也必须是小写urldata = case_data.get('data')  # 注意字符串格式,需要用json.loads()转化为字典格式expect_res = case_data.get('expect_res')  # 期望数据res = requests.post(url=url, data=json.loads(data))  # 表单请求,数据转为字典格式self.assertEqual(res.text, expect_res)  # 改为assertEqual断言if __name__ == '__main__':   # 非必要,用于测试我们的代码unittest.main(verbosity=2)

3.用例中使用方法(test_user_reg.py)

import unittest
import requests
from db import *
from read_excel import *
import jsonclass TestUserReg(unittest.TestCase):@classmethoddef setUpClass(cls):cls.data_list = excel_to_list("test_user_data.xlsx", "TestUserReg")  # 读取TestUserReg工作簿的所有数据def test_user_reg_normal(self):case_data = get_test_data(self.data_list, 'test_user_reg_normal')if not case_data:print("用例数据不存在")url = case_data.get('url')data = json.loads(case_data.get('data'))  # 转为字典,需要取里面的name进行数据库检查expect_res = json.loads(case_data.get('expect_res'))  # 转为字典,断言时直接断言两个字典是否相等name = data.get("name")  # 范冰冰# 环境检查if check_user(name):del_user(name)# 发送请求res = requests.post(url=url, json=data)  # 用data=data 传字符串也可以# 响应断言(整体断言)self.assertDictEqual(res.json(), expect_res)# 数据库断言self.assertTrue(check_user(name))# 环境清理(由于注册接口向数据库写入了用户信息)del_user(name)if __name__ == '__main__':    # 非必要,用于测试我们的代码unittest.main(verbosity=2)  

四.增加日志(log)功能

1.新建config.py文件

import logginglogging.basicConfig(level=logging.DEBUG,  # log levelformat='[%(asctime)s] %(levelname)s [%(funcName)s: %(filename)s, %(lineno)d] %(message)s',  # log格式datefmt='%Y-%m-%d %H:%M:%S',  # 日期格式filename='log.txt',  # 日志输出文件filemode='a')  # 追加模式if __name__ == '__main__':logging.info("hello")

运行后在当前目录下生成log.txt,内容如下

[2018-09-11 18:08:17] INFO [<module>: config.py, 38] hello

2.日志别级(Log Level)

CRITICAL: 用于输出严重错误信息
ERROR: 用于输出错误信息
WARNING: 用于输出警示信息
INFO: 用于输出一些提升信息
DEBUG: 用于输出一些调试信息

3.日志优先级

CRITICAL > ERROR > WARNING > INFO > DEBUG

指定level = logging.DEBUG所有等级大于等于DEBUG的信息都会输出;若指定level = logging.ERROR WARNING,INFO,DEBUG小于设置级别的信息不会输出。

4.日志格式说明

%(levelno)s: 打印日志级别的数值

%(levelname)s: 打印日志级别名称

%(pathname)s: 打印当前执行程序的路径,其实就是sys.argv[0]

%(filename)s: 打印当前执行程序名

%(funcName)s: 打印日志的当前函数

%(lineno)d: 打印日志的当前行号

%(asctime)s: 打印日志的时间

%(thread)d: 打印线程ID

%(threadName)s: 打印线程名称

%(process)d: 打印进程ID

%(message)s: 打印日志信息

5.日志在项目中的使用

db.py

import pymysql
from config import *# 封装数据库查询操作
def query_db(sql):conn = get_db_conn()cur = conn.cursor()  logging.debug(sql)    # 输出执行的sqlcur.execute(sql)conn.commit()result = cur.fetchall() logging.debug(result)  # 输出查询结果cur.close() conn.close() return result # 封装更改数据库操作
def change_db(sql):conn = get_db_conn() cur = conn.cursor()logging.debug(sql)  # 输出执行的sqltry:cur.execute(sql) conn.commit() except Exception as e:conn.rollback() logging.error(str(e))  # 输出错误信息finally:cur.close() conn.close()

用例

import unittest
import requests
from read_excel import *  # 导入read_excel中的方法
import json  # 用来转化excel中的json字符串为字典
from config import *class TestUserLogin(unittest.TestCase):@classmethoddef setUpClass(cls):   # 整个测试类只执行一次cls.data_list = excel_to_list("test_user_data.xlsx", "TestUserLogin")  # 读取该测试类所有用例数据# cls.data_list 同 self.data_list 都是该类的公共属性def test_user_login_normal(self):case_data = get_test_data(self.data_list, 'test_user_login_normal')   # 从数据列表中查找到该用例数据if not case_data:   # 有可能为Nonelogging.error("用例数据不存在")url = case_data.get('url')   # excel中的标题也必须是小写urldata = case_data.get('data')  # 注意字符串格式,需要用json.loads()转化为字典格式expect_res = case_data.get('expect_res')  # 期望数据res = requests.post(url=url, data=json.loads(data))  # 表单请求,数据转为字典格式logging.info("测试用例:{}".format('test_user_login_normal'))logging.info("url:{}".format(url))logging.info("请求参数:{}".format(data))logging.info("期望结果:{}".format(expect_res))logging.info("实际结果:{}".format(res.text)self.assertEqual(res.text, expect_res)  # 断言if __name__ == '__main__':unittest.main(verbosity=2)

输出结果

[2018-09-13 10:34:49] INFO [log_case_info: case_log.py, 8] 测试用例:test_user_login_normal
[2018-09-13 10:34:49] INFO [log_case_info: case_log.py, 9] url:http://115.28.108.130:5000/api/user/login/
[2018-09-13 10:34:49] INFO [log_case_info: case_log.py, 10] 请求参数:{"name": "张三","password":"123456"}
[2018-09-13 10:34:49] INFO [log_case_info: case_log.py, 11] 期望结果:<h1>登录成功</h1>
[2018-09-13 10:34:49] INFO [log_case_info: case_log.py, 12] 实际结果:<h1>登录成功</h1>

因为每个用例都要输出很多log信息,我们封装一个case_log的函数

from config import *
import jsondef log_case_info(case_name, url, data, expect_res, res_text): if isinstance(data,dict):data = json.dumps(data, ensure_ascii=False)  # 如果data是字典格式,转化为字符串logging.info("测试用例:{}".format(case_name))logging.info("url:{}".format(url))logging.info("请求参数:{}".format(data))logging.info("期望结果:{}".format(expect_res))logging.info("实际结果:{}".format(res_text)

简化后的用例log输出

import unittest
import requests
from read_excel import *  
import json
from config import *
from case_log import log_case_info  # 导入方法class TestUserLogin(unittest.TestCase):@classmethoddef setUpClass(cls):  cls.data_list = excel_to_list("test_user_data.xlsx", "TestUserLogin") def test_user_login_normal(self):case_data = get_test_data(self.data_list, 'test_user_login_normal') if not case_data: logging.error("用例数据不存在")url = case_data.get('url')  data = case_data.get('data') expect_res = case_data.get('expect_res')res = requests.post(url=url, data=json.loads(data))log_case_info('test_user_login_normal', url, data, expect_res, res_text)  # 输出用例log信息self.assertEqual(res.text, expect_res)  if __name__ == '__main__':unittest.main(verbosity=2)

五.发送邮件

在生成报告后我们希望框架能自动把报告发送到我们的邮箱中。和outlook,foxmail等邮件客户端一样,Python中发送邮件需要通过Email的smtp服务发送。

1.首先需要确认用来发送邮件的邮箱是否启用了smtp服务;

2.编写邮件内容(Email邮件需要专门的MIME格式);

3.组装Email头(发件人,收件人,主题);

4.连接smtp服务器并发送邮件;

import smtplib  # 用于建立smtp连接
from email.mime.text import MIMEText  # 邮件需要专门的MIME格式# 1. 编写邮件内容(Email邮件需要专门的MIME格式)
msg = MIMEText('this is a test email', 'plain', 'utf-8')  # plain指普通文本格式邮件内容# 2. 组装Email头(发件人,收件人,主题)
msg['From'] = 'test_results@sina.com'  # 发件人
msg['To'] = '2375247815@qq.com'  # 收件人
msg['Subject'] = 'Api Test Report'  # 邮件主题# 3. 连接smtp服务器并发送邮件
smtp = smtplib.SMTP_SSL('smtp.sina.com')  # smtp服务器地址 使用SSL模式
smtp.login('自己的邮箱地址', '自己的邮箱密码')  # 用户名和密码
smtp.sendmail("接收邮件地址1", "接收邮件地址2", msg.as_string())
smtp.quit()

5.中文邮件主题、HTML邮件内容,及附件

import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart  # 混合MIME格式,支持上传附件
from email.header import Header  # 用于使用中文邮件主题# 1.  编写邮件内容
with open('report.html', encoding='utf-8') as f:  # 打开html报告email_body = f.read()  # 读取报告内容msg = MIMEMultipart()  # 混合MIME格式
msg.attach(MIMEText(email_body, 'html', 'utf-8'))  # 添加html格式邮件正文(会丢失css格式)# 2. 组装Email头(发件人,收件人,主题)
msg['From'] = 'test_results@sina.com'  # 发件人
msg['To'] = '2375247815@qq.com'  # 收件人
msg['Subject'] = Header('接口测试报告', 'utf-8')  # 中文邮件主题,指定utf-8编码# 3. 构造附件1,传送当前目录下的 test.txt 文件
att1 = MIMEText(open('report.html', 'rb').read(), 'base64', 'utf-8')  # 二进制格式打开
att1["Content-Type"] = 'application/octet-stream'
att1["Content-Disposition"] = 'attachment; filename="report.html"'  # filename为邮件中附件显示的名字
msg.attach(att1)# 4. 连接smtp服务器并发送邮件
smtp = smtplib.SMTP_SSL('smtp.sina.com')  # smtp服务器地址 使用SSL模式
smtp.login('test_results@sina.com', 'hanzhichao123')  # 用户名和密码
smtp.sendmail("test_results@sina.com", "2375247815@qq.com", msg.as_string())
smtp.sendmail("test_results@sina.com", "superhin@126.com", msg.as_string())  # 发送给另一个邮箱
smtp.quit()

6.封装发送邮件方法

import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart  # 混合MIME格式,支持上传附件
from email.header import Header  # 用于使用中文邮件主题
from config import *def send_email(report_file):msg = MIMEMultipart()  # 混合MIME格式msg.attach(MIMEText(open(report_file, encoding='utf-8').read(), 'html', 'utf-8'))  # 添加html格式邮件正文(会丢失css格式)msg['From'] = 'test_results@sina.com'  # 发件人msg['To'] = '2375247815@qq.com'  # 收件人msg['Subject'] = Header('接口测试报告', 'utf-8')  # 中文邮件主题,指定utf-8编码att1 = MIMEText(open(report_file, 'rb').read(), 'base64', 'utf-8')  # 二进制格式打开att1["Content-Type"] = 'application/octet-stream'att1["Content-Disposition"] = 'attachment; filename="report.html"'  # filename为邮件中附件显示的名字msg.attach(att1)try:smtp = smtplib.SMTP_SSL('smtp.sina.com')  # smtp服务器地址 使用SSL模式smtp.login('test_results@sina.com', 'hanzhichao123')  # 用户名和密码smtp.sendmail("test_results@sina.com", "2375247815@qq.com", msg.as_string())smtp.sendmail("test_results@sina.com", "superhin@126.com", msg.as_string())  # 发送给另一个邮箱logging.info("邮件发送完成!")except Exception as e:logging.error(str(e))finally:smtp.quit()

7.run_all.py中结束后发送邮件

import unittest
from HTMLTestReportCN import HTMLTestRunner
from config import *
from send_email import send_emaillogging.info("====================== 测试开始 =======================")
suite = unittest.defaultTestLoader.discover("./")with open("report.html", 'wb') as f:  # 改为with open 格式HTMLTestRunner(stream=f, title="Api Test", description="测试描述", tester="卡卡").run(suite)send_email('report.html')  # 发送邮件
logging.info("======================= 测试结束 =======================")

图片

六.使用配置文件

和项目的log配置一样,数据库服务器地址,邮件服务地址我们一般放到配置文件config.py中。

import logging
import os# 项目路径
prj_path = os.path.dirname(os.path.abspath(__file__))  # 当前文件的绝对路径的上一级,__file__指当前文件data_path = prj_path  # 数据目录,暂时在项目目录下
test_path = prj_path  # 用例目录,暂时在项目目录下log_file = os.path.join(prj_path, 'log.txt')  # 也可以每天生成新的日志文件
report_file = os.path.join(prj_path, 'report.html')  # 也可以每次生成新的报告# log配置
logging.basicConfig(level=logging.DEBUG,  # log levelformat='[%(asctime)s] %(levelname)s [%(funcName)s: %(filename)s, %(lineno)d] %(message)s',  # log格式datefmt='%Y-%m-%d %H:%M:%S',  # 日期格式filename=log_file,  # 日志输出文件filemode='a')  # 追加模式# 数据库配置
db_host = '127.0.0.1'   # 自己的服务器地址
db_port = 3306
db_user = 'test'
db_passwd = '123456'
db = 'api_test'# 邮件配置
smtp_server = 'smtp.sina.com'
smtp_user = 'test_results@sina.com'
smtp_password = 'hanzhichao123'sender = smtp_user  # 发件人
receiver = '2375247815@qq.com'  # 收件人
subject = '接口测试报告'  # 邮件主题

修改db.py,send_email.py,run_all.py等对配置文件的引用

db.py

import pymysql
from config import *# 获取连接方法
def get_db_conn():conn = pymysql.connect(host=db_host,   # 从配置文件中读取port=db_port,user=db_user,passwd=db_passwd,  # passwd 不是 passworddb=db,charset='utf8')  # 如果查询有中文,需要指定测试集编码

send_email.py

import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.header import Header 
from config import *def send_email(report_file):msg = MIMEMultipart()msg.attach(MIMEText(open(report_file, encoding='utf-8').read(), 'html', 'utf-8'))msg['From'] = 'test_results@sina.com'msg['To'] = '2375247815@qq.com'msg['Subject'] = Header(subject, 'utf-8')  # 从配置文件中读取att1 = MIMEText(open(report_file, 'rb').read(), 'base64', 'utf-8')  # 从配置文件中读取att1["Content-Type"] = 'application/octet-stream'att1["Content-Disposition"] = 'attachment; filename="{}"'.format(report_file)  # 参数化一下report_filemsg.attach(att1)try:smtp = smtplib.SMTP_SSL(smtp_server)  # 从配置文件中读取smtp.login(smtp_user, smtp_password)  # 从配置文件中读取smtp.sendmail(sender, receiver, msg.as_string())logging.info("邮件发送完成!")except Exception as e:logging.error(str(e))finally:smtp.quit()

run_all.py

import unittest
from HTMLTestReportCN import HTMLTestRunner
from config import *
from send_email import send_emaillogging.info("==================== 测试开始 =======================")
suite = unittest.defaultTestLoader.discover(test_path)  # 从配置文件中读取用例路径with open(report_file, 'wb') as f:  # 从配置文件中读取HTMLTestRunner(stream=f, title="Api Test", description="测试描述").run(suite)send_email(report_file)  # 从配置文件中读取
logging.info("==================== 测试结束 =======================")

七.框架整理

图片
当前所有文件(配置文件,公共方法,测试用例,数据,报告,log)都在项目根目录下,随着用例的增加和功能的补充,文件会越来越多,不便于维护和管理,因此我们要建立不同的文件夹,对文件进行分类组织。

1.在项目中新建以下文件夹

config: 存放项目配置文件

data: 存放用例数据文件

lib: 公共方法库

log: 存放日志文件

report: 存放报告文件

test: 存放测试用例

user: 存放user模块用例(模块下要有__init__.py,这样里面的用例才能读取到)

2.代码目录整理

将配置文件config.py移动到config目录下

将数据文件test_user_data.xlsx移动到data目录下

将公共方法db.py,send_email.py,case_log.py,read_excel.py,HTMLTestReportCN.py移动到lib目录下

将测试用例test_user_login.py,test_user_reg.py移动到test/user目录下,保留run_all.py在项目根目录下,如图
图片
3.修改配置文件(config/config.py)

import logging
import os# 项目路径
prj_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))  # 当前文件的上一级的上一级目录(增加一级)data_path = os.path.join(prj_path, 'data')  # 数据目录
test_path = os.path.join(prj_path, 'test')   # 用例目录log_file = os.path.join(prj_path, 'log', 'log.txt')  # 更改路径到log目录下
report_file = os.path.join(prj_path, 'report', 'report.html')  # 更改路径到report目录下

4.修改对配置文件及公共方法的引用 为避免相对路径导包出错的问题,我们统一把导包搜索路径(sys.path)提升到项目根目录下,如lib/db.py

db.py

import pymysql
import sys
sys.path.append('..')  # 提升一级到项目更目录下
from config.config import *  # 从项目根目录下导入

test_user_login.py

import unittest
import requests
import json
import os  # 增加了一个os,需要用来组装路径
import sys
sys.path.append("../..")  # 提升2级到项目根目录下
from config.config import *  # 从项目路径下导入
from lib.read_excel import *  # 从项目路径下导入
from lib.case_log import log_case_info  # 从项目路径下导入class TestUserLogin(unittest.TestCase):@classmethoddef setUpClass(cls):   # 整个测试类只执行一次cls.data_list = excel_to_list(os.path.join(data_path, "test_user_data.xlsx"),"TestUserLogin")  # 增加data路径

run_all.py

import unittest
from lib.HTMLTestReportCN import HTMLTestRunner  # 修改导入路径
from config.config import *  # 修改导入路径
from lib.send_email import send_email  # 修改导入路径logging.info("================================== 测试开始 ==================================")
suite = unittest.defaultTestLoader.discover(test_path)  # 从配置文件中读取with open(report_file, 'wb') as f:  # 从配置文件中读取HTMLTestRunner(stream=f, title="Api Test", description="测试描述").run(suite)send_email(report_file)  # 从配置文件中读取
logging.info("================================== 测试结束 ==================================")
如果同一文件夹下的方法相互引用(如lib/read_excel.py假如需要引用lib/db.py),也需要采用这种从项目路径下导入的方式;run_all.py直接在项目路径下,不需要提升sys.path,无需相对导入我们自己的包时,如read_excel.py,不需要提升

5.运行run_all.py,根据log和报告调试代码,直至所有用例全部通过

同时,在这我为大家准备了一份软件测试视频教程(含面试、接口、自动化、性能测试等),就在下方,需要的可以直接去观看。

【2024最新版】Python自动化测试15天从入门到精通,10个项目实战,允许白嫖。。。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/30196.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++初学者指南第一步---7.控制流(基础)

C初学者指南第一步—7.控制流&#xff08;基础&#xff09; 文章目录 C初学者指南第一步---7.控制流&#xff08;基础&#xff09;1.术语:表达式/语句Expressions表达式Statements语句 2.条件分支3.Switching(切换):基于值的分支4.三元条件运算符5.循环迭代基于范围的循环   C…

Java基础 - 练习(三)打印空心菱形

Java基础练习 打印空心菱形&#xff0c;先上代码&#xff1a; public static void diamond() {//控制行数for (int i 1; i < 4; i) {//空格的个数for (int k 1; k < 4 - i; k) {System.out.print(" ");}//控制星星个数的时候和行有关for (int j 1; j <…

linux配置Vnc Server给Windows连接

1. linux 安装必要vnc server和桌面组件 sudo apt -y install tightvncserversudo apt install xfce4 xfce4-goodies2. linux 配置vncserver密码 #bash vncserver参考: https://cn.linux-console.net/?p21846#google_vignette 3. 将启动桌面命令写入.vnc/xstartup # .vnc/x…

TIME_WAIT的危害

前言 该文章主要讨论下TIME_WAIT的存在意义和潜在危害&#xff0c;以及解决措施。 具体内容 首先看一下下面这幅图 这幅图来自《TCP IP详解卷1&#xff1a;协议 原书第2版中文》TCP状态变迁图。 TIME_WAIT存在意义 可靠的终止TCP连接。 保证让迟来的TCP报文有足够的时间被…

【YOLOv10改进[注意力]】添加注意力CascadedGroupAttention(2023) + 含全部代码和详细修改方式 + 手撕结构图 + 全网首发

本文将进行使用注意力CascadedGroupAttention的实践,助力YOLOv10目标检测效果的实践,文中含全部代码、详细修改方式以及手撕结构图。助您轻松理解改进的方法。 改进前和改进后的参数对比: 目录 一 CascadedGroupAttention 二 使用注意力CascadedGroupAttention 1 整体…

KVB投资安全小知识:你知道情绪面、技术面与基本面的关系吗?

摘要&#xff1a;当涉及到金融市场分析时&#xff0c;情绪面、技术面和基本面是三个重要的方面。它们相互交织&#xff0c;共同影响着市场的走势和投资者的决策。下面我来详细解释它们之间的关系。 情绪面的影响 情绪面指的是投资者情绪和市场情绪&#xff0c;它反映了市场参与…

springboot+vue+mybatis酒店管理系统+PPT+论文+讲解+售后

基于Spring框架的小型宾馆旅客信息管理系统采用B/S结构、java开发语言、以及Mysql数据库等技术。系统主要分为管理员和用户二部分&#xff0c;管理员&#xff1a;首页、个人中心、用户管理、客房类型管理、客房信息管理、客房预订管理、入住登记管理、退房评价管理、系统管理&a…

Qt6之调色板QPaletee

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言Qt之调色板 QPalette什么是 QPalette&#xff1f;QPalette 的作用如何使用 QPaletteQPalette可设置的部分常规操作示例代码和运行效果图 总结 前言 在开发 Qt …

【C语言】C语言入门宝典:核心概念全解析

. C语言专栏 | C专栏 &#x1f449; 个人主页 &#x1f448; 前言 此篇文章我们主要是宏观的了解一下什么是C语言&#xff0c;C语言里面有那些知识点&#xff0c;所有的知识点我们此篇只是以入门为主&#xff0c;点到为止&#xff0c;简单易懂&#xff0c;后期的文章会一 一详…

Servlet实践操作

Servlet运行原理 Tomcat 的代码内置了 main 方法&#xff0c;当我们启动 Tomcat 的时候&#xff0c;就是从 Tomcat 的 main 方法开始执行的 被 WebServlet 注解修饰的类会在 Tomcat 启动的时候就被获取并集中管理 Tomcat 通过反射这样的语法机制来创建被 WebServlet 注解修饰…

PCB设计隐藏的陷进

1、BGA芯片的开窗和过油设计。 加工工艺中&#xff0c;范式过孔都需要盖油设计&#xff0c;实心焊盘需要开窗设计&#xff0c;坚决不能盖油。 2、通孔设计的互联连通性 比如H3芯片的wifi设计&#xff0c;实际上是没有联通的&#xff0c;虽然四层板的中间层有焊盘&#xff0c;但…

【FreeRTOS】估算栈的大小

参考《FreeRTOS入门与工程实践(基于DshanMCU-103).pdf》 目录 估算栈的大小回顾简介计算说明估计函数用到的栈有多大合计 估算栈的大小 回顾 上一篇文章链接&#xff1a;http://t.csdnimg.cn/Cc8b4 传送门: 上一篇文章 上一篇文章创建的三个任务 /* 创建任务&#xff1a;声 *…

LabVIEW开发为何仿制(致敬)经典成熟软件

​仿制&#xff08;致敬&#xff09;成熟软件进行LabVIEW开发更方便&#xff0c;因其提供了稳定的架构和结构、优化的用户体验和界面设计、技术规范和标准、稳定性和可靠性。结合用户手册和现有操作进行仿制&#xff0c;就像小米致敬保时捷一样&#xff0c;可以提高开发效率、降…

vivado SITE

描述 SITE是一个设备对象&#xff0c;表示许多不同类型的逻辑资源之一 可在目标Xilinx FPGA上获得。 SITE包括SLICE/CLB&#xff0c;它们是基本逻辑元件&#xff08;BEL&#xff09;的集合&#xff0c;如 查找表&#xff08;LUT&#xff09;、触发器、多路复用器&#xff0c;携…

QT/基于TCP的服务端实现

代码 widget.cpp #include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget),p(new QTcpServer(this))//给服务器指针申请空间 {ui->setupUi(this); }Widget::~Widget() {delete ui; }void W…

实测:三款垃圾CPU推理Llama3 8B

经常有一些朋友问我本地运行大模型的电脑需要什么样的配置。其实一些常用大模型的运行需要的硬件并不像我们想象的那样高不可攀。不要被那些复杂的技术术语所吓倒&#xff0c;关键在于亲自动手尝试。 “不试&#xff0c;怎么知道呢&#xff1f;” 这句话道出了真理。今天&#…

【Linux】基础IO_1

文章目录 六、基础IO1. C语言的文件接口2. 系统文件I/O 未完待续 六、基础IO 1. C语言的文件接口 我们知道 文件 文件内容 文件属性 。即使是一个空文件&#xff0c;仍然会在磁盘中占据空间。那打开文件是什么意思呢&#xff1f;其实文件打开的意思就是&#xff1a;将文件从…

力扣每日一题 6/19 排序+动态规划

博客主页&#xff1a;誓则盟约系列专栏&#xff1a;IT竞赛 专栏关注博主&#xff0c;后期持续更新系列文章如果有错误感谢请大家批评指出&#xff0c;及时修改感谢大家点赞&#x1f44d;收藏⭐评论✍ 2713.矩阵中严格递增的单元格数【困难】 题目&#xff1a; 给你一个下标从…

【学习DayNa】信息系统开发整理

✍&#x1f3fb;记录学习过程中的输出&#xff0c;坚持每天学习一点点~ ❤️希望能给大家提供帮助~欢迎点赞&#x1f44d;&#x1f3fb;收藏⭐评论✍&#x1f3fb;指点&#x1f64f; 结构化方法 结构是指系统内各个组成要素之间的相互联系、相互作用的框架。结构化开发方法就是…

shell中的流程控制

条件判断在流程控制中的重要性 有了条件判断才能进行if判断即分支流程&#xff0c;才能进行case的多分支流程&#xff0c;才能进行for循环和while循环。 单分支流程判断 如上图所示&#xff0c;在shell编程中常使用英文状态下的分号来在Linux控制台一次性执行多条命令&#x…