2024年10月

在使用 VSCode 远程 SSH 连接时,可能会遇到文件权限问题导致连接失败的情况。本文将详细记录如何为 SSH 配置文件(
config
)和私钥文件(
id_rsa
)正确设置权限,从而解决 VSCode 远程连接和 SSH 无法免密登录的问题。

前置背景知识:
VSCode使用Remote SSH连接远程服务器教程

问题背景

在 VSCode 中通过 SSH 连接远程服务器时,遇到了以下两个主要问题:

  1. SSH 配置文件(
    config
    )权限问题

    :VSCode 提示
    Everyone
    用户组对
    config
    文件的权限过高,要求只保留读取权限。

    报错信息:

    [13:14:14.179] Log Level: 2
    [13:14:14.192] Remote-SSH version: remote-ssh@0.111.2024040515
    [13:14:14.193] win32 x64
    [13:14:14.194] SSH Resolver called for host: guiyun
    [13:14:14.194] Setting up SSH remote "guiyun"
    [13:14:14.197] Using commit id "d994aede3529f4d1af9eeaeb234d32fd936243e7" and quality "insider" for server
    [13:14:14.199] Install and start server if needed
    [13:14:15.556] Got error from ssh: spawn C:\WINDOWS\System32\WindowsPowerShell\v1.0\ssh.exe ENOENT
    [13:14:15.556] Checking ssh with "C:\WINDOWS\System32\OpenSSH\ssh.exe -V"
    [13:14:15.596] > OpenSSH_for_Windows_9.5p1, LibreSSL 3.8.2
    [13:14:15.599] Running script with connection command: "C:\WINDOWS\System32\OpenSSH\ssh.exe" -T -D 5902 guiyun bash
    [13:14:15.601] Terminal shell path: C:\WINDOWS\System32\cmd.exe
    [13:14:15.845] > Bad permissions. Try removing permissions for user: \\Everyone (S-1-1-0) on file C:/Users/Administrator/.ssh/config.
    > Bad owner or permissions on C:\\Users\\Administrator/.ssh/config
    > 过程试图写入的管道不存在。
    > ]0;C:\WINDOWS\System32\cmd.exe
    [13:14:15.845] Got some output, clearing connection timeout
    [13:14:17.122] "install" terminal command done
    [13:14:17.122] Install terminal quit with output: ]0;C:\WINDOWS\System32\cmd.exe
    [13:14:17.122] Received install output: ]0;C:\WINDOWS\System32\cmd.exe
    [13:14:17.123] Failed to parse remote port from server output
    [13:14:17.124] Resolver error: Error: 
    	at g.Create (c:\Users\Administrator\.vscode-insiders\extensions\ms-vscode-remote.remote-ssh-0.111.2024040515\out\extension.js:2:499181)
    	at t.handleInstallOutput (c:\Users\Administrator\.vscode-insiders\extensions\ms-vscode-remote.remote-ssh-0.111.2024040515\out\extension.js:2:496503)
    	at t.tryInstall (c:\Users\Administrator\.vscode-insiders\extensions\ms-vscode-remote.remote-ssh-0.111.2024040515\out\extension.js:2:620043)
    	at async c:\Users\Administrator\.vscode-insiders\extensions\ms-vscode-remote.remote-ssh-0.111.2024040515\out\extension.js:2:579901
    	at async t.withShowDetailsEvent (c:\Users\Administrator\.vscode-insiders\extensions\ms-vscode-remote.remote-ssh-0.111.2024040515\out\extension.js:2:583207)
    	at async k (c:\Users\Administrator\.vscode-insiders\extensions\ms-vscode-remote.remote-ssh-0.111.2024040515\out\extension.js:2:576866)
    	at async t.resolve (c:\Users\Administrator\.vscode-insiders\extensions\ms-vscode-remote.remote-ssh-0.111.2024040515\out\extension.js:2:580578)
    	at async c:\Users\Administrator\.vscode-insiders\extensions\ms-vscode-remote.remote-ssh-0.111.2024040515\out\extension.js:2:846696
    [13:14:17.126] ------
    
  2. 私钥文件(
    id_rsa
    )无法免密码登录

    :SSH 提示
    id_rsa
    私钥文件权限不安全,导致无法免密码登录。

    报错信息:

    PowerShell 7.4.5
    PS C:\Users\Administrator> ssh root@103.110.228.78 -p 22
    Bad permissions. Try removing permissions for user: \\Everyone (S-1-1-0) on file C:/Users/Administrator/.ssh/id_rsa.
    @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
    @         WARNING: UNPROTECTED PRIVATE KEY FILE!          @
    @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
    Permissions for 'C:\\Users\\Administrator/.ssh/id_rsa' are too open.
    It is required that your private key files are NOT accessible by others.
    This private key will be ignored.
    Load key "C:\\Users\\Administrator/.ssh/id_rsa": bad permissions
    root@103.110.228.78's password:
    

