当前位置: 首页 > news >正文

使用Nginx OpenResty与Redis实现高效IP黑白名单管理

1、引言

在当今数字化时代,网络安全已成为企业和个人用户关注的焦点。IP黑白名单作为一种有效的网络安全策略,允许我们精确控制对Web资源的访问权限。通过白名单,我们可以确保只有可信的IP地址能够访问敏感资源;而黑名单则可以阻止恶意IP的访问,从而减少安全风险。

选择Nginx OpenResty与Redis作为实现黑白名单的解决方案,是基于以下几个原因:

  • 高性能:Nginx以其轻量级和高性能著称,适合处理高并发请求。
  • 灵活性:OpenResty通过集成Lua脚本,提供了强大的定制能力。
  • 可扩展性:Redis作为一个内存数据结构存储,支持数据的快速读写,适合实现动态的黑白名单管理。

2、简介

1、什么是OpenResty?

OpenResty是一个基于Nginx的全功能Web平台,它集成了一系列精心设计的Lua库、第三方模块和一个基于LuaJIT的轻量级Web框架。OpenResty的核心是Nginx,但它通过Lua语言扩展了Nginx的功能,使其能够构建能够处理超高并发的动态Web应用。

2、OpenResty与Nginx的关系

OpenResty是在Nginx的基础上构建的,它保留了Nginx的所有功能,并通过Lua语言扩展了其能力。这意味着你可以使用OpenResty来实现Nginx的所有功能,同时还能够利用Lua脚本来实现更复杂的业务逻辑。

3、环境安装

1、环境版本

centos 7 
redis 7.2
nginx version: openresty/1.25.3.1

2、环境安装

1、添加OpenResty仓库

# 由于公共库中找不到openresty,所以需要添加openresty的源仓库
yum-config-manager --add-repo https://openresty.org/package/centos/openresty.repo# 注意,如果上面命令提示不存在,那就先安装一下
yum install -y yum-utils
  1. 安装OpenResty
# 安装openresty
yum install -y openresty
# 安装OpenResty管理工具,帮助我们安装第三方的Lua模块
yum install -y openresty-opm

3、目录结构
​ 默认安装在/usr/local/openresty
在这里插入图片描述
看到里面有一个nginx目录,进去可以看到跟我们平常用的nginx是一模一样的,OpenResty就是在Nginx基础上集成了一些Lua模块

到这里我们就安装好了

4、启动和运行
OpenResty底层是基于Nginx的,查看OpenResty目录的nginx目录,结构与windows中安装的nginx基本一致

5、安装配置redis

sudo yum install redis -y

Redis配置主要包括设置持久化选项、网络配置、安全性设置等。以下是一个基本的配置示例:

# redis.conf
port 6379
bind 127.0.0.1
protected-mode yes
requirepass "yourpassword"

4、白名单实现

在这里插入图片描述

图例说明:

  • 客户端:发送HTTP请求的用户或应用。
  • Nginx (OpenResty):处理和管理HTTP请求,执行Lua脚本进行访问控制。
  • Lua脚本:在Nginx中运行,负责从Redis获取白名单并进行IP检查。
  • Redis:存储白名单数据,用于快速查询。
交互流程:
  1. 客户端发送请求到Nginx。
  2. Nginx调用Lua脚本进行访问控制。
  3. Lua脚本连接Redis,并查询IP是否在白名单中。
  4. Lua脚本返回查询结果给Nginx。
  5. Nginx根据结果决定是否允许请求,并返回响应给客户端

定义白名单的作用与重要性

白名单是一种安全策略,用于定义一组被信任的IP地址或实体,它们被允许访问特定的资源或服务。在Web应用中,白名单的作用尤为显著:

  • 安全性增强:限制访问权限,仅允许特定的IP地址访问敏感资源。
  • 防止滥用:减少恶意用户或爬虫对服务的滥用。
  • 流量管理:通过控制访问源,更有效地管理网络流量。

通过OpenResty Lua脚本实现白名单逻辑

在OpenResty中,我们可以使用Lua脚本来实现白名单逻辑。Lua脚本可以在Nginx的配置文件中直接编写,或者存储在外部文件中,并在配置文件中引用。

