网访问内网机器:基于frp的内网穿透

news2024/11/19 9:37:28

随缘更新些我自己的博客网站里的文章吧

因为经常需要远程访问自己的机器,所以写一个博客记录一下

frp项目Github仓库

公网访问内网机器:基于frp的内网穿透

从公网中访问自己的私有设备向来是一件难事儿。

1. 为什么需要内网穿透?

A. 计算机网络

如何在自己的机器上访问另外一台机器?一台机器本身是一个独立的整体,可以直接访问本身所存储的文件。而如果现在有两台机器的话,机器A想要访问机器B上的文件,该怎么做?

事实上,当两台、乃至多台机器在一起的时候,就构成了一个以单台计算机为节点,以计算机和计算机之间的链接为边的网络,即计算机网络。我们访问另外一台计算机文件,就需要通过计算机网络来实现。

计算机网络中有一个比较重要的问题,就是如何标识每一台计算机。作为人,我们能很简单的知道,这是Jack Wang的Mac、那是Sarah的Windows、那是课题组公用的Linux,但是对于计算机来说,这是很难的。

所以类似于身份证能够识别不同的人一样,给组成计算机网络中的每一台设备一个编号,这个编号就作为每一台机器在网络中的标识,利用这个编号,能够找到需要访问的计算机。这个编号称为IP地址

所以,想要访问另外一台电脑,就需要知道对方的IP地址,然后才能访问。

B. 私网间互相访问

IP地址根据最初的设定,分为ABC几类。直白的来说就是有一些IP地址是保留给局域网使用(私网),剩下的IP地址全球共享(公网)

  • 公网IP地址是不能重复的。
  • 保留给局域网使用的IP地址在不同的局域网间是可以重复的。例如:你家和我家可能都有192.168.0.1这个IP地址,而使用这个IP地址的设备在你的局域网中可能是你的手机,而在我的局域网中可能是我的PC。但是,保留给局域网使用的IP地址在同一个局域网内是不能重复的。例如:我家的192.168.0.1这个IP地址只可能被一部设备使用,要么是我的手机,要么是我的PC。

因此,不同局域网内的IP地址可重复这一性质就导致了两台处于不同局域内机器互相连接可能存在问题:

  • 我们在办公室中使用的PC连接了办公室的网络,因此具有一个私网的IP地址,可能是192.168.0.1;我们的手机连接办公室的网络,因此也具有一个私网地址,可能是192.168.0.2
  • 我们需要连接的在家里的PC连接了家里的网络,因此具有一个私网的IP地址,可能是192.168.0.2

那么我们使用在办公室内的机器连接192.168.0.2这个地址的时候,我们本来想连接家里的PC,但是由于私网的IP地址可重复,我们可能会连接到同一局域网下的另外一台机器。

C. 借助公网设备作为跳板

解决问题的办法就是获得一个公网IP。因为世界上所有的网络在一起,构成了互联网,或者公网。公网IP在公网中是唯一的。所以不管我们处于哪个局域网,都可以访问到具有公网IP的机器。

所以解决方案就是:

  • 机器A和机器B都先连接到公网机器。
  • 因为连接在建立后通信是双向的,所以在机器A、B连接到公网机器后,可以和公网机器双向通信
  • 而后机器A把需要访问的机器B上的文件路径传给公网机器
  • 公网机器把文件路径通知给机器B
  • 机器B把文件传输给公网机器
  • 公网机器再把文件传输给机器A

这样利用公网机器作为跳板,就实现了处于两个私网的机器间的访问。这种解决方案称为内网穿透,即借助一个具有公网IP的服务器作为跳板,来让处于其他私网的设备访问到内网中的机器。这样做类似于把内网穿透到公网上,因此称为内网穿透.

D. 哪来的公网IP?

上面解决两个私网机器互相访问最核心的,就是要有一个具有公网IP的机器。而由于中国加入到互联网的时间比较晚,所以分到的公网IP就比较少。原来很早的时候,打电话免费就可以申请得到一个公网IP,但现在运营商因为IP地址短缺不给你分配公网IP地址。

如果花钱买的话,目前市场中常用的网络有移动宽带、联通宽带、电信宽带,不同的网络运营商提供业务办理不同,收取的费用标准也存在一定的不同。一般情况,申请公网IP大概需要1000-2000元,具体的收费标准还需要以当地各大网络运营商提供的具体解决方案为准。所以就很贵。