本文将介绍如何一步步解决这两个问题,以便顺利使用 VSCode 进行远程 SSH 连接。


1. 为 SSH 配置文件
config
设置权限

VSCode 要求
config
文件的权限必须为只读权限,并且只限于当前用户和
Everyone
用户组读取。如果权限设置不当,VSCode 将无法正常使用远程 SSH 功能。

步骤 1:检查当前权限

首先,检查
config
文件的当前权限设置。打开
PowerShell
,并运行以下命令:

icacls "C:\Users\Administrator\.ssh\config"

检查输出中是否包含
Everyone
用户组的权限,特别关注是否有写权限(如
(W)
)。如果
Everyone
拥有写权限,这可能会导致 VSCode SSH 连接失败。

步骤 2:设置
Everyone
只读权限

VSCode 要求
config
文件的
Everyone
用户组只能拥有读取权限。

确保移除
Everyone
的写权限

:如果
Everyone
拥有写权限,我们需要确保完全移除它。执行以下命令来移除
Everyone
的写权限:

icacls "C:\Users\Administrator\.ssh\config" /remove "Everyone"

禁用权限继承
:为了确保文件不会从父目录中继承不必要的权限,我们需要禁用权限继承:

icacls "C:\Users\Administrator\.ssh\config" /inheritance:r

这将禁用继承的权限,确保
config
文件只使用当前手动设置的权限。

为此,你可以通过以下命令赋予
Everyone
只读权限:

icacls "C:\Users\Administrator\.ssh\config" /grant "Everyone:R"

步骤 3:验证权限

执行完上述操作后,验证权限设置是否正确。运行以下命令:

icacls "C:\Users\Administrator\.ssh\config"

应该看到类似
Everyone:(R)
的输出,表示
Everyone
用户组只拥有读取权限,没有写权限。这意味着文件的权限配置符合 VSCode SSH 连接的要求。通过这些步骤,你可以确保
config
文件的权限正确配置,从而解决 VSCode 远程 SSH 连接的权限问题。

步骤 4:验证远程连接命令

在完成文件权限的调整后,你可以通过 SSH 命令验证远程连接是否正常工作。确保你已经正确设置了
config
文件的权限并且已完成所有权限修复步骤。

1. 在终端或 PowerShell 中运行以下命令:
ssh root@your.ip.exam.ple -p 22
  • root
    :你希望使用的远程服务器的用户名。
  • your.ip.exam.ple
    :你要连接的服务器的 IP 地址。
  • -p 22
    :连接使用的端口号,默认是
    22
    ,可以根据需要调整。
2. 连接成功的情况:

如果配置正确,你将看到连接提示,可能会询问你是否接受远程服务器的指纹信息,像这样:

The authenticity of host 'your.ip.exam.ple (your.ip.exam.ple)' can't be established.
ED25519 key fingerprint is SHA256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.
Are you sure you want to continue connecting (yes/no)? yes

输入
yes
后,你将被要求输入密码或使用 SSH 密钥进行免密登录。

3. 连接失败的情况:

如果仍然无法连接,请检查:

  • config
    文件中的 IP、端口、用户名是否正确。
  • 私钥文件(如
    id_rsa
    )的权限是否设置正确,确保只有文件所有者可以访问。
  • 远程服务器的防火墙或 SSH 服务是否配置正确。