Lua脚本实现步骤:

  1. 定义白名单:在Redis中存储白名单IP地址。
  2. 访问控制:在Nginx配置中使用access_by_lua_blockaccess_by_lua_file指令调用Lua脚本。
  3. 脚本逻辑:检查请求的IP地址是否在白名单中,如果不在,则拒绝访问。

案例演示

jenkins.ownit.top.conf
这个是nginx的配置文件
最主要内容:access_by_lua_file /opt/nginx/lua_script/white.lua;

upstream jenkins-uat {server 192.168.102.20:91;
}
server {listen       80;server_name  jenkins.ownit.top;#白名单 或者 黑名单#include /opt/nginx/whitelist/corporation.conf;location / {rewrite ^/(.*)$ https://$host/$1 permanent;}access_log  /www/wwwlogs/dns.ownit.top.log;error_log  /www/wwwlogs/dns.ownit.top.error.log;}
server {listen       443 ssl;server_name  jenkins.ownit.top;#白名单 或者 黑名单#include /opt/nginx/whitelist/corporation.conf;#ssl                   on;ssl_certificate      /opt/nginx/ssl/ownit.top.crt;ssl_certificate_key  /opt/nginx/ssl/ownit.top.key;include ssl.conf;location / {access_by_lua_file /opt/nginx/lua_script/white.lua; # nginx的lua脚本proxy_pass  http://jenkins-uat;include https_proxy.conf;}access_log  /www/wwwlogs/dns.ownit.top.log;error_log  /www/wwwlogs/dns.ownit.top.error.log;}

white.lua文件

通过使用Lua脚本,在接收到HTTP请求时检查请求的IP地址是否在Redis存储的白名单中。如果IP不在白名单中,则拒绝访问。

思路

  1. 获取客户端IP和请求路径:在Lua脚本中获取客户端的IP地址和请求路径。
  2. 连接Redis:使用resty.redis模块连接Redis数据库。
  3. 权限校验:对连接的Redis进行认证。
  4. 检查IP是否在白名单中:从Redis中检查IP是否存在于白名单集合中。
  5. 返回结果:如果IP在白名单中,允许访问;否则,返回403 Forbidden状态码,拒绝访问。
  6. 释放Redis连接:将Redis连接返回到连接池中,以便复用。
-- 获取客户端IP和请求路径
local client_ip = ngx.var.remote_addr
local path = ngx.var.uri-- Redis相关配置
local redis_key_white_list = "map_request_white_list"-- 连接Redis
local redis = require "resty.redis"
local red = redis:new()
red:set_timeout(1000) -- 设置超时(毫秒)
local ok, err = red:connect("127.0.0.1", 6379)
if not ok thenngx.log(ngx.ERR, "Redis连接失败: ", err)return ngx.exit(500)
end-- 权限校验
local res, err = red:auth("123456")
if not res thenngx.say("failed to authenticate: ", err)return
end-- 检查IP是否在白名单中
local is_in_whitelist, err = red:sismember(redis_key_white_list, client_ip)
if is_in_whitelist == 1 thenngx.log(ngx.INFO, "IP在白名单中: ", client_ip)
elsengx.status = ngx.HTTP_FORBIDDENngx.say("Access Denied")return ngx.exit(ngx.HTTP_FORBIDDEN)
end-- 返还redis连接到连接池
local ok, err = red:set_keepalive(10000, 100)
if not ok thenngx.log(ngx.ERR, "设置keepalive失败: ", err)
end

详细解释

  1. 获取客户端IP和请求路径

    local client_ip = ngx.var.remote_addr
    local path = ngx.var.uri
    

    这两行代码从Nginx变量中获取客户端的IP地址和请求路径,client_ip用于后续的白名单检查。

  2. Redis相关配置

    local redis_key_white_list = "map_request_white_list"
    

    定义存储白名单的Redis键。

  3. 连接Redis

    local redis = require "resty.redis"
    local red = redis:new()
    red:set_timeout(1000) -- 设置超时(毫秒)
    local ok, err = red:connect("127.0.0.1", 6379)
    if not ok thenngx.log(ngx.ERR, "Redis连接失败: ", err)return ngx.exit(500)
    end
    

    使用resty.redis模块创建Redis连接对象,并设置连接超时时间。尝试连接到Redis服务器,如果连接失败,记录错误日志并返回500错误。

  4. 权限校验

local res, err = red:auth("123456")
if not res thenngx.say("failed to authenticate: ", err)return
end

对Redis进行认证,如果认证失败,输出错误信息并停止执行。

  1. 检查IP是否在白名单中
local is_in_whitelist, err = red:sismember(redis_key_white_list, client_ip)
if is_in_whitelist == 1 thenngx.log(ngx.INFO, "IP在白名单中: ", client_ip)
elsengx.status = ngx.HTTP_FORBIDDENngx.say("Access Denied")return ngx.exit(ngx.HTTP_FORBIDDEN)
end

使用SISMEMBER命令检查IP是否在Redis的白名单集合中。如果IP在白名单中,记录信息日志;否则,返回403 Forbidden状态码并拒绝访问。

  1. 释放Redis连接
local ok, err = red:set_keepalive(10000, 100)
if not ok thenngx.log(ngx.ERR, "设置keepalive失败: ", err)
end

将Redis连接返回到连接池中,以便后续请求复用该连接。如果设置失败,记录错误日志。

在Nginx中配置Lua脚本

在Nginx的location配置中,使用access_by_lua_file指令来调用上述Lua脚本:

nginx复制代码http {```lua
http {server {listen 80;server_name example.com;location / {access_by_lua_file /opt/nginx/lua_script/white.lua;proxy_pass http://backend;}}
}

上述配置在接收到HTTP请求时,会首先执行/opt/nginx/lua_script/white.lua脚本进行白名单检查。如果通过检查,则继续将请求转发到后端服务器。

在这里插入图片描述
成功访问:
在这里插入图片描述
禁止访问:
在这里插入图片描述

5、黑名单实现

黑名单的作用与场景

黑名单是一种网络安全机制,用于识别并阻止恶意IP地址对服务器资源的访问。它在多种场景中发挥着重要作用:

  • 防止恶意攻击:通过封禁已知的攻击者IP,减少服务器遭受的恶意攻击。
  • 打击爬虫滥用:限制爬虫对网站资源的过度访问,保护数据不被滥用。
  • 减轻服务器负载:通过限制特定IP的访问频率,减轻服务器压力,提高服务稳定性。
  • DDoS防御:快速响应DDoS攻击,封禁攻击源IP,保护服务可用性。

使用Lua脚本与Redis实现动态IP封禁

OpenResty结合Redis可以实现一个高效的动态IP封禁系统。以下是实现的关键步骤:

  1. 环境配置:确保Nginx OpenResty和Redis环境准备就绪。
  2. Lua脚本编写:编写Lua脚本来动态查询和更新Redis中的黑名单状态。
  3. Nginx配置整合:在Nginx配置文件中集成Lua脚本,实现访问控制。

在这里插入图片描述

案例演示

通过使用Lua脚本,在接收到HTTP请求时检查请求的IP地址是否在黑名单中,或控制IP的访问频率,并进行相应的处理。

思路

  1. 获取客户端IP:在Lua脚本中获取客户端的IP地址。
  2. 连接Redis:使用resty.redis模块连接Redis数据库。
  3. 权限校验:对连接的Redis进行认证。
  4. 检查IP是否在黑名单中:从Redis中检查IP是否存在于黑名单集合中。
  5. 访问频次控制:对每个IP的访问频次进行限制,如果超过指定的频次,则将IP加入黑名单。
  6. 返回结果:如果IP在黑名单中,返回403 Forbidden状态码,拒绝访问;否则,允许请求继续。

Nginx 配置文件

upstream jms-uat {server 192.168.82.105:81;
}
server {listen 80;server_name jms.ownit.top;# 白名单 或者 黑名单# include /opt/nginx/whitelist/corporation.conf;rewrite ^/(.*)$ https://$host/$1 permanent;access_log /www/wwwlogs/dns.ownit.top.log;error_log /www/wwwlogs/dns.ownit.top.error.log;
}
server {listen 443 ssl;server_name jms.ownit.top;# 白名单 或者 黑名单# include /opt/nginx/whitelist/corporation.conf;ssl_certificate /opt/nginx/ssl/ownit.top.crt;ssl_certificate_key /opt/nginx/ssl/ownit.top.key;include ssl.conf;location = /core/auth/login/ {access_by_lua_file /opt/nginx/lua_script/login.lua;proxy_pass http://jms-uat;proxy_set_header Upgrade $http_upgrade;proxy_set_header Connection "upgrade";}location / {if ($request_uri !~ \.(html|htm|jpg|png|ico|js|css)$) {access_by_lua_file /opt/nginx/lua_script/rule.lua;}proxy_set_header Upgrade $http_upgrade;proxy_set_header Connection "upgrade";proxy_pass http://jms-uat;include https_proxy.conf;client_max_body_size 0;}access_log /www/wwwlogs/dns.ownit.top.log;error_log /www/wwwlogs/dns.ownit.top.error.log;
}

location = /core/auth/login/

location = /core/auth/login/ {access_by_lua_file /opt/nginx/lua_script/login.lua;proxy_pass http://jms-uat;proxy_set_header Upgrade $http_upgrade;proxy_set_header Connection "upgrade";
}
解释
  • location = /core/auth/login/
    • 这是一个精确匹配的location块,仅对请求路径严格等于/core/auth/login/的请求生效。
  • access_by_lua_file /opt/nginx/lua_script/login.lua;
    • 使用OpenResty的Lua模块,指定在访问控制阶段执行/opt/nginx/lua_script/login.lua脚本。这个脚本通常用于执行认证、权限检查或其他预处理逻辑。
  • proxy_pass http://jms-uat;
    • 将匹配到的请求代理到上游服务器http://jms-uat
  • proxy_set_header Upgrade $http_upgrade;
    • 设置Upgrade请求头,支持WebSocket等协议升级。$http_upgrade变量包含原始请求中的Upgrade头字段的值。
  • proxy_set_header Connection "upgrade";
    • 设置Connection请求头为upgrade,通常与Upgrade头一起使用,以确保连接升级。

location /

location / {# 如果该location 下存在静态资源文件可以做一个判断 if ($request_uri !~ \.(html|htm|jpg|png|ico|js|css)$) {access_by_lua_file /opt/nginx/lua_script/rule.lua; 加上了这条配置,则会根据 rule.lua 的规则进行限流}proxy_set_header Upgrade $http_upgrade;proxy_set_header Connection "upgrade";proxy_pass http://jms-uat;include https_proxy.conf;client_max_body_size 0;
}
解释
  • location /
    • 这是一个通配符匹配的location块,表示所有路径的请求都会匹配到这个块,除非有其他更精确的匹配块。
  • if ($request_uri !~ \.(html|htm|jpg|png|ico|js|css)$)
    • 使用if指令对请求路径进行检查。仅在请求路径不匹配指定的静态资源文件扩展名(如.html, .htm, .jpg, .png, .ico, .js, .css)时,执行后续的Lua脚本。这种检查有助于将动态资源与静态资源区分开来。
  • access_by_lua_file /opt/nginx/lua_script/rule.lua;
    • 使用OpenResty的Lua模块,指定在访问控制阶段执行/opt/nginx/lua_script/rule.lua脚本。这个脚本通常用于实现限流、防火墙或其他动态访问控制逻辑。
  • proxy_set_header Upgrade $http_upgrade;
    • 设置Upgrade请求头,支持WebSocket等协议升级。$http_upgrade变量包含原始请求中的Upgrade头字段的值。
  • proxy_set_header Connection "upgrade";
    • 设置Connection请求头为upgrade,通常与Upgrade头一起使用,以确保连接升级。
  • proxy_pass http://jms-uat;
    • 将匹配到的请求代理到上游服务器http://jms-uat
  • include https_proxy.conf;
    • 包含额外的配置文件https_proxy.conf,该文件可能包含HTTPS代理相关的其他配置项。
  • client_max_body_size 0;
    • 设置客户端请求体的最大大小为0,表示不限制请求体的大小。

这两个location块主要用于处理不同路径的请求,并在访问控制阶段使用Lua脚本进行相应的逻辑处理。精确匹配的/core/auth/login/路径专用于特定的认证或预处理,而通配符匹配的/路径则处理所有其他请求,并进行动态访问控制逻辑。两者共同确保了Nginx服务器的灵活性和安全性。

Lua脚本 (rule.lua)

-- 连接池超时回收毫秒
local pool_max_idle_time = 10000
-- 连接池大小
local pool_size = 100
-- redis 连接超时时间
local redis_connection_timeout = 100
-- redis host
local redis_host = "192.168.102.20"
-- redis port
local redis_port = "6379"
-- redis auth
local redis_auth = "123456"
-- 封禁IP时间(秒)
local ip_block_time = 120
-- 指定ip访问频率时间段(秒)
local ip_time_out = 10
-- 指定ip访问频率计数最大值(次)
local ip_max_count = 60-- 错误日志记录
local function errlog(msg, ex)ngx.log(ngx.ERR, msg, ex)
end-- 释放连接池
local function close_redis(red)if not red thenreturnendlocal ok, err = red:set_keepalive(pool_max_idle_time, pool_size)if not ok thenngx.say("redis connct err:", err)return red:close()end
end-- 连接redis
local redis = require "resty.redis"
local client = redis:new()
local ok, err = client:connect(redis_host, redis_port)
-- 连接失败返回服务器错误
if not ok thenreturn
end
-- 设置超时时间
client:set_timeout(redis_connection_timeout)-- 优化验证密码操作
local connCount, err = client:get_reused_times()
-- 新建连接,需要认证密码
if 0 == connCount thenlocal ok, err = client:auth(redis_auth)if not ok thenerrlog("failed to auth: ", err)returnend
elseif err thenerrlog("failed to get reused times: ", err)return
end-- 获取请求ip
local function getIp()local clientIP = ngx.req.get_headers()["X-Real-IP"]if clientIP == nil thenclientIP = ngx.req.get_headers()["x_forwarded_for"]endif clientIP == nil thenclientIP = ngx.var.remote_addrendreturn clientIP
endlocal clientIp = getIp()local incrKey = "limit:all:count:" .. clientIp
local blockKey = "limit:all:block:" .. clientIp-- 查询ip是否被禁止访问,如果存在则返回403错误代码
local is_block, err = client:get(blockKey)
if tonumber(is_block) == 1 thenngx.exit(ngx.HTTP_FORBIDDEN)close_redis(client)
endlocal ip_count, err = client:incr(incrKey)
if tonumber(ip_count) == 1 thenclient:expire(incrKey, ip_time_out)
end
-- 如果超过单位时间限制的访问次数,则添加限制访问标识,限制时间为ip_block_time
if tonumber(ip_count) > tonumber(ip_max_count) thenclient:set(blockKey, 1)client:expire(blockKey, ip_block_time)
endclose_redis(client)

在这里插入图片描述
成功访问:
在这里插入图片描述

失败访问:
在这里插入图片描述

参考文档:
https://www.cnblogs.com/KingArmy/p/18019489
https://blog.csdn.net/qq_45503196/article/details/134648292

相关文章:

使用Nginx OpenResty与Redis实现高效IP黑白名单管理

1、引言 在当今数字化时代,网络安全已成为企业和个人用户关注的焦点。IP黑白名单作为一种有效的网络安全策略,允许我们精确控制对Web资源的访问权限。通过白名单,我们可以确保只有可信的IP地址能够访问敏感资源;而黑名单则可以阻…...

EasyExcel导入导出数据类型转换

前言: 1、基本数据类型转换:当前原始的数据类型是interger类型,需要在导出时将其映射为对应的字符串,并且导入时可以将字符串重新映射为interger类型。 2、时间格式转换:数据从数据库中获取的类型为LocalDate类型&…...

stm32入门-----EXTI外部中断(下——实践篇)

目录 前言 一、硬件介绍 1.对射红外线传感器 2.旋转编码器 二、EXTI外部中断C编程 1.开启RCC时钟 2.配置GPIOK口初始化 3.配置AFIO 4.配置EXIT 5.配置NVIC 三、EXIT外部中断项目实操 1.对射红外传感器计数 2.选择编码器计数 前言 本期接着上一期的内容继续学习stm3…...

深度学习落地实战:基于UNet实现血管瘤超声图像分割

前言 大家好,我是机长 本专栏将持续收集整理市场上深度学习的相关项目,旨在为准备从事深度学习工作或相关科研活动的伙伴,储备、提升更多的实际开发经验,每个项目实例都可作为实际开发项目写入简历,且都附带完整的代码与数据集。可通过百度云盘进行获取,实现开箱即用 …...

Python进阶(4)--正则表达式

正则表达式 在Python中,正则表达式(Regular Expression,简称Regex)是一种强大的文本处理工具,它允许你使用一种特殊的语法来匹配、查找、替换字符串中的文本。 在这之前,还记得之前我们是通过什么方法分割…...

RCA连接器是什么?一文读懂

RCA连接器,也就是我们在电视机、DVD播放器、通讯设备、立体声设备和游戏设备后面常见的彩色插头,其历史可以追溯到近一个世纪以前。这种现今广泛使用的电缆接口,最初是由美国无线电公司(RCA)开发并命名的,在…...

【linux】服务器安装NVIDIA驱动

【linux】服务器安装NVIDIA驱动 【创作不易,求点赞关注收藏】😀 文章目录 【linux】服务器安装NVIDIA驱动一、关闭系统自带驱动nouveau二、下载英伟达驱动三、安装英伟达驱动1、禁用X服务器和相关进程2、在TTY终端安装驱动3、验证是否安装成功4、重新启…...

【达梦数据库】关于用户、模式、表空间等如何理解?

与MySQL的用户有所区别,MySQL是单实例多库,DM7以上版本是单库多实例架构, MySQL访问方式: 一个root访问多个库,访问前切换一下就ok 比如MySQL到DM的迁移是,MySQL的一个库对应dm中的一个表空间和一个用户。比…...

一篇就够mysql高阶知识总结

一、事务的ACID原则 序号原则说明1原子性(Atomicity)事务是数据库的逻辑工作单位,事务中包括的诸操作要么都做,要么都不做2一致性(Consistency)事务执行的结果必须是使数据库从一个一致性状态变到另一个一…...

CTF-Web习题:[BJDCTF2020]ZJCTF,不过如此

题目链接:[BJDCTF2020]ZJCTF,不过如此 解题思路 访问靶场链接,出现的是一段php源码,接下来做一下代码审阅,发现这是一道涉及文件包含的题 主要PHP代码语义: file_get_contents($text,r); 把$text变量所…...

【IEEE出版】第四届能源工程与电力系统国际学术会议(EEPS 2024)

第四届能源工程与电力系统国际学术会议(EEPS 2024) 2024 4th International Conference on Energy Engineering and Power Systems 重要信息 大会官网:www.iceeps.com 大会时间:2024年8月9-11日 大会…...

浅谈Vue:text-align: center、align-items: center、justify-content: center三种居中的区别和用法

text-align: center、align-items: center 和 justify-content: center 是用于不同布局场景下的CSS属性。它们在水平和垂直居中元素方面有所不同,具体取决于你使用的布局模型(如块级元素、Flexbox、Grid)。以下是它们的区别和适用场景&#x…...

理解UI设计:UI设计师的未来发展机遇

UI设计师的出现是互联网时代的设计变革。随着移动互联网的快速发展,移动产品设计师非常短缺。高薪资让许多其他行业的设计师已经转向了UI设计。那么什么是UI设计呢?UI设计师负责什么?UI设计的发展趋势和就业前景如何?这些都是许多…...

关键字 internal

在C#中,internal 关键字是一个访问修饰符,它用于限制类型或类型成员的访问性。当一个类型(类、结构体、接口、枚举等)或类型成员(字段、属性、方法、事件等)被声明为 internal 时,它只能在同一程…...

C学习(数据结构)-->单链表习题

目录 一、环形链表 题一:环形链表 思路: 思考一:为什么? 思考二:快指针一次走3步、4步、......n步,能否相遇 step1: step2: 代码: 题二: 环形链表 I…...

MATLAB6:M文件和控制流

文章目录 一、实验目的二、实验内容三、仿真结果四、实践中遇到的问题及解决方法 一、实验目的 1. 熟悉运用MATLAB的控制指令。   2. 理解M脚本文件和函数文件的本质区别。   3. 能够运用所学知识,编制程序解决一般的计算问题。 二、实验内容 1.for循环结构及注…...

网页数据抓取:融合BeautifulSoup和Scrapy的高级爬虫技术

网页数据抓取:融合BeautifulSoup和Scrapy的高级爬虫技术 在当今的大数据时代,网络爬虫技术已经成为获取信息的重要手段之一。Python凭借其强大的库支持,成为了进行网页数据抓取的首选语言。在众多的爬虫库中,BeautifulSoup和Scrap…...

Linux应用——网络基础

一、网络结构模型 1.1C/S结构 C/S结构——服务器与客户机; CS结构通常采用两层结构,服务器负责数据的管理,客户机负责完成与用户的交互任务。客户机是因特网上访问别人信息的机器,服务器则是提供信息供人访问的计算机。 例如&…...

白骑士的C++教学实战项目篇 4.3 多线程网络服务器

系列目录 上一篇:白骑士的C教学实战项目篇 4.2 学生成绩管理系统 在这一节中,我们将实现一个多线程网络服务器项目,通过该项目,我们将学习套接字编程的基础知识以及如何使用多线程处理并发连接。此外,我们还将实现一个…...

Go语言并发编程-Context上下文

Context上下文 Context概述 Go 1.7 标准库引入 context,译作“上下文”,准确说它是 goroutine 的上下文,包含 goroutine 的运行状态、环境、现场等信息。 context 主要用来在 goroutine 之间传递上下文信息,包括:取…...

React@16.x(62)Redux@4.x(11)- 中间件2 - redux-thunk

目录 1,介绍举例 2,原理和实现实现 3,注意点 1,介绍 一般情况下,action 是一个平面对象,并会通过纯函数来创建。 export const createAddUserAction (user) > ({type: ADD_USER,payload: user, });这…...

【Qt】QTcpServer/QTcpSocket通信

这里写目录标题 1.pro文件2.服务器3.客户端 1.pro文件 QT network2.服务器 h文件 #ifndef MAINWINDOW_H #define MAINWINDOW_H#include <QMainWindow> #include <QTcpServer> #include <QTcpSocket>QT_BEGIN_NAMESPACE namespace Ui { class MainW…...

【时时三省】单元测试 简介

目录 1,单元测试简介 2,单元测试的目的 3,单元测试检查范围 4,单元测试用例设计方法 5,单元测试判断通过标准 6,测试范围 7,测试频率 8,输出成果 经验建议: 山不在高,有仙则名。水不在深,有龙则灵。 ----CSDN 时时三省 1,单元测试简介 单元测试在以V模型…...

中间件——Kafka

两个系统各自都有各自要去做的事&#xff0c;所以只能将消息放到一个中间平台&#xff08;中间件&#xff09; Kafka 分布式流媒体平台 程序发消息&#xff0c;程序接收消息 Producer&#xff1a;Producer即生产者&#xff0c;消息的产生者&#xff0c;是消息的入口。 Brok…...

中介者模式(行为型)

目录 一、前言 二、中介者模式 三、总结 一、前言 中介者模式&#xff08;Mediator Pattern&#xff09;是一种行为型设计模式&#xff0c;又成为调停者模式&#xff0c;用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式地互相引用&#xff0c;从而使其耦合…...

定个小目标之刷LeetCode热题(45)

32. 最长有效括号 给你一个只包含 ( 和 ) 的字符串&#xff0c;找出最长有效&#xff08;格式正确且连续&#xff09;括号 子串的长度。 示例 1&#xff1a; 输入&#xff1a;s "(()" 输出&#xff1a;2 解释&#xff1a;最长有效括号子串是 "()"有事…...

golang 实现负载均衡器-负载均衡原理介绍

go 实现负载均衡器 文章目录 go 实现负载均衡器代码实现介绍负载均衡的核心组件与工作流程核心组件工作流程 总结 算法详细描述&#xff1a;1. 轮询&#xff08;Round Robin&#xff09;2. 最少连接&#xff08;Least Connections&#xff09;3. IP散列&#xff08;IP Hash&…...

spring是如何解决循环依赖的,为什么不是两级

1. Spring使用三级缓存来解决循环依赖问题 Spring使用三级缓存来解决循环依赖问题&#xff0c;‌而不是使用两级缓存。‌ 在Spring框架中&#xff0c;‌解决循环依赖的关键在于正确地管理Bean的生命周期和依赖关系。‌循环依赖指的是两个或多个Bean相互依赖&#xff0c;‌如果…...

大模型预训练优化参数设置

文章目录 基于批次数据的训练学习率优化器稳定优化技术与传统神经网络的优化类似,通常使用批次梯度下降算法来进行模型参数的调优。同时,通过调整学习率以及优化器中的梯度修正策略,可以进一步提升训练的稳定性。为了防止模型对数据产生过度拟合,训练中还需要引入一系列正则…...

PHP pwn 学习 (2)

文章目录 A. 逆向分析A.1 基本数据获取A.2 函数逆向zif_addHackerzif_removeHackerzif_displayHackerzif_editHacker A.3 PHP 内存分配 A.4 漏洞挖掘B. 漏洞利用B.1 PHP调试B.2 exp 上一篇blog中&#xff0c;我们学习了一些PHP extension for C的基本内容&#xff0c;下面结合一…...

温州市网页制作项文静/关键词优化教程

今天在解决爬虫对加密参数的分析时&#xff0c;需要使用到base64解码。但是过程中出现了TypeError&#xff1a;Incorrect padding的错误提示。以下是解决方法&#xff0c;以便查阅。 其实正常使用base64是不会出现问题的&#xff0c;就比如下面的代码。 1 #!usr/bin/env pytho…...

dede织梦建站教程/seo网站设计工具

万拓超融合存储CS100-48是万拓推出的新一代48盘位云节点产品&#xff0c;凭借12G高性能背板、支持硬盘防震、大风量散热、嵌入式BBU、支持通用主板这些优点&#xff0c;很好地满足了中大型超融合系统和云存储系统的需求&#xff0c;产品广泛适用于公安、运营商、交通、政府、教…...

盘多多搜索引擎入口/seo全网营销公司

springMVC带参数请求重定向SpirngMVC返回逻辑视图名 可以分下面几种情况&#xff1a;1. servlet进行请求转发,返回到jsp页面,如 return "index.jsp" ;2. servlet 返回结果&#xff0c;让请求 重定向到某个jsp页面 &#xff0c;此时servlet 返回语句类似&#xff1a;…...

嘉祥县建设局网站/上海seo优化外包公司

公司有个子服务较多&#xff0c;交互频繁的系统&#xff0c;有一些需要共享传输的对象&#xff0c;它们通过 JDK 序列化&#xff08;Java Object Serialization&#xff09;后进行交互&#xff1b;但是由于一些不可描述的历史原因&#xff0c;这些对象存在多个版本&#xff0c;…...

网站做网络营销/临沂seo优化

NOTE&#xff1a; 1.绝不要返回pointer或reference 指向一个local stack 对象&#xff0c;或返回reference 指向一个heap-allocated对象&#xff0c;或返回pointer 或reference指向一个 local static 对象而有可能同时需要多个这样的对象。转载于:https://www.cnblogs.com/chip…...

网站 加域名/四川百度推广排名查询

http://www.ctshk.com/passport/talent_bookrep.htm 換領往來港澳通行證和申請簽注延期須知為方便持《往來港澳通行證》以內地逗留簽注在香港工作、就學、接受培訓的內地居民及其隨行家屬&#xff0c;以及勞務人員在香港逗留標籤的有效期間內&#xff0c;可以在香港換領 &#…...