所以就出现了一些服务商,他们购买了公网IP,然后架设了公网机器,我们只需要购买这些服务商提供的跳板服务/穿透服务就行了。但是这样功能非常有限,只有跳板服务,可玩性和功能性不高。

因此,我们不如直接租一个具有公网IP的服务器,然后自己架设跳板服务/穿透服务即可

2. frp搭建内网穿透

A. 什么是frp

既然我们需要进行内网穿透,肯定就需要有一个程序帮助我们去完成公网、私网机器连接的建立,公网机器上消息的转发等等功能,这个软件就是frp

简单地说,frp就是一个反向代理软件,它体积轻量但功能很强大。利用他就可以实现反向穿透,即可以使处于内网或防火墙后的设备对外界提供服务。

它支持HTTPTCPUDP等众多协议。我们今天使用的仅限于TCPUDP,所以使用frp是足够了

frpc项目的Github主页

B. 机器配置信息

既然frp需要建立公网机器和私网机器之间的连接,因此frp实际上是两个程序:

  • frpc:即frp客户端(client),运行在需要被穿透到公网上的机器,即将来被远程访问的机器
  • frps:即frp服务端(server),运行在具有公网IP的机器上

而在运行的时候,frp是根据配置文件中的描述来运行的。

因此,我们未来需要在公网机器和被远程访问的机器上分别下载frp程序,并编写配置文件。

这里我的配置是:

  • 公网机器是一台腾讯云服务器,后面就简称为服务器
    • 公网地址是81.68.123.84
    • 用户名是lighthouse
    • 主机名是VM-4-7-ubuntu
  • 需要被穿透的机器(被其他私网机器访问的机器,即家里的机器)称为PC端
    • 私网IP地址不重要
    • 用户名是jack
    • 主机名是jack-Alienware-Aurora-R13

注意,这里的公网地址公网机器用户名需要使用你自己的!

C. 下载frp

1) 服务器下载frps

首先连接进服务器下载frp服务端

ssh lighthouse@81.68.123.84
mkdir -p ~/opt/frps
cd opt/frps
wget -c https://github.com/fatedier/frp/releases/download/v0.51.0/frp_0.51.0_linux_amd64.tar.gz

注意,不同CPU架构下载的链接是不同的,我的服务器是IntelCPU,所以是x86_64架构,下载amd64版本的程序。你需要根据自己的服务器的架构去下载。

所有版本的下载地址:https://github.com/fatedier/frp/releases

下载完成

然后解压

tar xzvf frp_0.51.0_linux_amd64.tar.gz
ls -al frp_0.51.0_linux_amd64

可以看到,下载的程序是包含客户端和服务端的

因为目前是在服务器上配置frp服务端,因此删去不需要的客户端程序:

rm frp_0.51.0_linux_amd64/frpc*
ls -al frp_0.51.0_linux_amd64

服务器上只剩下frp服务端

2) PC端下载frpc

步骤和服务器上下载frps基本是一样的,这不过这里要删除的是frp服务端

mkdir -p ~/opt/frpc
cd ~/opt/frpc
wget -c https://github.com/fatedier/frp/releases/download/v0.51.0/frp_0.51.0_linux_amd64.tar.gz
tar xzvf frp_0.51.0_linux_amd64.tar.gz
rm frp_0.51.0_linux_amd64/frps*
ls -al frp_0.51.0_linux_amd64

PC端只剩下frp客户端

D. 配置frp

类似于下载,配置frp也是分为PC端配置和服务器配置。

frp工作流程:以SSH登录为例

以SSH登录为例,frp的工作流程如上图。假设现在远程主机(即键盘物理连接的机器)需要远程登录PC端,那么实际上就是远程主机使用PC机上的SSH程序,即访问PC机上的22端口。

所以,当远程主机的一个ssh请求来了之后:

  • 远程主机的ssh请求打到服务器上的10001端口
  • 服务器的10001端口被正在运行的frps程序监听。当frps监听到一个ssh请求后,将其通过服务器的的6006端口发到PC端(已经建立链接的两台机器之间的通信是相互的)
  • PC端上正在运行的的frpc程序接收到远程主机发来的ssh请求后,将其转发到本机的22端口
  • 远程主机的ssh请求最终被监听PC端22端口的服务程序处理