完成后,你应该能够成功通过 SSH 命令连接到远程服务器,并验证 VSCode 的 SSH 远程连接功能是否正常。


2. 解决 SSH 私钥
id_rsa
文件权限过高问题

在配置 SSH 密钥免密码登录时,SSH 需要确保私钥文件的权限非常严格,只有文件所有者能访问。如果权限过于宽松(如
Everyone
也有权限),SSH 将拒绝使用该私钥。

步骤 1:禁用继承权限

首先,我们需要禁用私钥文件的继承权限,这样文件不会从上层目录继承不必要的权限。

icacls "C:\Users\Administrator\.ssh\id_rsa" /inheritance:r

步骤 2:移除
Everyone
的权限

确保
Everyone
不再拥有对私钥文件的任何权限:

icacls "C:\Users\Administrator\.ssh\id_rsa" /remove "Everyone"

步骤 3:为
Administrator
设置读取权限

设置私钥文件的权限,让
Administrator
只拥有读取权限:

icacls "C:\Users\Administrator\.ssh\id_rsa" //grant:r "Administrator:(R)"

步骤 4:验证权限

再次验证权限,确保
Everyone
已被移除,且只有
Administrator
拥有读取权限:

icacls "C:\Users\Administrator\.ssh\id_rsa"

输出应显示类似于:

C:\Users\Administrator\.ssh\id_rsa DANCIPC\Administrator:(R)

步骤 5:验证远程连接命令

在完成文件权限的调整后,你可以通过 SSH 命令验证远程连接是否正常工作。确保你已经正确设置了
config
文件的权限并且已完成所有权限修复步骤。

1. 在终端或 PowerShell 中运行以下命令:
ssh root@your.ip.exam.ple -p 22
  • root
    :你希望使用的远程服务器的用户名。
  • your.ip.exam.ple
    :你要连接的服务器的 IP 地址。
  • -p 22
    :连接使用的端口号,默认是
    22
    ,可以根据需要调整。
2. 连接成功的情况:

如果配置正确,你将看到连接提示,可能会询问你是否接受远程服务器的指纹信息,像这样:

The authenticity of host 'your.ip.exam.ple (your.ip.exam.ple)' can't be established.
ED25519 key fingerprint is SHA256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.
Are you sure you want to continue connecting (yes/no)? yes

输入
yes
后,你将被要求输入密码或使用 SSH 密钥进行免密登录。

3. 连接失败的情况:

如果仍然无法连接,请检查:

  • config
    文件中的 IP、端口、用户名是否正确。
  • 私钥文件(如
    id_rsa
    )的权限是否设置正确,确保只有文件所有者可以访问。
  • 远程服务器的防火墙或 SSH 服务是否配置正确。

完成后,你应该能够成功通过 SSH 命令连接到远程服务器,并验证 VSCode 的 SSH 远程连接功能是否正常。


3. 解决 VSCode 远程连接问题总结