因此:

  • PC端(frp客户端)需要指定,将自己的22号端口映射为服务器(frp服务端)的10001端口,或者说需要将服务器的10001端口的流量转发到PC端的22端口
  • 服务器(frp服务端)需要指定PC机(frp客户端)需要通过哪个端口和服务器(frp服务端)通信

可以看到,frp其实最重要的就是转发了远程主机发来的数据包,因此frp实际上工作在传输层。稍后我们在配置中就能看到,在frp的配置文件中,我们需要指定服务器的哪个端口的哪种数据包需要转发到PC端的哪一个端口。

针对上面举的SSH的例子,SSH服务本质上是一个文本传输服务,只不过进行了加密,因此SSH的数据包使用的是TCP协议。后面穿透不同的服务的时候需要指定数据包的类型

1) 服务器配置

服务器端要配置的,实际上就只有bind_port。因为listen_port是需要frp客户端指定的

ssh lighthouse@81.68.123.84
cd ~/opt/frps/frp_0.51.0_linux_amd64
vim frps.ini

将其中的bind_port修改为6006,这里是为了和上面的图配合起来,你也可以改成自己喜欢的。

cat frps.ini

frp服务端将监听服务器的6006端口来接收frp客户端的消息

服务器端的配置就结束了,最后得到的配置文件为:

# frps.ini,即服务端上的配置
[common]
bind_port = 6006

2) PC端配置

客户端的配置比服务端配置要复杂些,因为要指定远程端口的某种流量转发到本地的某个端口。

cd ~/opt/frpc/frp_0.51.0_linux_amd64
vim frpc.ini

按照上面介绍的

  • 首先设置PC端的frp客户端连接到的frp服务端的IP地址为服务器地址,即设置server_addr=81.68.123.84
  • 然后设置PC端的frp客户端连接道frp服务端监听的端口,即设置server_port=6006

接着编写一个新的规则

  • 规则名字可以随便给,这里直接就是Aurora-SSH
  • 服务端需要监听服务端的10001端口
  • 服务端转发的数据包类型就是tcp
  • 服务端转发的数据包的目的地址就是本机地址127.0.0.1
  • 服务端转发的数据包的目的端口就是22端口

最后得到的总配置文件为

注意,为了避免你的内网机器被穿透到我的服务器上,你需要修改一下server_addr,免得到时候我能登录你的内网机器^_^

# frpc.ini,即PC端上的配置
[common]
# 公网服务器IP地址
server_addr = 81.68.123.84
# 公网服务器上frps通过该端口和私网机器上的frpc通信
server_port = 6006

[Aurora-SSH]
# 该规则所转发的数据包类型
type = tcp
# 数据包转发IP地址
local_ip = 127.0.0.1
# 数据包转发目的端口
local_port = 22
# 将公网服务器上该端口的type类型的包转发到本机
remote_port = 10001

所以总的来说就是:将81.68.123.84服务器上的10001端口接收到的tcp数据包转发到本地的22端口,并且通过服务器的6006端口进行通信

服务端配置文件

E. 启动frp

首先启动服务器端的frps

ssh lighthouse@81.68.123.84
cd ~/opt/frps/frp_0.51.0_linux_amd64
./frps -c frps.ini| tee -a frps.log

这里把命令行输出到信息备份一份到frps.log文件中

启动frp服务端

然后启动PC端的frpc

cd ~/opt/frps/frp_0.51.0_linux_amd64
./frpc -c frpc.ini | tess -a frpc.log

启动frp客户端

启动成功后,再检查一下服务器上的frps,发现已经接收到了frpc客户端发来的规则,开始监听端口10001

服务器上的frps开始监听端口10001

F. 验证

最后验证一下能否远程登录到PC端。

这里直接就在PC端下SSH连接服务器的10001端口,因为登录的是PC端的用户,所以用户名还需要是PC端的用户名,只不过此时SSH服务器地址已经变成了服务器的地址

ssh jack@81.68.123.84 -p 10001

成功登陆到PC端

3. 番外:PC端开机自运行frpc

最后,服务器因为我们随时可以链接进去,所以使用tmux开一个session,保持frps运行即可。但是PC端则需要我们事先手动运行frpc