在配置 SSH 时,正确的文件权限设置至关重要。VSCode 远程连接要求 SSH 配置文件
config
允许
Everyone
用户组读取权限,而 SSH 私钥文件
id_rsa
必须严格禁止
Everyone
访问。

  • SSH 配置文件(
    config

    :保留
    Everyone
    的读取权限,移除写权限。
  • SSH 私钥文件(
    id_rsa

    :移除所有用户组的权限,只保留当前用户的读取权限。

通过调整这些权限,VSCode 将能够顺利通过 SSH 进行远程连接,同时 SSH 也能够安全地使用私钥进行免密码登录。

如果你在使用 VSCode 远程 SSH 时遇到类似问题,希望本文的解决方案能够帮助你解决权限相关的错误,提升工作效率。


参考命令列表

  • 检查文件权限:

    icacls "C:\Users\Administrator\.ssh\config"
    

  • Everyone
    设置只读权限:

    icacls "C:\Users\Administrator\.ssh\config" /grant "Everyone:(R)"
    
  • 禁用继承权限:

    icacls "C:\Users\Administrator\.ssh\id_rsa" /inheritance:r
    
  • 移除
    Everyone
    权限:

    icacls "C:\Users\Administrator\.ssh\id_rsa" /remove "Everyone"
    

  • Administrator
    设置读取权限:

    icacls "C:\Users\Administrator\.ssh\id_rsa" /grant:r "Administrator:(R)"
    
  • 验证远程连接命令

    ssh root@your.ip.exam.ple -p 22
    

    希望这篇博客能够帮助你顺利解决 VSCode SSH 连接权限问题并启用 SSH 密钥免密码登录功能。

磐维数据库(PanWeiDB)是由中国移动基于中国本土开源数据库openGauss打造的自研数据库产品,主要面向ICT基础设施。它具有高性能、高可靠性、高安全性和高兼容性的特点,能够支持集中式、分布式、云原生、一体机等多种应用场景。目前,磐维数据库已在中国移动的多个省(区、市)公司及专业公司部署应用。未来,磐维数据库计划在云原生、Serverless、智能运维、生态兼容等方面持续做强深度自主研发,进一步打造面向全行业的数据管理解决方案。随着磐维数据库不断深入数据库国产化替换的深水区,越来越多的核心业务系统都在进行代码改造,准备上线磐维数据库。因历史原因,程序开发人员很热衷于使用database link从Oracle实例A访问其他Oracle实例(B、C、D...),从而完成数据的操作,但随着迁移到磐维数据库,异构数据库之间的数据交互就成了不容忽视的问题。

本文介绍了江西移动公司,是如何从Oracle数据库使用透明网关访问磐维数据库数据的。

无特别说明,都以oracle用户执行

测试环境信息

Oracle 19C         -- 192.168.11.151
PanWeiDB 3.0.0     -- 192.168.0.120

1、上传odbc驱动包到oracle服务器并解压

cd /home/oracle
mkdir pwodbc
cd pwodbc
tar xf  PanWeiDB-V2.0-ODBC-2.0.3_B01.tar.gz

2、配置odbc实例驱动

cat<<+>/home/oracle/pwodbc/unixODBC-2.3.9/etc/odbcinst.ini
[PWMPP]
Driver64=/home/oracle/pwodbc/odbc/lib/psqlodbcw.so
setup=/home/oracle/pwodbc/odbc/lib/psqlodbcw.so
+

3、配置odbc客户端连接磐维数据的信息

cat <<+>/home/oracle/pwodbc/unixODBC-2.3.9/etc/odbc.ini
[pwdb]
Description=Test
Driver=PWMPP
Servername=192.168.0.120
Database=testdb
Username=tpcc
Password=tpcc@123
Port=17700
Sslmode=allow
+

4、配置Oracle和grid用户环境变量,以使用指定的odbc驱动

cat <<+>>~/.bash_profile
export LD_LIBRARY_PATH=/home/oracle/pwodbc/lib:/home/oracle/pwodbc/odbc/lib:/home/oracle/pwodbc/unixODBC-2.3.9/lib:$LD_LIBRARY_PATH
export ODBCSYSINI=/home/oracle/pwodbc/unixODBC-2.3.9/etc
export ODBCINI=/home/oracle/pwodbc/unixODBC-2.3.9/etc/odbc.ini
+
source ~/.bash_profile

5、为驱动路径添加合适的权限,保证grid和oracle都有权限访问

chmod 755 -R /home/oracle/pwodbc

6、验证odbc驱动能正常访问PanWeiDB库,Oracle和grid用户都验证一下

odbcinst  -j
odbcinst -q -d
isql -v pwdb

结果类似如下:

[oracle@ora19c1 ~]$ isql -v pwdb
+---------------------------------------+
| Connected!                            |
|                                       |
| sql-statement                         |
| help [tablename]                      |
| quit                                  |
|                                       |
+---------------------------------------+
SQL> 

7、Oracle 配置透明网关服务,这里以PanWeiDB为sid示例
配置oracle用户hs, 配置init<sid>.ora在 $ORACLE_HOME/hs/admin/init<sid>.ora

cat <<+>$ORACLE_HOME/hs/admin/initpwdb.ora
HS_FDS_CONNECT_INFO = pwdb
HS_FDS_TRACE_LEVEL = 255
HS_FDS_SHAREABLE_NAME = /home/oracle/pwodbc/unixODBC-2.3.9/lib/libodbc.so
HS_NLS_NCHAR = UCS2
HS_LANGUAGE = AMERICAN_AMERICA.AL32UTF8
set LD_LIBRARY_PATH=/home/oracle/pwodbc/lib:/home/oracle/pwodbc/odbc/lib:/home/oracle/pwodbc/unixODBC-2.3.9/lib
set ODBCSYSINI = /home/oracle/pwodbc/unixODBC-2.3.9/etc
+

8、增加侦听

grid:  $ORACLE_HOME/network/admin/listener.ora  增加 
SID_LIST_LISTENER=
(SID_LIST=
   (SID_DESC=
     (SID_NAME=pwdb)
     (ORACLE_HOME=/u01/app/oracle/product/19.3.0/dbhome_1)
     (PROGRAM=dg4odbc)
     (ENVS="LD_LIBRARY_PATH=/home/oracle/pwodbc/lib:/home/oracle/pwodbc/odbc/lib:/home/oracle/pwodbc/unixODBC-2.3.9/lib")
   )
)

重新加载侦听

lsnrctl reload
lsnrctl status

9、配置tns
oracle: $ORACLE_HOME/network/admin/tnsnames.ora 增加

pwdb =
  (DESCRIPTION=
    (ADDRESS=(PROTOCOL=tcp)(HOST=192.168.11.151)(PORT=1521))
    (CONNECT_DATA=(SID=pwdb))
    (HS=OK)
  )
tnsping pwdb

10、创建dblink验证

create database link  pg_link connect to "tpcc" identified by "tpcc@123" using 'pwdb';
select * from "t1"@pg_link ;

结果类似如下

SQL> select * from "t1"@pg_link ;
	id
----------
	 1
SQL> 

注意:
访问PanWeiDB的数据库表是需要在表名字上加上
双引号
(因为在oracle默认会转换为大写,而PanWeiDB默认小写,会造成访问不到表)

随着国际政治经济形势的变化,尤其是中美科技竞争日益激烈,软件信创国产化已经迫在眉睫。在这种大环境下,我们将现有的Windows版软件逐步迁移到信创国产化基础设施上,适配国产操作系统(如银河麒麟、统信UOS)、国信芯片(如飞腾、鲲鹏、海光、龙芯、麒麟)以及国产DB。

我们经常有这样的需求,比如需要在银河麒麟或统信UOS上实现RTMP推流摄像头视频和麦克风声音到流媒体服务器(如nginx或srs),那么这个要如何实现了?

一. 技术方案

要完成这个功能,具体来说,需要解决如下几个技术问题:

(1)麦克风数据采集。

(2)摄像头数据采集。

(3)音频数据AAC编码。

(4)视频数据H264编码。

(5)将编码后的数据按RTMP协议推送给流媒体服务器。

(6)通过时间戳(PTS)保证音频视频的同步。

我们使用跨平台的 .NET Core (C#),跨平台的UI框架Avalonia,再借助 LinuxCapture 和 NPusher.NetCore 这两个组件,就很容易采集到麦克风和摄像头的数据,并且将它们推流到流媒体服务器上。

我们先看看推流程序在银河麒麟上的运行效果:

两个下拉列表可以选择要使用的麦克风和摄像头设备。

点击“开始”按钮,麦克风和摄像头将开始采集数据,并推流至流媒体Server。

如果中途网络断开,推流将会中断,并尝试自动重连,重连成功后,将恢复推流。

点击“结束”按钮,则将结束音视频采集和推流。

二.具体实现

(1)ICameraCapturer是摄像头视频采集组件;IMicrophoneCapturer是麦克风声音采集组件。

(2)我们可以通过调用CapturerFactory的CreateXXXX方法来创建对应的采集器实例。

(3)得到采集器实例后,调用Start方法,即可开始采集;调用Stop方法,即停止采集。

(4)采集得到的数据,将通过相应的事件(ImageCaptured、AudioCaptured)暴露出来,我们预定这些事件,即可拿到采集的数据。

(5)将拿到的数据喂给IStreamPusher,就会将其推流到指定的流媒体服务器。

我们这里列一下核心代码,完整的代码大家可以从文末下载源码进行了解。

创建并启动采集器:

            //摄像头采集器
            this.cameraCapturer =CapturerFactory.CreateCameraCapturer(cameraIndex, videoSize, frameRate);this.cameraCapturer.ImageCaptured +=CameraCapturer_ImageCaptured;this.cameraCapturer.CaptureError +=CameraCapturer_CaptureError;//麦克风采集器
            this.microphoneCapturer =CapturerFactory.CreateMicrophoneCapturer(micIndex);this.microphoneCapturer.AudioCaptured +=MicrophoneCapturer_AudioCaptured;this.microphoneCapturer.CaptureError +=MicrophoneCapturer_CaptureError;this.microphoneCapturer.Start();this.cameraCapturer.Start();

创建并启动推流器:

           string nginxServerIP = ConfigurationManager.AppSettings["NginxServerIP"];int nginxServerPort = int.Parse(ConfigurationManager.AppSettings["NginxServerPort"]);string rtmpUrl = $"rtmp://{nginxServerIP}:{nginxServerPort}/hls/{streamID}";this.streamPusher.UpsideDown4RGB24 = true;this.streamPusher.Initialize(rtmpUrl, videoSize.Width, videoSize.Height, InputAudioDataType.PCM, InputVideoDataType.RGBA, this.channelCount);

将采集到的数据喂给推流器:

private void CameraCapturer_ImageCaptured(byte[] agba32Data)
{
if (this.isRecording)
{
this.streamPusher.PushVideoFrame(agba32Data);
UiSafeInvoker.ActionOnUI(()
=>{
WriteableBitmap writeableBitmap
=CreateBitmapFromPixelData(agba32Data, videoSize.Width, videoSize.Height);
img.Source
=writeableBitmap;
});
}
}
private void MicrophoneCapturer_AudioCaptured(byte[] pcm)
{
if (this.isRecording)
{
this.streamPusher.PushAudioFrame(pcm);
}
}

推流器内部会对音视频数据进行编码,并依据RTMP协议发送给流媒体服务器。

停止推流:

private void FinishRecorded(boolsuccess)
{
this.RecordState_Changed(false);this.cameraCapturer?.Stop();this.cameraCapturer?.Dispose();this.microphoneCapturer?.Stop();this.microphoneCapturer?.Dispose();this.streamPusher?.Close();string tip = success ? "推流停止!" : "推流器断开,推流停止!";
ShowStateMsg(tip);
}

三. 部署运行

如果要在银河麒麟或统信UOS上运行这里的RTMP推流程序,则需要现在目标操作系统上安装.NET Core 3.1。

然后将VS生成目录下的 netcoreapp3.1 文件夹拷贝到目标电脑上,进入netcoreapp3.1文件夹,打开终端,并在终端中输入如下命令:

dotnet Oraycn_Avalonias_PusherDemo.Desktop.dll

回车运行后,就会出现前面截图的UI界面,然后我们就可以预览摄像头,并开始推流麦克风摄像头了。

四. 源码下载

Oraycn.Avalonias.PusherDemo.rar

源码中包含的非托管库是X64架构的,如果需要在其它架构的国产芯片上运行该程序,可以联系我获取对应架构的非托管库。

〇、两时间段比较的全部情况

总共有如下图中的六种情况:

下文将根据这六种情况进一步操作。

注意,图中说的动态和固定两时间段,就是两个普通时间段,不区分主次,仅用作帮助理解。

一、判断两个时间段是否有交叉(交集)

正常情况下,就是图中的 2、3、4、5 四种有交叉的情况。如果直接通过这四种情况判断的话,就需要四个判断条件组合,过于复杂,本文略过。

如果通过
逆向思维
的话,就只需要判断 1、6 两种情况。当然
推荐使用逆向思维,判断的情况比较少,也易于理解
,下边详细介绍下。

判断两时间段
不交叉的条件

-- 动态结束时间 < 固定开始时间
jieshusj_dt < kaishisj_gd -- 情况 1
or
kaishisj_dt > jieshusj_gd -- 情况 6
-- 动态开始时间 > 固定结束时间

那么,就可以
通过
取反
,得到两时间段有交叉的条件

-- 动态结束时间 >= 固定开始时间
jieshusj_dt >= kaishisj_gd
and
kaishisj_dt <= jieshusj_gd
-- 动态开始时间 <= 固定结束时间

二、取两个时间段的交叉部分(交集)

前提条件:
通过了有交叉判断。也就是包含 2、3、4、5 四种情况。

然后,就需要分别比较两个时间段的开始时间和结束时间:

  • 开始时间:取较大的那一个;
  • 结束时间:取较小的那一个。
-- 动态时间段示例:2024-10-16 ~ 2024-10-20
select 
-- 开始时间取较大的
(Case When kaishisj_gd > '2024-10-16' Then kaishisj_gd Else '2024-10-16' End) kaishisj,
-- 结束时间取较小的
(Case When jieshusj_gd < '2024-10-20' Then jieshusj_gd Else '2024-10-20' End) jieshusj
from table_name

三、取两个时间段并集

取并集也需要分两种情况,就是是否有交叉。

  • 第一种:无交叉

直接将两个时间段进行‘或’运算即可。

  • 第二种:有交叉

此种情况也是分别比较两个时间段的开始时间和结束时间,但是取值和上一章节中刚好相反,:

  • 开始时间:取较小的那一个;
  • 结束时间:取较大的那一个。
-- 动态时间段示例:2024-10-16 ~ 2024-10-20
select 
-- 开始时间取较小的
(Case When kaishisj_gd > '2024-10-16' Then '2024-10-16' Else kaishisj_gd End) kaishisj,
-- 结束时间取较大的
(Case When jieshusj_gd < '2024-10-20' Then '2024-10-20' Else jieshusj_gd End) jieshusj
from table_name

四、取两个时间段的补集

首先,什么是补集?简单的示意图如下:

(其中,
全集
‘集合 B’包含‘集合 A’,那么图中
灰色部分就是‘集合 A’的补集

所以,求补集的前提条件就是两个时间段的有包含关系,也就是情况 3、4。

  • 情况 3:

-- 动态时间段示例:2024-10-16 ~ 2024-10-20
select 
kaishisj_gd,'2024-10-16' as jieshusj_new, -- 两个时间,组成新的时间段
'2024-10-20' as kaishisj_new,jieshusj_gd  -- 两个时间,组成新的时间段
from table_name 
where kaishisj_gd < '2024-10-16' and jieshusj_gd > '2024-10-20'

如上边的查询语句,可以得到四个时间,分别组成两个时间段,再进行后续个性化操作。

  • 情况 4:

-- 动态时间段示例:2024-10-16 ~ 2024-10-20
select 
'2024-10-16' as kaishisj_new, kaishisj_gd, -- 两个时间,组成新的时间段
jieshusj_gd, '2024-10-20' as jiehsusj_new  -- 两个时间,组成新的时间段
from table_name 
where kaishisj_gd > '2024-10-16' and jieshusj_gd < '2024-10-20'

如上边的查询语句,可以得到四个时间,分别组成两个时间段,再进行后续个性化操作。

所谓
复数平面
,就是一种二维坐标系统,用于几何表示复数的场景,其中横轴代表实部,纵轴代表虚部。

每个点对应一个唯一的复数,反之亦然,这种表示方法使得复数的加法、乘法等运算可以通过直观的图形变换来理解。

ComplexPlane

Manim
库中用于处理
复数平面
的类。

它不仅提供了标准的笛卡尔坐标系,还特别针对复数操作进行了优化,使得复数及其变换的可视化变得更加直观。

通过
ComplexPlane
,我们可以轻松地绘制出复数点、向量以及执行复数变换,如旋转、缩放等。

本篇将介绍
Manim
中的
ComplexPlane
对象以及一些常用的使用示例。

1. 主要参数

ComplexPlane
继承自上一篇介绍的
NumberPlane

ComplexPlane
没有自己特有的参数,和
NumberPlane
的参数是一样的。

参数名称 类型 说明
x_range Sequence[float] 直角平面的
横坐标轴
范围,间隔
y_range Sequence[float] 直角平面的
纵坐标轴
范围,间隔
x_length float 直角平面宽度
y_length float 直角平面高度
background_line_style dict 直角平面背景网格线的样式
faded_line_style dict 淡化网格线的样式,用于辅助背景网格线
faded_line_ratio int 定义淡化网格线与背景网格线的比例
make_smooth_after_applying_functions bool 应用函数后是否进行平滑处理

2. 主要方法


NumberPlane
一样,
ComplexPlane
也包含了坐标系统
CoordinateSystem
类提供的方法,

不过,在复数平面中,我比较常用的是以下3个方法:

名称 说明
add_coordinates 给复数平面的坐标轴添加刻度数值
n2p(number_to_point) 根据复数得到此复数在复数平面上的位置
p2n(point_to_number) 根据复数平面上的位置得到对应的复数

3. 使用示例

下面通过示例来演示复数平面
ComplexPlane
的多种功能,包括复数平面的网格与坐标轴,复数点的标记与展示、复数平面上的函数图像、复数变换动画等。


ComplexPlane
成为我们展示复数概念和性质的有力工具。

3.1. 网格与坐标轴

创建一个复数平面
ComplexPlane
,绘制网格线和坐标轴,设置实部的范围
[-5, 5]
,虚部的范围
[-4, 4]
,最后再给坐标轴加上刻度值。

plane = ComplexPlane(
    x_range=[-5, 5],
    y_range=[-4, 4],
    x_length=6,
    y_length=4,
)

# 加上刻度值
plane.add_coordinates()

3.2. 复数点的标记

在复数平面坐标上添加2个复数点,再给这两个点添加标签,显示其复数的值。

# 创建复数平面
plane = ComplexPlane(
    x_range=[-5, 5],
    y_range=[-5, 5],
)
plane.add_coordinates()

# 添加复数的点
d1 = Dot(plane.n2p(3 + 2j))
d2 = Dot(plane.n2p(-4 - 2j))

3.3. 复数运算

复数平面上添加两个点,然后计算这两个复数相加的结果,并将计算过程在复数平面上用动画显示出来。

# 创建复数平面
plane = ComplexPlane(
    x_range=[-1, 8],
    y_range=[-1, 8],
)
plane.add_coordinates()

# 初始的两个点
d1 = Dot(plane.n2p(2 + 1j))
d2 = Dot(plane.n2p(2 + 4j))

# 相加后的点
d3 = Dot(plane.n2p(4 + 5j))

3.4. 复数变换

最后,是复数点经过一个函数变换后,在复数平面上显示新的位置。

示例中先初始4个点,然后经过函数$ f(x)=2^x $的变换后,显示其变换后的位置。

其中用到了
ComplexPlane
的主要方法
n2p

p2n

# 创建复数平面
plane = ComplexPlane(
    x_range=[-5, 5],
    y_range=[-5, 5],
)
plane.add_coordinates()

d1 = LabeledDot(
    label=MathTex("1"),
    point=plane.n2p(2 + 1j),
)
d2 = LabeledDot(
    label=MathTex("2"),
    point=plane.n2p(2 + 3j),
)
d3 = LabeledDot(
    label=MathTex("3"),
    point=plane.n2p(-2 - 2j),
)
d4 = LabeledDot(
    label=MathTex("4"),
    point=plane.n2p(-3 + 2j),
)
self.add(d1, d2, d3, d4)

# 变换后点的位置
pd1 = np.exp2(plane.p2n(d1.get_center()))
pd2 = np.exp2(plane.p2n(d2.get_center()))
pd3 = np.exp2(plane.p2n(d3.get_center()))
pd4 = np.exp2(plane.p2n(d4.get_center()))

4. 附件

文中的代码只是关键部分的截取,完整的代码共享在网盘中(
complex_plane.py
),

下载地址:
完整代码
(访问密码: 6872)