如果我们运行了一些命令导致PC端重启了,那么再次启动的时候就会导致服务丢失。所以,我们希望PC端在重新启动的时候能够自动运行frpc

为此,我们使用Systemd来新建一个服务。关于Systemd后面会写点文章介绍,这里就先用吧。

Systemd介绍:

Systemd是一个用于Linux系统的系统和服务管理器。它被设计为替代传统的SysV初始化系统(init)和System V启动脚本,并提供了更先进的功能和特性。

Systemd的目标是改进系统的启动速度、效率和可靠性,并提供更好的系统管理和服务控制功能。它引入了一种并行启动机制,可以同时启动系统中的多个服务,加快系统启动时间。此外,Systemd还支持基于套接字激活的服务,可以在需要时按需启动或停止服务,提高系统资源利用率。

Systemd还引入了一种统一的单元文件(unit files)格式,用于描述系统服务、设备、挂载点等。这些单元文件位于/etc/systemd/system//usr/lib/systemd/system/等目录下,通过这些单元文件,可以对系统的各个方面进行配置和管理。

Systemd提供了一系列的命令行工具,用于管理和控制系统和服务,例如systemctl命令用于启动、停止、重启和管理系统服务,journalctl命令用于查看系统日志。

总的来说,Systemd是一个现代化的系统和服务管理器,它在Linux系统中扮演着重要的角色,改进了系统的启动和管理方式,提供了更好的性能和功能。它已经成为许多主流Linux发行版的默认初始化系统。

A. 编写启动脚本

首先编写一个脚本来运行frpc

cd ~/opt/frpc
# 创建一个软连接,方便后面更新版本
ln -s frp_0.51.0_linux_amd64 bin
vim start_frpc.sh

内容如下:

#! /bin/bash

run_folder=$(cd $(dirname $0) && pwd || exit)
bin_folder="${run_folder}/bin"

cd ${bin_folder} && ${bin_folder}/frpc -c ${bin_folder}/frpc.ini  2>&1 | tee -a ${run_folder}/frpc.log

运行这个脚本就可以一键化直接运行frpc

chmox 755 start_frpc.sh
./start_frpc.sh

输出到终端的日志信息会保存到frpc.log文件中
脚本启动frpc

B. 开机运行启动脚本

编写完了开机脚本还不行,还需要开机就运行这个脚本。后面就是通过Systemd来设置开机运行这个脚本了。开机自运行的Systemd任务需要放在/usr/lib/systemd/system目录下

首先新建一个Systemd任务,名字为frpc-client,而后创建软连接方便修改

cd ~/opt/frpc
sudo touch /etc/systemd/system/frp-client.service
ln -s /etc/systemd/system/frp-client.service ./
sudo vim frp-client.service

然后编写内容如下:

# 这个部分定义了服务的基本信息, 这里是一个启动frpc的服务
[Unit]
Description=开机自动运行frpc任务
# 必须要在网络启动之后才能运行, 因为Systemd是多线程运行服务的
After=network.target
# 同时该任务以来网络, 因此声明启动网络服务是该服务的依赖
Wants=network.target



# 这个部分定义了服务的运行参数和行为
[Service]
# 指定了服务的类型,这里是simple,表示是一个简单的服务,即执行指定的命令或脚本。
Type=simple
# 指定了运行服务的用户,这里是jack,表示以jack的身份运行服务
User=jack
# 这个参数很重要!无论是由于错误、异常退出还是手动停止,只要服务退出,它都应该立即重新启动。
# 这确保了服务的持续性,即使出现问题导致服务停止,Systemd也会自动重新启动它,以恢复服务的正常运行。
# 所以将其指定为always确保脚本会一直运行
Restart=always
# 指定了服务在重启之前的等待时间
RestartSec=5s
# 指定了服务可以打开的最大文件描述符数,这里是1048576
LimitNOFILE=1048576
# 指定了要运行的命令或脚本的绝对路径
ExecStart=/bin/bash /home/jack/opt/frpc/start_frpc.sh
# 服务重新加载(reload)时执行的命令或脚本。
ExecReload=/bin/bash /home/jack/opt/frpc/start_frpc.sh

# 这个部分定义了服务的安装和启动配置
[Install]
# 下面这段不能少, 强制要求了在用户登录前运行启动脚本
WantedBy = multi-user.target

然后把这个启用这个任务

# 因为新建了一个开机启动任务,所以重新加载一下systemd守护进程
sudo systemctl daemon-reload
sudo systemctl enable frp-client.service

启用frpc任务

然后查看一下这个任务的状态

sudo systemctl status frp-client.service

因为目前只是加载了这个任务(表示启动时将会运行这个任务),而由于上次启动时还没运行这个任务,所以显示的是dead。

查看frpc任务

紧着这,启动一下这个服务

sudo systemctl start frpc-client.service
sudo systemctl status frpc-client.service

启动frpc任务

接下来重启一下PC端就行了,此时这个任务就会被运行

sudo reboot
# 重启后检查一下任务状态
sudo systemctl status frp-client.service

开机运行frpc,赢!

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

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

相关文章

【Lua学习笔记】Lua进阶——Table,迭代器

文章目录 官方唯一指定数据结构--tabletable的一万种用法字典和数组 迭代器ipairs()pairs() 回到Table 在【Lua学习笔记】Lua入门中我们讲到了Lua的一些入门知识点,本文将补充Lua的一些进阶知识 官方唯一指定数据结构–table 在上篇文章的最后,我们指出…

【windows】连接共享打印机提示:0x0000011B

【问题现象】 添加共享打印机的时候, 提示错误:0x0000011B。 【解决方法】 按winr键,在运行输入regedit 然后在注册表中找到路径: 计算机\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Print 打开后,在右侧…

Android 之 Canvas API 详解 (Part 3) Matrix 和 drawBitmapMesh

本节引言: 在Canvas的API文档中,我们看到这样一个方法:drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint) 这个Matrix可是有大文章的,前面我们在学Paint的API中的ColorFilter中曾讲过ColorMatrix 颜色矩阵,一个4…

Python 生成随机图片验证码

Python 生成随机图片验证码 在写一个Web项目的时候一般要写登录操作,而为了安全起见,现在的登录功能都会加上输入图片验证码这一功能,在利用Django开发Web项目的过程中,可以使用 Python 生成一个如下所示的图片验证码&#xff1a…

MVC与MVVM模式的区别

一、MVC Model(模型):用于处理应用程序数据逻辑,负责在数据库中存取数据。处理数据的crud View(视图):处理数据显示的部分。通常视图是依据模型数据创建的。 Controller(控制器&…

Leetcode-每日一题【剑指 Offer 51. 数组中的逆序对】

题目 在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。 示例 1: 解题思路 前置知识 分治法 设计思想: 将规模为n的问题分解为k个规模较小的子问题…

解析LED防蓝光灯珠技术原理

LED防蓝光灯珠能有效减少蓝光对眼睛的持续伤害,通过便携式光谱分析仪对比检测,使用LED防蓝光灯珠后,手机屏幕发出的蓝光强度得到了有效抑制,减少了有害蓝光对眼睛的伤害。LED防蓝光灯珠主要是通过将有害蓝光进行反射,或…

(css)AI智能问答页面布局

(css)AI智能问答页面布局 效果&#xff1a; html <!-- AI框 --><div class"chat-top"><div class"chat-main" ref"chatList"><div v-if"!chatList.length" class"no-message"><span>欢迎使…

<PrivateImplementationDetails>.ComputeStringHash 错误解决办法

严重性 代码 说明 项目 文件 行 禁止显示状态 错误 CS0119 “PrivateImplementationDetails”是一个 类型&#xff0c;这在给定的上下文中无效 G:\\_Default.cs 26 活动 用 ILSPY 或者 .NET Reflector 、dnspy 等反编译出来之后 <Privat…

专访伊士曼中国区高管赵志伟:以创新应对新能源汽车后市场变化

受访人&#xff1a;伊士曼高性能膜事业部中国区商务总监赵志伟 新能源汽车发展至规模化阶段&#xff0c;以贴膜、保养维修为主的后市场产业迎来快速崛起&#xff0c;新能源消费者在汽车贴膜、改装和养护领域也表现出比燃油车更高频的需求度。 作为一家全球特种材料公司&#x…

【iOS】KVOKVC原理

1 KVO 键值监听 1.1 KVO简介 KVO的全称是Key-Value Observing&#xff0c;俗称"键值监听"&#xff0c;可以用于监听摸个对象属性值得改变。 KVO一般通过以下三个步骤使用&#xff1a; // 1. 添加监听 [self.student1 addObserver:self forKeyPath:"age"…

Windows实现端口转发(附配置过程图文详解)

文章目录 1. 前言2. 命令提示符3. 防火墙4. netsh 命令4.1 查看已有的转发规则4.2 新增转发规则4.3 删除转发规则 5. 图解汇总6. 欢迎纠正~ 1. 前言 利用Windows端口转发&#xff0c;实现本地设备 ⬅➡ 公网主机 ⬅➡ 远端服务器 2. 命令提示符 以管理员身份打开“命令提示…

【雕爷学编程】Arduino动手做(88)---水流量传感器模块2

37款传感器与执行器的提法&#xff0c;在网络上广泛流传&#xff0c;其实Arduino能够兼容的传感器模块肯定是不止这37种的。鉴于本人手头积累了一些传感器和执行器模块&#xff0c;依照实践出真知&#xff08;一定要动手做&#xff09;的理念&#xff0c;以学习和交流为目的&am…

2023年深圳杯数学建模C题无人机协同避障航迹规划

2023年深圳杯数学建模 C题 无人机协同避障航迹规划 原题再现&#xff1a; 平面上A、B两个无人机站分别位于半径为500 m的障碍圆两边直径的延长线上&#xff0c;A站距离圆心1 km&#xff0c;B站距离圆心3.5 km。两架无人机分别从A、B两站同时出发&#xff0c;以恒定速率10 m/s…

Codeforces Round 888 (Div. 3)

原题链接&#xff1a;Dashboard - Codeforces Round 888 (Div. 3) - Codeforces 目录 A. Escalator Conversations B. Parity Sort C. Tiles Comeback D. Prefix Permutation Sums E. Nastya and Potions F. Lisa and the Martians A. Escalator Conversations 题意&…

【Python从入门到人工智能】14个必会的Python内置函数(7)——数据格式化处理综合应用场景 (实现程序主界面)

总觉得忍一忍就会好起来。真笨&#xff0c;人家不就是觉得你会忍一忍&#xff0c;所以才这样对你吗&#xff1f;当我们凶狠地对待这个世界的时候&#xff0c;才会发现这个世界&#xff0c;突然变得温文尔雅了。——余华《在细雨中呼喊》 &#x1f3af;作者主页&#xff1a; 追光…

第二章:Learning Deep Features for Discriminative Localization ——学习用于判别定位的深度特征

0.摘要 在这项工作中&#xff0c;我们重新审视了在[13]中提出的全局平均池化层&#xff0c;并阐明了它如何明确地使卷积神经网络&#xff08;CNN&#xff09;具有出色的定位能力&#xff0c;尽管它是在图像级别标签上进行训练的。虽然这个技术之前被提出作为一种训练规范化的手…

Docker构建Nginx镜像并部署前台应用

文章目录 1. 简介2. 准备工作3. 编写Dockerfile4. 编写nginx.conf5. 构建镜像6. 查看镜像是否构建成功7. 运行容器8. 访问Web应用9. 总结 1. 简介 Docker是一个开源的容器化平台&#xff0c;它可以帮助我们快速构建、发布和运行应用程序&#xff0c;实现应用程序的环境隔离和依…

全国大学生数据统计与分析竞赛2021年【本科组】-B题:用户消费行为价值分析

目录 摘 要 1 任务背景与重述 1.1 任务背景 1.2 任务重述 2 任务分析 3 数据假设 4 任务求解 4.1 任务一&#xff1a;数据预处理 4.1.1 数据清洗 4.1.2 数据集成 4.1.3 数据变换 4.2 任务二&#xff1a;对用户城市分布情况与分布情况可视化分析 4.2.1 城市分布情况可视化分析 4…

PWM定时器精准定时实现led闪烁(S3C2440裸机开发)

文章目录 前言一、PWM定时器原理二、使用步骤总结 前言 上期和大家分享了使用PWM定时器输出周期方波驱动蜂鸣器&#xff0c;那么本期分享的内容是使用PWM定时器实现定时器的功能&#xff0c;有了上期的基础&#xff0c;这期分享的内容大家理解起来应该非常easy&#xff0c;接下…